#include #include #include #include #include "connections.h" #include "lua_interface.h" #include "notify.h" #define CONNECTION_META_TABLE "MetaConnection" #define CONNECTION_TABLE "Connection" #define CONNECTION_TABLE_UD_FIELD "core_" /** * HARD: shared common server state, updatable commands table * Interim: independent states, any global changes queued to all workers * Idea: can a proxy table be crafted to access a shared table-like c entity * Idea: eventual-consistency between lua states (somehow) * */ /** * Create a new referenced coroutine on lua state. * release with: * luaL_unref(L, LUA_REGISTRYINDEX, refkey); */ int lua_new_coroutine_ref(lua_State *L, lua_State **coL, int *refkey) { *refkey = LUA_NOREF; /* Create new coroutine on top of stack. */ *coL = lua_newthread(L); if (!*coL) { NOTIFY_ERROR("%s:%s", "lua_newthread", "failed"); return -1; } /* Store coroutine reference in state registry. */ *refkey = luaL_ref(L, LUA_REGISTRYINDEX); return 0; } /** * Connection Object * is a table with metatable for methods and userdata field * */ /** * Add a connection reference to lua stack * */ int lemu_connection_push(lua_State *L, struct connection *c) { connection_inc_ref(c); lua_newtable(L); // new connection table luaL_getmetatable(L, CONNECTION_META_TABLE); // locate meta lua_setmetatable(L, -2); // assign meta to connection table /* keeping a pointer in userdata, rather than light userdata, to get metatable support */ struct connection **cud = lua_newuserdatauv(L, sizeof c, 0); *cud = c; luaL_getmetatable(L, CONNECTION_META_TABLE); lua_setmetatable(L, -2); lua_setfield(L, -2, CONNECTION_TABLE_UD_FIELD); return 1; } /** * I guess this one would take a stack value to find a connection */ static int lemu_connection_create_(lua_State *L) { struct connection *c; luaL_checktype(L, 1, LUA_TSTRING); // c = connection_lookup(lua_tostring(L, 1)); c = NULL; return lemu_connection_push(L, c); } /** * this will only get called on userdata (how does that happen??) */ static int lemu_connection_destroy_(lua_State *L) { struct connection **cud = luaL_checkudata(L, 1, CONNECTION_META_TABLE); struct connection *c = *cud; connection_free(c); return 0; } /** * Send a fixed string to a connection. */ static int lemu_connection_send_(lua_State *L) { if (lua_gettop(L) < 2) { lua_pushliteral(L, "too few arguments"); lua_error(L); } luaL_checktype(L, 1, LUA_TTABLE); lua_getfield(L, 1, CONNECTION_TABLE_UD_FIELD); luaL_checktype(L, -1, LUA_TUSERDATA); struct connection **cud = lua_touserdata(L, -1); struct connection *c = *cud; luaL_checktype(L, 2, LUA_TSTRING); const char *message = lua_tostring(L, 2); connection_printf(c, "%s\n", message); return 0; } static const luaL_Reg Connection_funcs[] = { { "create", lemu_connection_create_ }, { NULL, NULL } }; static const luaL_Reg Connection_methods[] = { { "__gc", lemu_connection_destroy_ }, { "send", lemu_connection_send_ }, { NULL, NULL } }; /** * Initialize the Connection object prototypes */ int lemu_connection_luainit(lua_State *L) { luaL_newmetatable(L, CONNECTION_META_TABLE); // new userdata metatable, __name = CONNECTION_META_TABLE lua_pushstring(L, "__index"); lua_pushvalue(L, -2); // meta table lua_settable(L, -3); // becomes its own index table luaL_setfuncs(L, Connection_methods, 0); // add methods to metatable lua_pop(L, 1); luaL_newlibtable(L, Connection_funcs); // new table with functions luaL_setfuncs(L, Connection_funcs, 0); lua_setglobal(L, CONNECTION_TABLE); // make it available return 0; } // int luaopen_lemu(lua_State *L);