diff options
Diffstat (limited to 'src/lua_binding_functions.c')
| -rw-r--r-- | src/lua_binding_functions.c | 782 |
1 files changed, 782 insertions, 0 deletions
diff --git a/src/lua_binding_functions.c b/src/lua_binding_functions.c new file mode 100644 index 0000000..3d8f3ee --- /dev/null +++ b/src/lua_binding_functions.c @@ -0,0 +1,782 @@ +/************************************************************************* + > File Name: lua_binding_functions.c + > Author: + > Created Time: 2024-08 + > Encoding : UTF-8 + ************************************************************************/ + +/************************************************************************* + * 声明并定义所有需要在lua状态机中绑定的函数 + * version + * [ v0.1 ] + * 08-14 + * 1. 实现函数 + * 新增插件注册函数 + * int lua_plugin_manage_regist + * 新增会话相关函数 + * int lua_session_get_id + * int lua_session_set_id + * int lua_session_get_type + * int lua_session_set_type + * 新增message相关函数 + * int lua_mq_create_topic + * int lua_mq_get_topic_id + * int lua_mq_update_topic + * int lua_mq_destory_topic + * int lua_mq_subscribe_topic + * int lua_mq_topic_is_active + * int lua_mq_publish_message + * int lua_mq_ignore_message + * int lua_mq_unignore_message + ************************************************************************/ +#include "lua_plugin_manage_internal.h" +#include "session_mq.h" + +/* ***** ***** ***** ***** ***** ***** */ +int lua_plugin_manage_regist(lua_State *state) +{ + /* 参数个数检查 */ + if (lua_gettop(state) != 4) + { + lua_settop(state, 0); + return 0; + } + + /* 参数类型检查 */ + if (lua_type(state, -1) != LUA_TTABLE || lua_type(state, -2) != LUA_TFUNCTION || + lua_type(state, -3) != LUA_TFUNCTION || lua_type(state, -4) != LUA_TLIGHTUSERDATA) + { + lua_settop(state, 0); + return 0; + } + + /* 取出处理第四个参数 */ + lua_getfield(state, -1, LUA_PLUGIN_ENV_DEFAULT_KEY); /* stack 4, table中取出对应结构的指针 */ + if (lua_type(state, -1) != LUA_TLIGHTUSERDATA) + { + lua_settop(state, 0); + return 0; + } + struct lua_model *plugin_env = (struct lua_model *)lua_topointer(state, -1); + lua_pop(state, 2); + // debug_lua_state_stack(state, 0, "here"); + // printf("env pointer is %p\n", plugin_env); + + /* 取出处理第三个参数 */ + int ctx_free_id = luaL_ref(state, LUA_REGISTRYINDEX); /* stack 3 */ + if (ctx_free_id == LUA_REFNIL) + { + lua_settop(state, 0); + return 0; + } + + /* 取出处理第二个参数 */ + int ctx_new_id = luaL_ref(state, LUA_REGISTRYINDEX); /* stack 2 */ + if (ctx_new_id == LUA_REFNIL) + { + luaL_unref(state, LUA_REGISTRYINDEX, ctx_free_id); + lua_settop(state, 0); + return 0; + } + + /* 取出处理第一个参数 */ + struct stellar *st = (struct stellar *)lua_topointer(state, -1); /* stack 1 */ + if (!st) + { + luaL_unref(state, LUA_REGISTRYINDEX, ctx_new_id); + luaL_unref(state, LUA_REGISTRYINDEX, ctx_free_id); + lua_settop(state, 0); + return 0; + } + lua_pop(state, 1); + + /* 在stellar中注册, 获取注册id */ + int plugin_id = stellar_session_plugin_register(st, lpm_ctx_new_func, lpm_ctx_free_func, (void *)plugin_env); +#ifdef LUAPLUGIN_BASIC_UNITTEST + LOGDEBUG("now regist new plugin, plugin id is %d, %d, %d\n", plugin_id, ctx_new_id, ctx_free_id); +#endif + + /* TODO: 如果运行完全符合预期的话, 理论上仅有thread 0在此处需要插入新的插件, 且不应该有错误 + * 对于其他线程这里应该直接检查ref id是否一致即可, 按理说不应该再插入新插件 + * 后续可以修改为根据线程号执行不同的处理流程 + */ + /* 如果在其他线程中已经完成过注册 */ + struct lua_plugin *search_plugin = NULL; + while ((search_plugin = utarray_next(plugin_env->plugin_array, search_plugin))) + { + if (search_plugin->plugin_id == plugin_id) + { + /* 初始化过程中已经进行过加载 */ + if (search_plugin->ctx_new_ref != ctx_new_id || search_plugin->ctx_free_ref != ctx_free_id) + { + LOGERROR("regist plugin, same id with different function ref"); + LOGERROR("plugin id %d, registed %d, %d, new ref %d, %d", plugin_id, + search_plugin->ctx_new_ref, search_plugin->ctx_free_ref, + ctx_new_id, ctx_free_id); + lua_settop(state, 0); + return 0; + } + lua_settop(state, 0); + lua_pushinteger(state, plugin_id); + return 1; + } + } + + /* 将注册完成的新插件插入到队列中 */ + struct lua_plugin new_plugin; + memset(&new_plugin, 0, sizeof(new_plugin)); + new_plugin.plugin_id = plugin_id; + new_plugin.ctx_new_ref = ctx_new_id; + new_plugin.ctx_free_ref = ctx_free_id; + utarray_push_back(plugin_env->plugin_array, &new_plugin); + plugin_env->plugin_count += 1; + + lua_settop(state, 0); + lua_pushinteger(state, plugin_id); + + return 1; +} + +/* ***** ***** ***** ***** ***** ***** */ +int lua_session_get_id(lua_State *state) +{ + /* 参数个数检查 */ + if (lua_gettop(state) != 1) + { + lua_settop(state, 0); + return 0; + } + + /* 参数类型检查 */ + if (lua_type(state, -1) != LUA_TLIGHTUSERDATA) + { + lua_settop(state, 0); + return 0; + } + + struct session *sess = (struct session *)lua_topointer(state, -1); + if (!sess) + { + lua_settop(state, 0); + return 0; + } + lua_pop(state, 1); + + lua_pushinteger(state, session_get_id(sess)); + return 1; +} + +int lua_session_set_id(lua_State *state) +{ + /* 参数个数检查 */ + if (lua_gettop(state) != 2) + { + lua_settop(state, 0); + return 0; + } + + /* 参数类型检查 */ + if (lua_type(state, -1) != LUA_TNUMBER || lua_type(state, -2) != LUA_TLIGHTUSERDATA) + { + lua_settop(state, 0); + return 0; + } + + int setid = lua_tointeger(state, -1); + lua_pop(state, 1); + struct session *sess = (struct session *)lua_topointer(state, -1); + lua_pop(state, 1); + + session_set_id(sess, setid); + return 0; +} + +int lua_session_get_type(lua_State *state) +{ + /* 参数个数检查 */ + if (lua_gettop(state) != 1) + { + lua_settop(state, 0); + return 0; + } + + /* 参数类型检查 */ + if (lua_type(state, -1) != LUA_TLIGHTUSERDATA) + { + lua_settop(state, 0); + return 0; + } + + struct session *sess = (struct session *)lua_topointer(state, -1); + if (!sess) + { + lua_settop(state, 0); + return 0; + } + lua_pop(state, 1); + + lua_pushinteger(state, session_get_type(sess)); + return 1; +} + +int lua_session_set_type(lua_State *state) +{ + /* 参数个数检查 */ + if (lua_gettop(state) != 2) + { + lua_settop(state, 0); + return 0; + } + + /* 参数类型检查 */ + if (lua_type(state, -1) != LUA_TNUMBER || lua_type(state, -2) != LUA_TLIGHTUSERDATA) + { + lua_settop(state, 0); + return 0; + } + + int settype = lua_tointeger(state, -1); + lua_pop(state, 1); + struct session *sess = (struct session *)lua_topointer(state, -1); + lua_pop(state, 1); + + session_set_id(sess, settype); + return 0; +} + +/* ***** ***** ***** ***** ***** ***** */ +/* + * TODO: 未完整考虑线程安全问题, 例如 + * 多个线程同时注册一个topic, 是否需要做处理等。 + */ +static UT_icd lua_plugin_mq_icd = {sizeof(struct lua_plugin_mq), NULL, NULL, NULL}; + +int lua_mq_create_topic(lua_State *state) +{ + /* 参数个数检查 */ + if (lua_gettop(state) != 4) + { + lua_settop(state, 0); + return 0; + } + + /* 参数类型检查 */ + if (lua_type(state, -1) != LUA_TTABLE || lua_type(state, -2) != LUA_TFUNCTION || + lua_type(state, -3) != LUA_TSTRING || lua_type(state, -4) != LUA_TLIGHTUSERDATA) + { + lua_settop(state, 0); + return 0; + } + + /* 创建对该table的引用, 防止该table被回收 */ + int private_ref = luaL_ref(state, LUA_REGISTRYINDEX); /* stack top function */ + if (private_ref == LUA_REFNIL) + { + lua_settop(state, 0); + return 0; + } + + /* 导出free message的调用函数 */ + int free_ref = luaL_ref(state, LUA_REGISTRYINDEX); + if (free_ref == LUA_REFNIL) + { + luaL_unref(state, LUA_REGISTRYINDEX, private_ref); + lua_settop(state, 0); + return 0; + } + + /* 出栈队列名称 */ + char *name = strdup((char *)lua_tostring(state, -1)); + lua_pop(state, 1); + + /* 出栈传入的stellar */ + struct stellar *st = (struct stellar *)lua_topointer(state, -1); + if (!st) + { + luaL_unref(state, LUA_REGISTRYINDEX, free_ref); + luaL_unref(state, LUA_REGISTRYINDEX, private_ref); + if (name) + free(name); + lua_settop(state, 0); + return 0; + } + lua_settop(state, 0); + + /* 插入新的元素 */ + struct lua_message_mq new_mq; + memset(&new_mq, 0, sizeof(new_mq)); + utarray_push_back(global_schema->message_mq_array, &new_mq); + /* 从队列尾部取出最后一个元素 */ + struct lua_message_mq *mq = utarray_eltptr(global_schema->message_mq_array, (utarray_len(global_schema->message_mq_array) - 1)); + mq->freemessage_ref = free_ref; + mq->mq_private_ref = private_ref; + /* 调用stellar中mq的topic创建函数 */ + /* BugFix: 仔细看了代码, 在stellar中没有对name做拷贝处理, 这里name不能释放 */ + int topic_id = stellar_session_mq_create_topic(st, (const char *)name, lpm_message_free_func, mq); + /* 创建topic失败, 还原创建topic之前的状态 */ + if (topic_id < 0) + { + utarray_pop_back(global_schema->message_mq_array); + luaL_unref(state, LUA_REGISTRYINDEX, free_ref); + luaL_unref(state, LUA_REGISTRYINDEX, private_ref); + if (name) + free(name); + return 0; + } + + lua_rawgeti(state, LUA_REGISTRYINDEX, mq->mq_private_ref); +#if 0 + /* 不检查了, 直接覆盖 */ + /* 在传入的table中检查是否存在与mq_private_env同名的元素 */ + lua_getfield(state, -1, LUA_MQ_ENV_DEFAULT_KEY); /* stack top nil */ + if (lua_type(state, -1) != LUA_TNIL) { + lua_settop(state, 0); + return 0; + } + lua_pop(state, 1); /* stack top table */ +#endif + /* 在该table中加入新元素 */ + lua_pushlightuserdata(state, (void *)mq); /* stack top new_mq */ + lua_setfield(state, -2, LUA_MQ_ENV_DEFAULT_KEY); /* stack top table */ + mq->topic_id = topic_id; + + lua_settop(state, 0); + lua_pushinteger(state, topic_id); + + return 1; +} + +int lua_mq_get_topic_id(lua_State *state) +{ + /* 参数个数检查 */ + if (lua_gettop(state) != 2) + { + lua_settop(state, 0); + return 0; + } + + /* 参数类型检查 */ + if (lua_type(state, -1) != LUA_TSTRING || lua_type(state, -2) != LUA_TLIGHTUSERDATA) + { + lua_settop(state, 0); + return 0; + } + + /* 出栈队列名称 */ + char *name = strdup(lua_tostring(state, -1)); + lua_pop(state, 1); + + /* 出栈传入的stellar */ + struct stellar *st = (struct stellar *)lua_topointer(state, -1); + if (!st) + { + if (name) + free(name); + return 0; + } + lua_pop(state, 1); + + int topic_id = stellar_session_mq_get_topic_id(st, (const char *)name); + if (name) + free(name); + + lua_settop(state, 0); + lua_pushinteger(state, topic_id); + return 1; +} + +int lua_mq_update_topic(lua_State *state) +{ + /* 参数个数检查 */ + if (lua_gettop(state) != 4) + { + lua_settop(state, 0); + return 0; + } + + /* 参数类型检查 */ + if (lua_type(state, -1) != LUA_TTABLE || lua_type(state, -2) != LUA_TFUNCTION || + lua_type(state, -3) != LUA_TNUMBER || lua_type(state, -4) != LUA_TLIGHTUSERDATA) + { + lua_settop(state, 0); + return 0; + } + + /* 创建对该table的引用, 防止该table被回收 */ + int private_ref = luaL_ref(state, LUA_REGISTRYINDEX); /* stack top function */ + if (private_ref == LUA_REFNIL) + { + lua_settop(state, 0); + return 0; + } + + /* 导出free message的调用函数 */ + int free_ref = luaL_ref(state, LUA_REGISTRYINDEX); + if (free_ref == LUA_REFNIL) + { + luaL_unref(state, LUA_REGISTRYINDEX, private_ref); + lua_settop(state, 0); + return 0; + } + + /* topic_id */ + int topic_id = lua_tointeger(state, -1); + lua_pop(state, 1); + + /* 出栈传入的stellar */ + struct stellar *st = (struct stellar *)lua_topointer(state, -1); + if (!st) + { + luaL_unref(state, LUA_REGISTRYINDEX, free_ref); + luaL_unref(state, LUA_REGISTRYINDEX, private_ref); + lua_settop(state, 0); + return 0; + } + lua_settop(state, 0); + + struct lua_message_mq *mq = search_message_mq_by_id(topic_id); + if (!mq || mq->topic_id != topic_id) + { + /* 如果topic不是lua创建的, 需要加入管理 */ + struct lua_message_mq new_mq; + memset(&new_mq, 0, sizeof(new_mq)); + utarray_push_back(global_schema->message_mq_array, &new_mq); + mq = utarray_eltptr(global_schema->message_mq_array, (utarray_len(global_schema->message_mq_array) - 1)); + + if (stellar_session_mq_update_topic(st, topic_id, lpm_message_free_func, mq)) + { + utarray_pop_back(global_schema->message_mq_array); + luaL_unref(state, LUA_REGISTRYINDEX, free_ref); + luaL_unref(state, LUA_REGISTRYINDEX, private_ref); + return 0; + } + + mq->freemessage_ref = free_ref; + mq->mq_private_ref = private_ref; + mq->topic_id = topic_id; + lua_pushboolean(state, 1); + return 1; + } + else + { + /* 本身是由lua创建的 */ + /* 更新private_ref */ + lua_rawgeti(state, LUA_REGISTRYINDEX, private_ref); + lua_pushlightuserdata(state, (void *)mq); /* stack top new_mq */ + lua_setfield(state, -2, LUA_MQ_ENV_DEFAULT_KEY); /* stack top table */ + luaL_unref(state, LUA_REGISTRYINDEX, mq->mq_private_ref); + mq->mq_private_ref = private_ref; + + /* 更新free function ref */ + luaL_unref(state, LUA_REGISTRYINDEX, mq->freemessage_ref); + mq->freemessage_ref = free_ref; + } + + lua_settop(state, 0); + lua_pushboolean(state, 1); + + return 1; +} + +int lua_mq_destory_topic(lua_State *state) +{ + /* 参数个数检查 */ + if (lua_gettop(state) != 2) + { + lua_settop(state, 0); + return 0; + } + + /* topic_id */ + int topic_id = lua_tointeger(state, -1); + lua_pop(state, 1); + + /* 出栈传入的stellar */ + struct stellar *st = (struct stellar *)lua_topointer(state, -1); + if (!st) + { + lua_settop(state, 0); + return 0; + } + lua_settop(state, 0); + + /* 优先调用C函数进行卸载 */ + if (stellar_session_mq_destroy_topic(st, topic_id) < 0) + { + return 0; + } + + /* 不方便删除, 将id置为-1, 确保匹配不到 */ + struct lua_message_mq *mq = search_message_mq_by_id(topic_id); + if (mq) + { + mq->topic_id = -1; + luaL_unref(state, LUA_REGISTRYINDEX, mq->mq_private_ref); + luaL_unref(state, LUA_REGISTRYINDEX, mq->freemessage_ref); + mq->freemessage_ref = 0; + mq->mq_private_ref = 0; + } + + lua_pushboolean(state, 1); + return 1; +} + +int lua_mq_subscribe_topic(lua_State *state) +{ + /* 参数个数检查 */ + if (lua_gettop(state) != 2) + { + lua_settop(state, 0); + return 0; + } + + /* 参数类型检查 */ + if (lua_type(state, -1) != LUA_TNUMBER || lua_type(state, -2) != LUA_TFUNCTION || + lua_type(state, -3) != LUA_TNUMBER || lua_type(state, -4) != LUA_TLIGHTUSERDATA) + { + lua_settop(state, 0); + return 0; + } + + /* 读取参数 */ + int plugin_id = lua_tointeger(state, -1); + lua_pop(state, 1); + + int on_message_ref = luaL_ref(state, -1); + if (on_message_ref == LUA_REFNIL) + { + lua_settop(state, 0); + return 0; + } + + int topic_id = lua_tointeger(state, -1); + lua_pop(state, 1); + + struct stellar *st = (struct stellar *)lua_topointer(state, -1); + if (!st) + { + lua_settop(state, 0); + return 0; + } + lua_pop(state, 1); + + lua_settop(state, 0); + if (stellar_session_mq_subscribe(st, topic_id, lpm_on_session_msg_func, plugin_id)) + { + + /* 订阅失败, 返回false */ + lua_pushboolean(state, 0); + } + else + { + struct lua_plugin *plugin = search_plugin_by_id(plugin_id); + if (plugin) + { + if (!plugin->sub_topic_array) + { + /* 该插件尚未注册任何topic, 注册第一个topic时将创建接收的topic列表 */ + utarray_new(plugin->sub_topic_array, &lua_plugin_mq_icd); + } + else + { + /* 如果该插件中之前已经订阅过该消息, 更新message函数 */ + struct lua_plugin_mq *mq = NULL; + while ((mq = utarray_next(plugin->sub_topic_array, mq))) + { + if (mq->topic_id == topic_id) + { + luaL_unref(state, LUA_REGISTRYINDEX, mq->onmessage_ref); + mq->onmessage_ref = on_message_ref; + lua_pushboolean(state, 1); + return 1; + } + } + } + + struct lua_plugin_mq new_mq; + memset(&new_mq, 0, sizeof(new_mq)); + new_mq.topic_id = topic_id; + new_mq.onmessage_ref = on_message_ref; + utarray_push_back(plugin->sub_topic_array, &new_mq); + } + /* 订阅成功, 返回true */ + lua_pushboolean(state, 1); + } + + return 1; +} + +int lua_mq_publish_message(lua_State *state) +{ + /* 参数个数检查 */ + if (lua_gettop(state) != 3) + { + lua_settop(state, 0); + return 0; + } + + /* 参数类型检查 */ + if (lua_type(state, -1) != LUA_TTABLE || lua_type(state, -2) != LUA_TNUMBER || + lua_type(state, -3) != LUA_TLIGHTUSERDATA) + { + lua_settop(state, 0); + return 0; + } + + /* 倒序依次获取参数 */ + int mess_ref = luaL_ref(state, LUA_REGISTRYINDEX); + if (mess_ref == LUA_REFNIL) + { + lua_settop(state, 0); + return 0; + } + + int topic_id = lua_tointeger(state, -1); + lua_pop(state, 1); + + struct session *sess = (struct session *)lua_topointer(state, -1); + if (!sess) + { + luaL_unref(state, LUA_REGISTRYINDEX, mess_ref); + lua_settop(state, 0); + return 0; + } + lua_settop(state, 0); + + /* 创建一段数据引用 */ + struct lua_context *new_context = (struct lua_context *)calloc(1, sizeof(struct lua_context)); + if (__glibc_unlikely(!new_context)) + { + luaL_unref(state, LUA_REGISTRYINDEX, mess_ref); + return 0; + } + new_context->context_ref_id = mess_ref; + + /* 调用C接口发布消息 */ + if (session_mq_publish_message(sess, topic_id, new_context)) + { + luaL_unref(state, LUA_REGISTRYINDEX, new_context->context_ref_id); + free(new_context); + lua_pushboolean(state, 0); + } + else + { + lua_pushboolean(state, 1); + } + + return 1; +} + +int lua_mq_ignore_message(lua_State *state) +{ + /* 参数个数检查 */ + if (lua_gettop(state) != 4) + { + lua_settop(state, 0); + return 0; + } + + /* 参数类型检查 */ + if (lua_type(state, -1) != LUA_TNUMBER || lua_type(state, -2) != LUA_TNUMBER || + lua_type(state, -3) != LUA_TLIGHTUSERDATA) + { + lua_settop(state, 0); + return 0; + } + + /* 倒序获取参数 */ + int plugin_id = lua_tointeger(state, -1); + lua_pop(state, 1); + + int topic_id = lua_tointeger(state, -1); + lua_pop(state, 1); + + struct session * sess = (struct session *)lua_topointer(state, -1); + if ( !sess ) { + lua_settop(state, 0); + return 0; + } + lua_settop(state, 0); + + if (session_mq_ignore_message(sess, topic_id, plugin_id)) + lua_pushboolean(state, 0); + else + lua_pushboolean(state, 1); + + return 1; +} + +int lua_mq_unignore_message(lua_State *state) +{ + /* 参数个数检查 */ + if (lua_gettop(state) != 4) + { + lua_settop(state, 0); + return 0; + } + + /* 参数类型检查 */ + if (lua_type(state, -1) != LUA_TNUMBER || lua_type(state, -2) != LUA_TNUMBER || + lua_type(state, -3) != LUA_TLIGHTUSERDATA) + { + lua_settop(state, 0); + return 0; + } + + /* 倒序获取参数 */ + int plugin_id = lua_tointeger(state, -1); + lua_pop(state, 1); + + int topic_id = lua_tointeger(state, -1); + lua_pop(state, 1); + + struct session * sess = (struct session *)lua_topointer(state, -1); + if ( !sess ) { + lua_settop(state, 0); + return 0; + } + lua_settop(state, 0); + + if (session_mq_unignore_message(sess, topic_id, plugin_id)) + lua_pushboolean(state, 0); + else + lua_pushboolean(state, 1); + + return 1; +} + +int lua_mq_topic_is_active(lua_State *state) +{ + /* 参数个数检查 */ + if (lua_gettop(state) != 4) + { + lua_settop(state, 0); + return 0; + } + + /* 参数类型检查 */ + if (lua_type(state, -1) != LUA_TNUMBER || lua_type(state, -2) != LUA_TLIGHTUSERDATA) + { + lua_settop(state, 0); + return 0; + } + + /* 倒序获取参数 */ + int topic_id = lua_tointeger(state, -1); + lua_pop(state, 1); + + struct session * sess = (struct session *)lua_topointer(state, -1); + if ( !sess ) { + lua_settop(state, 0); + return 0; + } + lua_settop(state, 0); + + /* 1 means active */ + if (session_mq_topic_is_active(sess, topic_id) == 1) + lua_pushboolean(state, 1); + else + lua_pushboolean(state, 0); + + return 1; +}
\ No newline at end of file |
