From a9b77b320674ce99536348420ec9824d21a856a8 Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
Date: Thu, 21 Apr 2016 00:38:30 +0200
Subject: degesch: expose channels and users to Lua
---
degesch.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 226 insertions(+), 5 deletions(-)
diff --git a/degesch.c b/degesch.c
index c21dba7..f1eceb8 100644
--- a/degesch.c
+++ b/degesch.c
@@ -8322,6 +8322,183 @@ lua_plugin_parse (lua_State *L)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#define XLUA_USER_METATABLE "user" ///< Identifier for the Lua metatable
+
+struct lua_user
+{
+ struct lua_plugin *plugin; ///< The plugin we belong to
+ struct user *user; ///< The user
+ struct weak_ref_link *weak_ref; ///< A weak reference link
+};
+
+static void
+lua_user_invalidate (void *object, void *user_data)
+{
+ struct lua_user *wrapper = user_data;
+ wrapper->user = NULL;
+ wrapper->weak_ref = NULL;
+ // This can in theory call the GC, order isn't arbitrary here
+ lua_cache_invalidate (wrapper->plugin->L, object);
+}
+
+static void
+lua_plugin_push_user (struct lua_plugin *plugin, struct user *user)
+{
+ lua_State *L = plugin->L;
+ if (lua_cache_get (L, user))
+ return;
+
+ struct lua_user *wrapper = lua_newuserdata (L, sizeof *wrapper);
+ luaL_setmetatable (L, XLUA_USER_METATABLE);
+ wrapper->plugin = plugin;
+ wrapper->user = user;
+ wrapper->weak_ref = user_weak_ref (user, lua_user_invalidate, wrapper);
+ lua_cache_store (L, user, -1);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+/// Identifier for the Lua metatable
+#define XLUA_CHANNEL_METATABLE "channel"
+
+struct lua_channel
+{
+ struct lua_plugin *plugin; ///< The plugin we belong to
+ struct channel *channel; ///< The channel
+ struct weak_ref_link *weak_ref; ///< A weak reference link
+};
+
+static void
+lua_channel_invalidate (void *object, void *user_data)
+{
+ struct lua_channel *wrapper = user_data;
+ wrapper->channel = NULL;
+ wrapper->weak_ref = NULL;
+ // This can in theory call the GC, order isn't arbitrary here
+ lua_cache_invalidate (wrapper->plugin->L, object);
+}
+
+static void
+lua_plugin_push_channel (struct lua_plugin *plugin, struct channel *channel)
+{
+ lua_State *L = plugin->L;
+ if (lua_cache_get (L, channel))
+ return;
+
+ struct lua_channel *wrapper = lua_newuserdata (L, sizeof *wrapper);
+ luaL_setmetatable (L, XLUA_CHANNEL_METATABLE);
+ wrapper->plugin = plugin;
+ wrapper->channel = channel;
+ wrapper->weak_ref = channel_weak_ref
+ (channel, lua_channel_invalidate, wrapper);
+ lua_cache_store (L, channel, -1);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+static int
+lua_user_gc (lua_State *L)
+{
+ struct lua_user *wrapper = luaL_checkudata (L, 1, XLUA_USER_METATABLE);
+ if (wrapper->user)
+ {
+ lua_cache_invalidate (L, wrapper->user);
+ user_weak_unref (wrapper->user, &wrapper->weak_ref);
+ wrapper->user = NULL;
+ }
+ return 0;
+}
+
+static int
+lua_user_get_nickname (lua_State *L)
+{
+ struct lua_user *wrapper = luaL_checkudata (L, 1, XLUA_USER_METATABLE);
+ luaL_argcheck (L, wrapper->user, 1, "dead reference used");
+ lua_pushstring (L, wrapper->user->nickname);
+ return 1;
+}
+
+static int
+lua_user_get_channels (lua_State *L)
+{
+ struct lua_user *wrapper = luaL_checkudata (L, 1, XLUA_USER_METATABLE);
+ luaL_argcheck (L, wrapper->user, 1, "dead reference used");
+
+ int i = 1;
+ lua_newtable (L);
+ LIST_FOR_EACH (struct user_channel, iter, wrapper->user->channels)
+ {
+ lua_plugin_push_channel (wrapper->plugin, iter->channel);
+ lua_rawseti (L, -2, i++);
+ }
+ return 1;
+}
+
+static luaL_Reg lua_user_table[] =
+{
+ { "__gc", lua_user_gc },
+ { "get_nickname", lua_user_get_nickname },
+ { "get_channels", lua_user_get_channels },
+ { NULL, NULL }
+};
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+static int
+lua_channel_gc (lua_State *L)
+{
+ struct lua_channel *wrapper =
+ luaL_checkudata (L, 1, XLUA_CHANNEL_METATABLE);
+ if (wrapper->channel)
+ {
+ lua_cache_invalidate (L, wrapper->channel);
+ channel_weak_unref (wrapper->channel, &wrapper->weak_ref);
+ wrapper->channel = NULL;
+ }
+ return 0;
+}
+
+static int
+lua_channel_get_name (lua_State *L)
+{
+ struct lua_channel *wrapper =
+ luaL_checkudata (L, 1, XLUA_CHANNEL_METATABLE);
+ luaL_argcheck (L, wrapper->channel, 1, "dead reference used");
+ lua_pushstring (L, wrapper->channel->name);
+ return 1;
+}
+
+static int
+lua_channel_get_users (lua_State *L)
+{
+ struct lua_channel *wrapper =
+ luaL_checkudata (L, 1, XLUA_CHANNEL_METATABLE);
+ luaL_argcheck (L, wrapper->channel, 1, "dead reference used");
+
+ int i = 1;
+ lua_newtable (L);
+ LIST_FOR_EACH (struct channel_user, iter, wrapper->channel->users)
+ {
+ lua_createtable (L, 0, 2);
+ lua_plugin_push_user (wrapper->plugin, iter->user);
+ lua_setfield (L, -2, "user");
+ lua_plugin_kv (L, "prefixes", iter->prefixes.str);
+
+ lua_rawseti (L, -2, i++);
+ }
+ return 1;
+}
+
+static luaL_Reg lua_channel_table[] =
+{
+ { "__gc", lua_channel_gc },
+ { "get_name", lua_channel_get_name },
+ { "get_users", lua_channel_get_users },
+ { NULL, NULL }
+};
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
#define XLUA_BUFFER_METATABLE "buffer" ///< Identifier for the Lua metatable
struct lua_buffer
@@ -8409,6 +8586,32 @@ lua_buffer_gc (lua_State *L)
return 0;
}
+static int
+lua_buffer_get_user (lua_State *L)
+{
+ struct lua_buffer *wrapper = luaL_checkudata (L, 1, XLUA_BUFFER_METATABLE);
+ luaL_argcheck (L, wrapper->buffer, 1, "dead reference used");
+
+ if (wrapper->buffer->user)
+ lua_plugin_push_user (wrapper->plugin, wrapper->buffer->user);
+ else
+ lua_pushnil (L);
+ return 1;
+}
+
+static int
+lua_buffer_get_channel (lua_State *L)
+{
+ struct lua_buffer *wrapper = luaL_checkudata (L, 1, XLUA_BUFFER_METATABLE);
+ luaL_argcheck (L, wrapper->buffer, 1, "dead reference used");
+
+ if (wrapper->buffer->channel)
+ lua_plugin_push_channel (wrapper->plugin, wrapper->buffer->channel);
+ else
+ lua_pushnil (L);
+ return 1;
+}
+
static int
lua_buffer_get_server (lua_State *L)
{
@@ -8450,11 +8653,13 @@ lua_buffer_execute (lua_State *L)
static luaL_Reg lua_buffer_table[] =
{
// TODO: some useful methods or values
- { "__gc", lua_buffer_gc },
- { "get_server", lua_buffer_get_server },
- { "log", lua_buffer_log },
- { "execute", lua_buffer_execute },
- { NULL, NULL }
+ { "__gc", lua_buffer_gc },
+ { "get_user", lua_buffer_get_user },
+ { "get_channel", lua_buffer_get_channel },
+ { "get_server", lua_buffer_get_server },
+ { "log", lua_buffer_log },
+ { "execute", lua_buffer_execute },
+ { NULL, NULL }
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -8472,6 +8677,19 @@ lua_server_gc (lua_State *L)
return 0;
}
+static int
+lua_server_get_user (lua_State *L)
+{
+ struct lua_server *wrapper = luaL_checkudata (L, 1, XLUA_SERVER_METATABLE);
+ luaL_argcheck (L, wrapper->server, 1, "dead reference used");
+
+ if (wrapper->server->irc_user)
+ lua_plugin_push_user (wrapper->plugin, wrapper->server->irc_user);
+ else
+ lua_pushnil (L);
+ return 1;
+}
+
static int
lua_server_get_buffer (lua_State *L)
{
@@ -8500,6 +8718,7 @@ static luaL_Reg lua_server_table[] =
{
// TODO: some useful methods or values
{ "__gc", lua_server_gc },
+ { "get_user", lua_server_get_user },
{ "get_buffer", lua_server_get_buffer },
{ "send", lua_server_send },
{ NULL, NULL }
@@ -9631,6 +9850,8 @@ lua_plugin_load (struct app_context *ctx, const char *filename,
// Create metatables for our objects
lua_plugin_create_meta (L, XLUA_HOOK_METATABLE, lua_hook_table);
+ lua_plugin_create_meta (L, XLUA_USER_METATABLE, lua_user_table);
+ lua_plugin_create_meta (L, XLUA_CHANNEL_METATABLE, lua_channel_table);
lua_plugin_create_meta (L, XLUA_BUFFER_METATABLE, lua_buffer_table);
lua_plugin_create_meta (L, XLUA_SERVER_METATABLE, lua_server_table);
lua_plugin_create_meta (L, XLUA_SCHEMA_METATABLE, lua_schema_table);
--
cgit v1.2.3-70-g09d2