add Lua bindings for ubus events

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>
This commit is contained in:
John Crispin 2013-11-07 13:51:11 +01:00
parent a9ee3ef0cf
commit 8ea9667036
3 changed files with 109 additions and 1 deletions

View file

@ -39,4 +39,16 @@ local 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()

View file

@ -36,4 +36,6 @@ for a = 1, #status do
end
end
conn:send("test", { foo = "bar"})
uloop.run()

View file

@ -17,7 +17,7 @@
#include <libubox/blobmsg.h>
#include <libubox/blobmsg_json.h>
#include <lauxlib.h>
#include <lua.h>
#define MODNAME "ubus"
#define METANAME MODNAME ".meta"
@ -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);
@ -557,6 +562,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)
@ -580,6 +668,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 },
};
@ -629,5 +719,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;
}