/************************************************************************* > File Name: lua_plugin_manage_internal.h > Author: > Created Time: 2024-08 > Encoding : UTF-8 ************************************************************************/ /************************************************************************* * version * [ v0.1 ] * 08-02 * 完成函数注册及数据注册功能 * 1. 声明及定义结构 * struct lua_binding_function; * enum BINDING_DATATYPE; * struct lua_binding_data; * 2. 声明函数 * int lua_cbinding_function; * int lua_cbinding_function_remove; * int lua_cbinding_data; * int lua_cbinding_data_remove; * int lua_cbinding_functions; * int lua_cbinding_datas; * * 08-05 * 基本完成lua_plugin_manage中主流程 * 1. 声明及定义结构 * struct lua_config_specific; * struct lua_script; * struct lua_session_plugin; * struct lua_plugin_env; * struct lua_thread_state; * struct lua_plugin_manage_schema; * 2. 声明函数 * void specific_instance_copy; * void specific_instance_destory; * int script_instance_init_byname; * int script_instance_init_byrefid; * void script_instance_clean; * int script_execute; (暂未实现) * int session_plugin_instance_init; * void session_plugin_instance_destory; * int plugin_env_instance_init; * void plugin_env_instance_destory; * int thread_state_instance_init; * void thread_state_instance_destory; * int thread_state_instance_load; * int lua_plugin_manage_config_load; * int lua_plugin_manage_thread_load; * * 08-06 * 完成数据相关操作, 并补全函数script_execute * 完成注册至C插件管理器中的session_ctx_new_func及session_ctx_free_func函数 * 1. 声明并定义结构 * struct lua_cdata; * struct lua_context; * 2. 声明函数 * int lua_cdata_push_stack; * int lua_cdata_pop_stack; * void lua_cdata_destory; * struct lua_context * lua_context_new; * int lua_context_push_stack; * void lua_context_free; * * void *lpm_ctx_new_func; * void lpm_ctx_free_func; * * 08-07 * BugFix: * 修改struct lua_plugin_env, 其中增加文件路径 * 防止在加载过程中由于函数重名导致的加载错误 * * 08-08 * 整体重构状态机相关结构定义, 拆分高频访问数据与低频访问数据 * 状态机中数据管理由树形结构修改为数组型结构 * 经过多次验证, 相同状态机在执行相同操作后返回结果及中间产物一致, 合并一些冗余数据 * 1. 声明并定义结构 * struct lua_plugin_statistics; * struct lua_plugin; * struct lua_model; * struct lua_plugin_manage_schema; * * 08-14 * 新增message相关结构定义 * 1. 声明并定义结构 * struct lua_plugin_mq; * struct lua_message_mq; * 2. 声明函数 * void lpm_message_free_func * void lpm_on_session_msg_func * struct lua_plugin * search_plugin_by_id * struct lua_message_mq * search_message_mq_by_id ************************************************************************/ #ifndef LUA_PLUGIN_MANAGE_INTERNAL_H #define LUA_PLUGIN_MANAGE_INTERNAL_H #include "lua_plugin_manage.h" #include "lpm_log.h" #include #include #include #include enum LUA_PLUGIN_RETURN { /* 状态机相关的错误码 */ STATE_LOAD_FILE_ERR = -400, /* 状态机加载lua文件时出错, 可能原因是文件不存在或文件无法加载 */ STATE_CREATE_ENV_FAIL, /* 在状态机中创建新的plugin_env时出现错误, 无法创建或该模块之前加载过程中的引用ID与新创建ID不同 */ STATE_GET_LOAD_FAIL, /* 状态机加载load函数时出现错误, 该函数不存在或引用ID有问题 */ STATE_GET_UNLOAD_FAIL, /* 状态机加载unload函数时出现错误, 该函数不存在或引用ID有问题 */ /* lua代码块运行错误码 */ CHUNK_TYPE_NOT_FUNCTION = -300, /* 获取得到的代码块类型并非可执行的lua语句, 无法执行 */ CHUNK_RUN_CODE_FAIL, /* 调用代码过程中运行失败, 失败的具体报错信息会保存在栈中, 通过日志输出 */ CHUNK_RCOUNT_ERR, /* 尝试接收返回值, 但传入接收返回值的队列长度小于实际返回值个数 */ /* lua与C之间数据转换或操作错误码 */ DATA_PUSHSTACK_ERR = -200, /* 数据入栈过程中遇到未知的问题 */ DATA_POPSTACK_ERR, /* 数据从状态机中出栈过程中遇到未知的问题 */ DATA_POPSTACK_NODATA, /* 出栈过程中栈内无数据, 导致出栈失败 */ DATA_TYPE_UNKNOWN, /* 无法识别的struct lua_cdata数据类型, 或在该函数中操作了不支持的数据类型 */ /* lua函数或数据绑定错误码 */ BIND_NAMESPACE_TYPE_ERR = -100, /* 绑定或删除过程中使用命名空间, 但命名空间数据类型不符 */ BIND_FUNCTION_TYPE_ERR, /* 绑定或删除函数过程中数据类型错误 */ BIND_DATA_TYPE_ERR, /* 绑定或删除全局变量过程中数据类型错误 */ BIND_DATA_TYPE_UNKNOWN, /* struct lua_binding_data格式中数据类型无法识别, 或在该功能中操作了不支持的数据类型 */ /* 通用返回值 */ PARAM_ERR = -1, /* 传入参数错误, 可能是指针为空或类型不符合 */ SUCCESS = 0, /* 运行成功 */ }; /* ***** ***** ***** ***** ***** ***** */ /* 此部分主要功能为C向lua中注册函数及数据, 实现在lua_plugin_binding.c中 */ /* 需要注册至lua中的函数 */ struct lua_binding_function { /* 注册函数原型 */ lua_CFunction function; /* 注册至lua中的函数名称 */ char *function_name; /* 注册至lua中的命名空间名称 */ char *space_name; }; /* 定义在lua_plugin_binding.c文件中 */ /* 所有需要注册至lua状态机中供lua调用的函数 */ extern struct lua_binding_function lua_bind_functions[]; /* 暂时支持前四种数据类型提前注册至lua状态机中 */ /* 其余类型用于运行lua函数等场景 */ enum DATATYPE { DATATYPE_BEGIN = 0, /* nil类型 */ DATATYPE_NIL, /* bool类型 */ DATATYPE_BOOL, /* int类型 */ DATATYPE_INT, /* double类型 */ DATATYPE_NUM, /* 字符串类型 */ DATATYPE_STRING, /* 以下类型不能用于全局变量注册, 仅用于函数等场景 */ /* table类型 */ DATATYPE_TABLE, /* 指针类型 */ DATATYPE_POINTER, /* context上下文类型 */ DATATYPE_CONTEXT, DATATYPE_END }; /* 需要注册至lua状态机中的数据 */ struct lua_binding_data { /* 注册的数据类型 */ enum DATATYPE data_type; /* 注册数数据值 */ char *data_value; /* 注册的数据名称 */ char *data_name; /* 注册至lua中的命名空间名称 */ char *space_name; }; /* 定义在lua_plugin_binding.c中 */ /* 所有需要注册至lua状态机中的全局数据 */ extern struct lua_binding_data lua_bind_datas[]; /* 将lua_bind_functions中提前注册的所有函数注册至state状态机中 */ int lua_cbinding_functions(lua_State *state); /* 将lua_bind_datas中提前注册的所有数据注册至state状态机中 */ int lua_cbinding_datas(lua_State *state); /* ***** ***** ***** ***** ***** ***** */ /* 此部分主要用于lua与C之间的数据转换与传递, 实现在lua_plugin_data.c中 */ struct lua_cdata; // struct lua_ctable; struct lua_context; /* 保存lua数据的结构 */ struct lua_cdata { enum DATATYPE cdata_type; union { int cdata_bool; int cdata_int; double cdata_num; char *cdata_string; /* table暂时只有plugin_env场景下使用, 暂时使用索引进行操作 */ int cdata_table; void *cdata_pointer; struct lua_context *cdata_context; }; }; /* 将一个data结构入栈 */ int lua_cdata_push_stack(lua_State *state, struct lua_cdata *cdata); /* 从栈中弹出一个元素, 并保存在data结构中 */ int lua_cdata_pop_stack(lua_State *state, struct lua_cdata *cdata); /* 销毁一个data结构, 只有string类型需要调用此函数, 其他的情况直接释放即可 */ void lua_cdata_destory(struct lua_cdata *cdata); /* 上下文结构, 保存临时数据 */ struct lua_context { // lua_State *context_state; int context_ref_id; }; /* 在状态机中生成一个context */ struct lua_context *lua_context_new(lua_State *state); /* 将一个context入栈 */ int lua_context_push_stack(lua_State *state, struct lua_context *context); /* 释放一个context */ void lua_context_free(lua_State *state, struct lua_context *context); /* ***** ***** ***** ***** ***** ***** */ /* 此部分为注册至C中的lua通用函数, 实现在lua_plugin_cfunc.c中 */ void *lpm_ctx_new_func(struct session *sess, void *plugin_env); void lpm_ctx_free_func(struct session *sess, void *sess_ctx, void *plugin_env); void lpm_message_free_func(struct session *sess, void *msg, void *msg_free_arg); void lpm_on_session_msg_func(struct session *sess, int topic_id, const void *msg, void *sess_ctx, void *plugin_env); /* ***** ***** ***** ***** ***** ***** */ /* lua代码块相关操作, 实现在lua_plugin_chunk.c中 */ /* 执行一段lua代码块, 执行之前需要先在lua中生成一个引用ID */ int lua_chunk_execute(lua_State *state, int ref_id, int pcount, struct lua_cdata *params, int rcount, struct lua_cdata *returns); /* ***** ***** ***** ***** ***** ***** */ /* TODO:统计插件的运行情况, 暂时没想好怎么用 */ /* 记录一个插件的运行状态 */ struct lua_plugin_statistics { /* ctx_new函数调用成功的次数 */ int new_success_count; /* ctx_new函数调用失败的次数 */ int new_failed_count; /* ctx_free函数调用成功的次数 */ int free_success_count; /* ctx_free函数调用失败的次数 */ int free_failed_count; }; /* 状态机相关的一些数据结构及操作, 实现在lua_plugin_manage.c中 */ extern struct lua_plugin_manage_schema *global_schema; /* 保存插件的运行情况, 运行次数等信息 */ /* 二维数组修改为一维数组, 方便使用偏移快速查找 */ extern struct lua_plugin_statistics *global_plugin_statistics; /* 最大插件编号 */ extern int global_max_plugin_id; #define LUA_MQ_ENV_DEFAULT_KEY "__mqenv_pointer" #define LUA_MQ_TOPIC_ID_KEY "topic_id" /* 保存lua插件注册的消息队列信息 */ struct lua_plugin_mq { /* 消息队列ID, 消息队列可能是订阅得到或者创建得到, 此处保存对应topic信息 */ int topic_id; /* 如果是订阅的topic必须包含处理函数 */ int onmessage_ref; }; /* 保存Lua插件信息 */ struct lua_plugin { /* 注册完成后得到的插件ID */ int plugin_id; /* context_new函数在状态机中的引用值 */ int ctx_new_ref; /* context_free函数在状态机中的引用值 */ int ctx_free_ref; /* 该插件中订阅的topic */ UT_array *sub_topic_array; }; void lua_plugin_destory(void *elt); /* 根据ID号在整个schema中进行遍历 */ struct lua_plugin *search_plugin_by_id(int plugin_id); #define MODEL_MARK_INIT_DONE 0x0001 #define MODEL_MARK_LOAD_DONE 0x0002 #define LUA_PLUGIN_ENV_DEFAULT_KEY "__penv_pointer" /* 加载的lua模块, 一个lua模块一般来说对应一个lua文件, 与C插件管理中的so相同 */ struct lua_model { /* 该模块注册后的插件列表 */ UT_array *plugin_array; /* 该模块load函数在状态机中的引用值 */ int load_ref; /* 该模块unload函数在状态机中的引用值 */ int unload_ref; /* 该模块创建出的plugin_env数据在状态机中的引用值 */ int private_env_ref; /* 初始化过程中的标记 */ unsigned short model_mark; /* 加载的插件数量 */ unsigned short plugin_count; }; /* 在一个状态机中初始化一个模块 */ int thread_state_load_specific(lua_State *state, struct lua_model *model, struct lua_config_specific *specific); /* 由lua创建的topic结构, 该结构保存在schema中 */ struct lua_message_mq { /* 消息队列ID, 消息队列可能是订阅得到或者创建得到, 此处保存对应topic信息 */ int topic_id; /* 如果是新创建的topic, 必须包含释放函数 */ int freemessage_ref; /* 创建一个消息处理私有数据, 对应session_mq中的msg_free_arg */ int mq_private_ref; // char * topic_name; }; /* 根据topic_id在schema中查找一个message对应的函数 */ struct lua_message_mq *search_message_mq_by_id(int topic_id); #define LUA_STATE_THREAD_ID_KEY "__thread_id" struct lua_plugin_manage_schema { struct stellar *st; /* 创建的状态机数量, 状态机数量与线程的个数相同 */ int state_count; /* 插入模块的数量, 模块的数量与specific的数量相同 */ int model_count; /* 注册的消息队列的数量 */ int mq_count; /* 所有模块中注册的插件总数量 */ int plugin_count; /* 线程状态机 */ lua_State **thread_state; /* 所有插入的模块 */ struct lua_model **model; /* TODO: 创建的所有message topic id理论上应该是连续的, 可以考虑用hash数组, 寻址能更快 */ UT_array *message_mq_array; }; #ifdef LUAPLUGIN_BASIC_UNITTEST void debug_lua_state_stack(lua_State *state, int mod, const char *message); void debug_lua_plugin_manage_schema(struct lua_plugin_manage_schema *schema); #endif #endif