rough framework
[lemu] / lua_interface.c
diff --git a/lua_interface.c b/lua_interface.c
new file mode 100644 (file)
index 0000000..03496e8
--- /dev/null
@@ -0,0 +1,168 @@
+#include <stdlib.h>
+
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+
+#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);