X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fubus.git;a=blobdiff_plain;f=lua%2Fubus.c;h=0f2338c9420d6d323c637717283182c6fc3fb6d4;hp=081ff45b53f6482657d5922a8bc130f4b294198f;hb=334c38918063b5ece164624e20490021b2bff38a;hpb=0f793d3a457af9afa8bc4eae2dff855cd7e6a192 diff --git a/lua/ubus.c b/lua/ubus.c index 081ff45..0f2338c 100644 --- a/lua/ubus.c +++ b/lua/ubus.c @@ -17,10 +17,10 @@ #include #include #include +#include - -#define MODNAME "ubus" -#define METANAME MODNAME ".meta" +#define MODNAME "ubus" +#define METANAME MODNAME ".meta" static lua_State *state; @@ -35,6 +35,11 @@ struct ubus_lua_object { int r; }; +struct ubus_lua_event { + struct ubus_event_handler e; + int r; +}; + static int ubus_lua_parse_blob(lua_State *L, struct blob_attr *attr, bool table); @@ -67,7 +72,6 @@ ubus_lua_parse_blob(lua_State *L, struct blob_attr *attr, bool table) int len; int off = 0; void *data; - char buf[32]; if (!blobmsg_check_attr(attr, false)) return 0; @@ -96,9 +100,7 @@ ubus_lua_parse_blob(lua_State *L, struct blob_attr *attr, bool table) break; case BLOBMSG_TYPE_INT64: - /* NB: Lua cannot handle 64bit, format value as string and push that */ - sprintf(buf, "%lld", (long long int) be64_to_cpu(*(uint64_t *)data)); - lua_pushstring(L, buf); + lua_pushnumber(L, (double) be64_to_cpu(*(uint64_t *)data)); break; case BLOBMSG_TYPE_STRING: @@ -137,7 +139,7 @@ ubus_lua_format_blob_is_array(lua_State *L) if (lua_type(L, -2) != LUA_TNUMBER) #endif { - lua_pop(L, 1); + lua_pop(L, 2); return false; } @@ -145,7 +147,7 @@ ubus_lua_format_blob_is_array(lua_State *L) if ((cur - 1) != prv) { - lua_pop(L, 1); + lua_pop(L, 2); return false; } @@ -287,6 +289,8 @@ ubus_method_handler(struct ubus_context *ctx, struct ubus_object *obj, lua_getglobal(state, "__ubus_cb"); lua_rawgeti(state, -1, o->r); lua_getfield(state, -1, method); + lua_remove(state, -2); + lua_remove(state, -2); if (lua_isfunction(state, -1)) { lua_pushlightuserdata(state, req); @@ -295,7 +299,9 @@ ubus_method_handler(struct ubus_context *ctx, struct ubus_object *obj, else ubus_lua_parse_blob_array(state, blob_data(msg), blob_len(msg), true); lua_call(state, 2, 0); - } + } else + lua_pop(state, 1); + return 0; } @@ -347,12 +353,11 @@ static int ubus_lua_load_methods(lua_State *L, struct ubus_method *m) /* get the policy table */ lua_pushinteger(L, 2); lua_gettable(L, -3); - plen = lua_gettablelen(L, -1); /* check if the method table is valid */ if ((lua_type(L, -2) != LUA_TFUNCTION) || (lua_type(L, -1) != LUA_TTABLE) || - lua_objlen(L, -1) || !plen) { + lua_objlen(L, -1)) { lua_pop(L, 2); return 1; } @@ -361,6 +366,17 @@ static int ubus_lua_load_methods(lua_State *L, struct ubus_method *m) lua_pushvalue(L, -2); lua_setfield(L, -6, lua_tostring(L, -5)); + m->name = lua_tostring(L, -4); + m->handler = ubus_method_handler; + + plen = lua_gettablelen(L, -1); + + /* exit if policy table is empty */ + if (!plen) { + lua_pop(L, 2); + return 0; + } + /* setup the policy pointers */ p = malloc(sizeof(struct blobmsg_policy) * plen); memset(p, 0, sizeof(struct blobmsg_policy) * plen); @@ -384,8 +400,6 @@ static int ubus_lua_load_methods(lua_State *L, struct ubus_method *m) } m->n_policy = pidx; - m->name = lua_tostring(L, -4); - m->handler = ubus_method_handler; lua_pop(L, 2); return 0; @@ -415,7 +429,7 @@ static struct ubus_object* ubus_lua_load_object(lua_State *L) obj->o.type->id = 0; obj->o.type->methods = obj->o.methods; - /* create the he callback lookup table */ + /* create the callback lookup table */ lua_createtable(L, 1, 0); lua_getglobal(L, "__ubus_cb"); lua_pushvalue(L, -2); @@ -560,6 +574,89 @@ ubus_lua_call(lua_State *L) return lua_gettop(L) - top; } +static void +ubus_event_handler(struct ubus_context *ctx, struct ubus_event_handler *ev, + const char *type, struct blob_attr *msg) +{ + struct ubus_lua_event *listener = container_of(ev, struct ubus_lua_event, e); + + lua_getglobal(state, "__ubus_cb_event"); + lua_rawgeti(state, -1, listener->r); + + if (lua_isfunction(state, -1)) { + ubus_lua_parse_blob_array(state, blob_data(msg), blob_len(msg), true); + lua_call(state, 1, 0); + } +} + +static struct ubus_event_handler* +ubus_lua_load_event(lua_State *L) +{ + struct ubus_lua_event* event = NULL; + + event = malloc(sizeof(struct ubus_lua_event)); + memset(event, 0, sizeof(struct ubus_lua_event)); + event->e.cb = ubus_event_handler; + + /* update the he callback lookup table */ + lua_getglobal(L, "__ubus_cb_event"); + lua_pushvalue(L, -2); + event->r = luaL_ref(L, -2); + lua_setfield(L, -1, lua_tostring(L, -3)); + + return &event->e; +} + +static int +ubus_lua_listen(lua_State *L) { + struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); + + /* verify top level object */ + luaL_checktype(L, 2, LUA_TTABLE); + + /* scan each object */ + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + struct ubus_event_handler *listener; + + /* check if the key is a string and the value is a method */ + if ((lua_type(L, -2) == LUA_TSTRING) && (lua_type(L, -1) == LUA_TFUNCTION)) { + listener = ubus_lua_load_event(L); + if(listener != NULL) { + ubus_register_event_handler(c->ctx, listener, lua_tostring(L, -2)); + } + } + lua_pop(L, 1); + } + return 0; +} + +static int +ubus_lua_send(lua_State *L) +{ + struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); + const char *event = luaL_checkstring(L, 2); + + if (*event == 0) + return luaL_argerror(L, 2, "no event name"); + + // Event content convert to ubus form + luaL_checktype(L, 3, LUA_TTABLE); + blob_buf_init(&c->buf, 0); + + if (!ubus_lua_format_blob_array(L, &c->buf, true)) { + lua_pushnil(L); + lua_pushinteger(L, UBUS_STATUS_INVALID_ARGUMENT); + return 2; + } + + // Send the event + ubus_send_event(c->ctx, event, c->buf.head); + + return 0; +} + + static int ubus_lua__gc(lua_State *L) @@ -583,6 +680,8 @@ static const luaL_Reg ubus[] = { { "signatures", ubus_lua_signatures }, { "call", ubus_lua_call }, { "close", ubus_lua__gc }, + { "listen", ubus_lua_listen }, + { "send", ubus_lua_send }, { "__gc", ubus_lua__gc }, { NULL, NULL }, }; @@ -632,5 +731,9 @@ luaopen_ubus(lua_State *L) lua_createtable(L, 1, 0); lua_setglobal(L, "__ubus_cb"); + /* create the event table */ + lua_createtable(L, 1, 0); + lua_setglobal(L, "__ubus_cb_event"); + return 0; }