degesch: expose channels and users to Lua

This commit is contained in:
Přemysl Eric Janouch 2016-04-21 00:38:30 +02:00
parent 29418e5e55
commit a9b77b3206
Signed by: p
GPG Key ID: B715679E3A361BE6
1 changed files with 226 additions and 5 deletions

221
degesch.c
View File

@ -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)
{
@ -8451,6 +8654,8 @@ static luaL_Reg lua_buffer_table[] =
{
// TODO: some useful methods or values
{ "__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 },
@ -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);