add Lua bindings for ubus events
authorJohn Crispin <blogic@openwrt.org>
Thu, 7 Nov 2013 12:51:11 +0000 (13:51 +0100)
committerJohn Crispin <blogic@openwrt.org>
Thu, 7 Nov 2013 15:23:30 +0000 (16:23 +0100)
It mostly mimick the style of the existing code.

With it and the ubox Lua bindings, you can now send ubus events
through Lua or listen for events (you can register for multiple events
at the same time).

Signed-off-by: Jeff Remy <jeff.remy@gmail.com>
lua/test.lua
lua/test_client.lua
lua/ubus.c

index 07e62c6..d24ac6e 100755 (executable)
@@ -39,4 +39,16 @@ local my_method = {
 }
 
 conn:add(my_method)
 }
 
 conn:add(my_method)
+
+local my_event = {
+       test = function(msg)
+               print("Call to test event")
+               for k, v in pairs(msg) do
+                       print("key=" .. k .. " value=" .. tostring(v))
+               end
+       end,
+}
+
+conn:listen(my_event)
+
 uloop.run()
 uloop.run()
index f55c327..0b60e0d 100755 (executable)
@@ -36,4 +36,6 @@ for a = 1, #status do
        end
 end
 
        end
 end
 
+conn:send("test", { foo = "bar"})
+
 uloop.run()
 uloop.run()
index 77624d7..84ee06b 100644 (file)
@@ -17,7 +17,7 @@
 #include <libubox/blobmsg.h>
 #include <libubox/blobmsg_json.h>
 #include <lauxlib.h>
 #include <libubox/blobmsg.h>
 #include <libubox/blobmsg_json.h>
 #include <lauxlib.h>
-
+#include <lua.h>
 
 #define MODNAME        "ubus"
 #define METANAME       MODNAME ".meta"
 
 #define MODNAME        "ubus"
 #define METANAME       MODNAME ".meta"
@@ -35,6 +35,11 @@ struct ubus_lua_object {
        int r;
 };
 
        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);
 
 static int
 ubus_lua_parse_blob(lua_State *L, struct blob_attr *attr, bool table);
 
@@ -557,6 +562,89 @@ ubus_lua_call(lua_State *L)
        return lua_gettop(L) - top;
 }
 
        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)
 
 static int
 ubus_lua__gc(lua_State *L)
@@ -580,6 +668,8 @@ static const luaL_Reg ubus[] = {
        { "signatures", ubus_lua_signatures },
        { "call", ubus_lua_call },
        { "close", ubus_lua__gc },
        { "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 },
 };
        { "__gc", ubus_lua__gc },
        { NULL, NULL },
 };
@@ -629,5 +719,9 @@ luaopen_ubus(lua_State *L)
        lua_createtable(L, 1, 0);
        lua_setglobal(L, "__ubus_cb");
 
        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;
 }
        return 0;
 }