X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fubus.git;a=blobdiff_plain;f=lua%2Fubus.c;h=cfe9c9b0abde93feb9447f334aced7d1c96d91b1;hp=2903e7b1ea7142e5e8ff7f919875e04d16a859e9;hb=9c13096b169759eabf4c528df22d605e2d6093f4;hpb=d23b07a9ff999275c09957cb385e10cb729abd17 diff --git a/lua/ubus.c b/lua/ubus.c index 2903e7b..cfe9c9b 100644 --- a/lua/ubus.c +++ b/lua/ubus.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2012 Jo-Philipp Wich * Copyright (C) 2012 John Crispin + * Copyright (C) 2016 Iain Fraser * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 2.1 @@ -33,6 +34,7 @@ struct ubus_lua_connection { struct ubus_lua_object { struct ubus_object o; int r; + int rsubscriber; }; struct ubus_lua_event { @@ -40,6 +42,12 @@ struct ubus_lua_event { int r; }; +struct ubus_lua_subscriber { + struct ubus_subscriber s; + int rnotify; + int rremove; +}; + static int ubus_lua_parse_blob(lua_State *L, struct blob_attr *attr, bool table); @@ -302,8 +310,9 @@ ubus_method_handler(struct ubus_context *ctx, struct ubus_object *obj, lua_call(state, 2, 1); if (lua_isnumber(state, -1)) rv = lua_tonumber(state, -1); - } else - lua_pop(state, 1); + } + + lua_pop(state, 1); return rv; } @@ -343,6 +352,26 @@ static int ubus_lua_reply(lua_State *L) return 0; } +static int ubus_lua_defer_request(lua_State *L) +{ + struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); + struct ubus_request_data *req = lua_touserdata(L, 2); + struct ubus_request_data *new_req = lua_newuserdata(L, sizeof(struct ubus_request_data)); + ubus_defer_request(c->ctx, req, new_req); + + return 1; +} + +static int ubus_lua_complete_deferred_request(lua_State *L) +{ + struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); + struct ubus_request_data *req = lua_touserdata(L, 2); + int ret = luaL_checkinteger(L, 3); + ubus_complete_deferred_request(c->ctx, req, ret); + + return 0; +} + static int ubus_lua_load_methods(lua_State *L, struct ubus_method *m) { struct blobmsg_policy *p; @@ -381,11 +410,10 @@ static int ubus_lua_load_methods(lua_State *L, struct ubus_method *m) } /* setup the policy pointers */ - p = malloc(sizeof(struct blobmsg_policy) * plen); + p = calloc(plen, sizeof(struct blobmsg_policy)); if (!p) return 1; - memset(p, 0, sizeof(struct blobmsg_policy) * plen); m->policy = p; lua_pushnil(L); while (lua_next(L, -2) != 0) { @@ -411,6 +439,39 @@ static int ubus_lua_load_methods(lua_State *L, struct ubus_method *m) return 0; } +static void +ubus_new_sub_cb(struct ubus_context *ctx, struct ubus_object *obj) +{ + struct ubus_lua_object *luobj; + + luobj = container_of(obj, struct ubus_lua_object, o); + + lua_getglobal(state, "__ubus_cb_publisher"); + lua_rawgeti(state, -1, luobj->rsubscriber); + lua_remove(state, -2); + + if (lua_isfunction(state, -1)) { + lua_pushnumber(state, luobj->o.has_subscribers ); + lua_call(state, 1, 0); + } else { + lua_pop(state, 1); + } +} + +static void +ubus_lua_load_newsub_cb( lua_State *L, struct ubus_lua_object *obj ) +{ + /* keep ref to func */ + lua_getglobal(L, "__ubus_cb_publisher"); + lua_pushvalue(L, -2); + obj->rsubscriber = luaL_ref(L, -2); + lua_pop(L, 1); + + /* real callback */ + obj->o.subscribe_cb = ubus_new_sub_cb; + return; +} + static struct ubus_object* ubus_lua_load_object(lua_State *L) { struct ubus_lua_object *obj = NULL; @@ -419,26 +480,23 @@ static struct ubus_object* ubus_lua_load_object(lua_State *L) int midx = 0; /* setup object pointers */ - obj = malloc(sizeof(struct ubus_lua_object)); + obj = calloc(1, sizeof(struct ubus_lua_object)); if (!obj) return NULL; - memset(obj, 0, sizeof(struct ubus_lua_object)); obj->o.name = lua_tostring(L, -2); /* setup method pointers */ - m = malloc(sizeof(struct ubus_method) * mlen); - memset(m, 0, sizeof(struct ubus_method) * mlen); + m = calloc(mlen, sizeof(struct ubus_method)); obj->o.methods = m; /* setup type pointers */ - obj->o.type = malloc(sizeof(struct ubus_object_type)); + obj->o.type = calloc(1, sizeof(struct ubus_object_type)); if (!obj->o.type) { free(obj); return NULL; } - memset(obj->o.type, 0, sizeof(struct ubus_object_type)); obj->o.type->name = lua_tostring(L, -2); obj->o.type->id = 0; obj->o.type->methods = obj->o.methods; @@ -453,6 +511,13 @@ static struct ubus_object* ubus_lua_load_object(lua_State *L) /* scan each method */ lua_pushnil(L); while (lua_next(L, -3) != 0) { + /* check if its the subscriber notification callback */ + if( lua_type( L, -2 ) == LUA_TSTRING && + lua_type( L, -1 ) == LUA_TFUNCTION ){ + if( !strcmp( lua_tostring( L, -2 ), "__subscriber_cb" ) ) + ubus_lua_load_newsub_cb( L, obj ); + } + /* check if it looks like a method */ if ((lua_type(L, -2) != LUA_TSTRING) || (lua_type(L, -1) != LUA_TTABLE) || @@ -494,8 +559,14 @@ static int ubus_lua_add(lua_State *L) if ((lua_type(L, -2) == LUA_TSTRING) && (lua_type(L, -1) == LUA_TTABLE)) { obj = ubus_lua_load_object(L); - if (obj) + if (obj){ ubus_add_object(c->ctx, obj); + + /* allow future reference of ubus obj */ + lua_pushstring(state,"__ubusobj"); + lua_pushlightuserdata(state, obj); + lua_settable(state,-3); + } } lua_pop(L, 1); } @@ -503,6 +574,34 @@ static int ubus_lua_add(lua_State *L) return 0; } +static int +ubus_lua_notify( lua_State *L ) +{ + struct ubus_lua_connection *c; + struct ubus_object *obj; + const char* method; + + c = luaL_checkudata(L, 1, METANAME); + method = luaL_checkstring(L, 3); + luaL_checktype(L, 4, LUA_TTABLE); + + if( !lua_islightuserdata( L, 2 ) ){ + lua_pushfstring( L, "Invald 2nd parameter, expected ubus obj ref" ); + lua_error( L ); + } + obj = lua_touserdata( L, 2 ); + + /* create parameters from table */ + blob_buf_init(&c->buf, 0); + if( !ubus_lua_format_blob_array( L, &c->buf, true ) ){ + lua_pushfstring( L, "Invalid 4th parameter, expected table of arguments" ); + lua_error( L ); + } + + ubus_notify( c->ctx, obj, method, c->buf.head, -1 ); + return 0; +} + static void ubus_lua_signatures_cb(struct ubus_context *c, struct ubus_object_data *o, void *p) { @@ -612,11 +711,10 @@ ubus_lua_load_event(lua_State *L) { struct ubus_lua_event* event = NULL; - event = malloc(sizeof(struct ubus_lua_event)); + event = calloc(1, sizeof(struct ubus_lua_event)); if (!event) return NULL; - memset(event, 0, sizeof(struct ubus_lua_event)); event->e.cb = ubus_event_handler; /* update the he callback lookup table */ @@ -652,6 +750,142 @@ ubus_lua_listen(lua_State *L) { return 0; } +static void +ubus_sub_remove_handler(struct ubus_context *ctx, struct ubus_subscriber *s, + uint32_t id) +{ + struct ubus_lua_subscriber *sub; + + sub = container_of(s, struct ubus_lua_subscriber, s); + + lua_getglobal(state, "__ubus_cb_subscribe"); + lua_rawgeti(state, -1, sub->rremove); + lua_remove(state, -2); + + if (lua_isfunction(state, -1)) { + lua_call(state, 0, 0); + } else { + lua_pop(state, 1); + } +} + +static int +ubus_sub_notify_handler(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct ubus_subscriber *s; + struct ubus_lua_subscriber *sub; + + s = container_of(obj, struct ubus_subscriber, obj); + sub = container_of(s, struct ubus_lua_subscriber, s); + + lua_getglobal(state, "__ubus_cb_subscribe"); + lua_rawgeti(state, -1, sub->rnotify); + lua_remove(state, -2); + + if (lua_isfunction(state, -1)) { + if( msg ){ + ubus_lua_parse_blob_array(state, blob_data(msg), blob_len(msg), true); + lua_call(state, 1, 0); + } else { + lua_call(state, 0, 0); + } + } else { + lua_pop(state, 1); + } + + return 0; +} + + + +static void +ubus_lua_do_subscribe( struct ubus_context *ctx, lua_State *L, const char* target, + int idxnotify, int idxremove ) +{ + uint32_t id; + int status; + struct ubus_lua_subscriber *sub; + + if( ( status = ubus_lookup_id( ctx, target, &id ) ) ){ + lua_pushfstring( L, "Unable find target, status=%d", status ); + lua_error( L ); + } + + sub = calloc( 1, sizeof( struct ubus_lua_subscriber ) ); + if( !sub ){ + lua_pushstring( L, "Out of memory" ); + lua_error( L ); + } + + if( idxnotify ){ + lua_getglobal(L, "__ubus_cb_subscribe"); + lua_pushvalue(L, idxnotify); + sub->rnotify = luaL_ref(L, -2); + lua_pop(L, 1); + sub->s.cb = ubus_sub_notify_handler; + } + + if( idxremove ){ + lua_getglobal(L, "__ubus_cb_subscribe"); + lua_pushvalue(L, idxnotify); + sub->rnotify = luaL_ref(L, -2); + lua_pop(L, 1); + sub->s.remove_cb = ubus_sub_remove_handler; + } + + if( ( status = ubus_register_subscriber( ctx, &sub->s ) ) ){ + lua_pushfstring( L, "Failed to register subscriber, status=%d", status ); + lua_error( L ); + } + + if( ( status = ubus_subscribe( ctx, &sub->s, id) ) ){ + lua_pushfstring( L, "Failed to register subscriber, status=%d", status ); + lua_error( L ); + } +} + +static int +ubus_lua_subscribe(lua_State *L) { + int idxnotify, idxremove, stackstart; + struct ubus_lua_connection *c; + const char* target; + + idxnotify = idxremove = 0; + stackstart = lua_gettop( L ); + + + c = luaL_checkudata(L, 1, METANAME); + target = luaL_checkstring(L, 2); + luaL_checktype(L, 3, LUA_TTABLE); + + + lua_pushstring( L, "notify"); + lua_gettable( L, 3 ); + if( lua_type( L, -1 ) == LUA_TFUNCTION ){ + idxnotify = lua_gettop( L ); + } else { + lua_pop( L, 1 ); + } + + lua_pushstring( L, "remove"); + lua_gettable( L, 3 ); + if( lua_type( L, -1 ) == LUA_TFUNCTION ){ + idxremove = lua_gettop( L ); + } else { + lua_pop( L, 1 ); + } + + if( idxnotify ) + ubus_lua_do_subscribe( c->ctx, L, target, idxnotify, idxremove ); + + if( lua_gettop( L ) > stackstart ) + lua_pop( L, lua_gettop( L ) - stackstart ); + + return 0; +} + static int ubus_lua_send(lua_State *L) { @@ -698,12 +932,16 @@ static const luaL_Reg ubus[] = { { "connect", ubus_lua_connect }, { "objects", ubus_lua_objects }, { "add", ubus_lua_add }, + { "notify", ubus_lua_notify }, { "reply", ubus_lua_reply }, + { "defer_request", ubus_lua_defer_request }, + { "complete_deferred_request", ubus_lua_complete_deferred_request }, { "signatures", ubus_lua_signatures }, { "call", ubus_lua_call }, { "close", ubus_lua__gc }, { "listen", ubus_lua_listen }, { "send", ubus_lua_send }, + { "subscribe", ubus_lua_subscribe }, { "__gc", ubus_lua__gc }, { NULL, NULL }, }; @@ -757,5 +995,12 @@ luaopen_ubus(lua_State *L) lua_createtable(L, 1, 0); lua_setglobal(L, "__ubus_cb_event"); + /* create the subscriber table */ + lua_createtable(L, 1, 0); + lua_setglobal(L, "__ubus_cb_subscribe"); + + /* create the publisher table - notifications of new subs */ + lua_createtable(L, 1, 0); + lua_setglobal(L, "__ubus_cb_publisher"); return 0; }