# LuaPluginManage - [LuaPluginManage](#luapluginmanage) - [总述](#总述) - [整体功能](#整体功能) - [状态机](#状态机) - [函数](#函数) - [数据](#数据) - [插件](#插件) - [数据转换\*](#数据转换) - [接口](#接口) - [外部接口](#外部接口) - [内部接口](#内部接口) - [C注册函数](#c注册函数) - [Lua注册函数](#lua注册函数) - [总体设计](#总体设计) - [初始化](#初始化) - [退出](#退出) - [功能模块](#功能模块) - [函数及全局变量注册](#函数及全局变量注册) - [数据结构](#数据结构) - [函数](#函数-1) - [Lua与C数据转换](#lua与c数据转换) - [数据结构](#数据结构-1) - [状态机管理](#状态机管理) - [数据结构](#数据结构-2) - [函数](#函数-2) - [插件管理](#插件管理) - [数据结构](#数据结构-3) - [函数](#函数-3) - [脚本管理](#脚本管理) - [数据结构](#数据结构-4) - [函数](#函数-4) - [配置管理](#配置管理) - [数据结构](#数据结构-5) - [函数](#函数-5) - [C注册函数](#c注册函数-1) - [Lua注册函数](#lua注册函数-1) - [安全性](#安全性) - [重名的情况](#重名的情况) ## 总述 ### 整体功能 实现Lua插件的管理功能,功能整体包括如下部分: 1. 状态机的管理及维护:功能包括状态机的创建、删除、初始化、获取运行状态等; 2. 注册函数的管理功能:C将函数注册至Lua环境中,并可在Lua中进行调用;提供函数检查功能,为保证调用过程安全可靠,在传入过程中对安全状态进行检查; 3. 数据的管理功能:C将数据注册至Lua环境中,如全局使用的字符串、版本信息、运行环境等; 4. 插件的管理功能:将一个Lua插件加载至插件管理中,与C插件一致,将插件注册至stellar-plugin_manage及session_plugin_manage中; 5. 数据转化:可以将Lua中的数据与C中的数据进行安全的数据转换,用于在C中暂存Lua中保存的数据,并可以对该数据进行修改、维护; ### 状态机 状态机用于保存Lua运行虚拟机在运行过程中所有的环境表、注册表、堆栈、数据段、上下文等数据。Lua状态机是Lua运行过程中对外暴露的唯一数据结构,其余数据结构均已经在Lua内部隐藏,所有对Lua的操作均需要通过改变状态机的状态来实现。一个Lua状态机可以理解为一个Lua的线程,该状态机和C的线程一样,拥有独立的内存空间。 创建:安全的新建一个空的状态机 删除:释放一个状态机,删除其内部所有数据占用的内存并释放一个状态机实例 初始化:状态机初始化过程中加载运行时必要的Lua组件,并根据配置文件将各个Lua插件加载在状态机中 获取运行错误*:获取状态机运行过程中的错误 获取运行状态*:获取状态机运行状态,包括运行时间、加载插件数量、运行耗时等 ### 函数 向Lua内部注册一个函数,可供Lua程序在运行过程中调用。如向lua中传入数据结构时,可通过注册函数的方式向Lua提供数据的获取方法。或通过注册函数向Lua提供其他模块的外部接口。 注册:向Lua状态机中注册一个格式要求符合lpm_cbinding_function类型的函数,该函数可供Lua脚本调用 删除:从Lua状态机中删除一个C注册的函数 安全检查*:提供一个标准化的定义方式,在Lua插件编写过程中可通过该定义方式得知运行过程中存在的注册函数名称、参数类型等,防止在调用过程中出错;在Lua脚本加载前对其内部调用的C函数进行安全性检查,检查如传入参数个数、参数类型等 自动化函数翻译*:通过特定方法能够自动将一些C函数转换为Lua的注册函数格式 ### 数据 向Lua内部注册一个函数,可供Lua脚本在运行过程中使用。如向Lua中传入运行程序版本、运行环境信息、系统信息等。 注册:向状态机中注册一个全局变量,变量类型可以为数字、字符串;如需注册一个数据结构需同时注册该数据结构的成员获取方法 删除:从状态机中删除一个全局变量 数据范式化*:将一段Lua数据范式化为一段json或其他特定格式,方便输出或在其他程序中调用 ### 插件 插件为一整个Lua功能模块,与C中的插件含义相同。 插件加载:将一个插件加载至插件管理器中 插件卸载:从插件管理器中卸载一个插件 会话插件加载:将一个会话插件加载至session_plugin_manage中 会话插件卸载:从session_plugin_manage中删除一个会话插件 注册会话插件:此功能仅在lua端暴露,不在C接口中。在插件加载过程中可注册会话插件 订阅会话消息:此功能仅在lua端暴露,不在C接口中。在插件加载过程中可订阅一个会话中特定id的会话消息 处理会话消息:处理会话过程中的数据 ### 数据转换* 将Lua数据翻译为C中可读可写可持久化保存的数据,也可以将一个由Lua转换为C数据得到的序列化数据转换为Lua中的数据结构 Lua转换至C:将Lua数据序列化成为C中一段内存数据 C转换至Lua:将C中数据反序列化为Lua中一段数据 ## 接口 ### 外部接口 | 函数名称 | 参数 | 返回值 | 功能 | | --- | --- | --- | --- | | lua_plugin_manage_init | struct stellar * st
const char * config_file_path | 创建的lua插件管理器实例指针 | 根据配置文件创建一个lua插件管理器实例,并在函数内完成配置加载及初始化过程 | lua_plugin_manage_exit | struct lua_plugin_manage_schema * lua_plug_mgr | void | 清理一个lua插件管理器实例,清除内部所有数据 ### 内部接口 | 函数名称 | 参数 | 返回值 | 功能 | | --- | --- | --- | --- | | lua_cbinding_functions | lua_State *state | 0表示成功,其他表示失败,返回值大于0时表示注册失败的元素个数 | 向lua状态机中注册函数,函数定义在全局变量lua_bind_functions中 | lua_cbinding_datas | lua_State *state | 0表示成功,其他表示失败,返回值大于0时表示注册失败的元素个数 | 向lua状态机中注册数据,所有注册数据在状态机中作为全局变量存在,所有注册数据保存在lua_bind_datas全局变量中 | lua_cdata_push_stack | lua_State *state
struct lua_cdata *cdata | 0表示成功,其他表示失败 | 将一个data结构入栈 | lua_cdata_pop_stack | lua_State *state
struct lua_cdata *cdata | 0表示成功,其他表示失败 | 从栈中弹出一个元素,并保存在data结构中,类型限制见函数实现部分 | lua_cdata_destory | struct lua_cdata *cdata | void | 销毁一个data结构,只有string类型需要调用此函数,其他的情况直接释放即可 | lua_context_new | lua_State *state | 创建出的context实例 | 在状态机中生成一个context | lua_context_push_stack | struct lua_context *context | 0表示成功,其他表示失败 | 将一个context入栈 | lua_context_free | struct lua_context *context | void | 释放一个context ### C注册函数 | 函数名称 | 参数 | 返回值 | 功能 | | --- | --- | --- | --- | | lpm_ctx_new_func | struct session *sess
void *plugin_env | 在该session中创建的context实例 | session创建时调用 | lpm_ctx_free_func | struct session *sess
void *sess_ctx
void *plugin_env | void | session销毁时调用 ### Lua注册函数 | 函数名称 | 参数 | 返回值 | 功能 | | --- | --- | --- | --- | | lua_plugin_manage_session_regist | lua_State * state | 0无需处理返回值,1需处理返回值 | lua中调用该函数注册插件,注册完成后调用方式为调用plugin_manage.register ## 总体设计 ### 初始化 ```mermaid --- title: lua_plugin_manage_init --- flowchart TD; start(["开始"]); createschema["calloc新的schema"]; loadconfig["从配置文件中加载配置"]; configcheck{"检查返回值"}; threadcount["获取线程数量"]; loadthread["每个线程中创建新的状态机"]; freeschema["清理schema"]; finish(["结束"]); start --> createschema createschema --> loadconfig loadconfig --> configcheck configcheck --> |<0|freeschema configcheck --> |>=0|threadcount; threadcount --> loadthread loadthread --> finish freeschema --> finish ``` 1. 创建一个新的schema实例 2. 将配置文件中配置信息加载至schema实例中暂存 3. 在schema中按照线程数量创建状态机,并完成初始化 ### 退出 ```mermaid --- title: lua_plugin_manage_exit --- flowchart TD; start(["开始"]); freespecific["依次清理加载的配置信息"]; freethread["依次关闭线程中的状态机"]; freeschema["清理schema"]; finish(["结束"]); start --> freespecific freespecific --> freethread freethread --> freeschema freeschema --> finish ``` ## 功能模块 ### 函数及全局变量注册 1. 如果传入参数中包含space_name,则将函数在Lua中注册为space_name.func_name形式 2. 如果参数中没有space_name,则将函数在Lua中注册为func_name形式 3. 删除过程中只是将该函数的指针在Lua中修改为nil,并不会真正删除,需要等Lua下一次自动垃圾回收完成后才会真正完成删除 4. 数据管理与函数管理流程相同,不同之处在于函数删除时会检查Lua中数据类型是否为function,但是在全局变量删除时不会做该校验 #### 数据结构 ```C /* 需要注册至lua中的函数 */ struct lua_binding_function { /* 注册函数原型 */ lua_CFunction binding_function; /* 注册至lua中的函数名称 */ char *binding_function_name; /* 注册至lua中的命名空间名称 */ char *binding_function_space_name; }; /* 需要注册至lua状态机中的数据 */ struct lua_binding_data { /* 注册的数据类型 */ enum DATATYPE binding_data_type; /* 注册数数据值 */ char *binding_data_value; /* 注册的数据名称 */ char *binding_data_name; /* 注册至lua中的命名空间名称 */ char *binding_data_space_name; }; ``` #### 函数 | 函数名称 | 参数 | 返回值 | 功能 | | --- | --- | --- | --- | | lua_cbinding_function | lua_State *state
lua_CFunction bind_function
const char *function_name
const char *space_name | 0表示成功,其他表示失败 | 向lua状态机中注册一个函数 | lua_cbinding_function_remove | lua_State *state
const char *function_name
const char *space_name | 0表示成功,其他表示失败 | 从状态机中移除一个已经完成注册的函数 | lua_cbinding_data | lua_State *state
struct lua_binding_data *data | 0表示成功,其他表示失败 | 向lua状态机中注册一段数据,该数据在状态机中作为全局变量存在 | lua_cbinding_data_remove | lua_State *state
const char *data_name
const char *space_name | 0表示成功,其他表示失败 | 从状态机中删除一个已经注册的数据,从状态机中删除该全局变量的引用 ```mermaid --- title: 函数注册 lua_cbinding_function --- flowchart TD; start(["开始"]); paramcheck{"参数检查"}; checkspace{"参数中是否有space_name"}; getspace["状态机中获取space_name"]; spacecheck{"space_name是否存在"}; spacetablecheck{"space_name类型检查,是否为table类型"}; createspace["创建space_name"]; funccheck{"func_name是否存在"}; createfunc["注册函数"]; addfunc["func_name加入管理列表中"] finish(["结束"]); start --> paramcheck paramcheck --> |Y|checkspace paramcheck --> |N|finish checkspace --> |Y|getspace checkspace --> |N|funccheck getspace --> spacecheck spacecheck --> |Y|spacetablecheck spacecheck --> |N|createspace createspace --> funccheck spacetablecheck --> |N|finish spacetablecheck --> |Y|funccheck funccheck --> |N|createfunc funccheck --> |Y|finish createfunc --> addfunc addfunc --> finish ``` ```mermaid --- title: 函数卸载 lua_cbinding_function_remove --- flowchart TD; start(["开始"]); paramcheck{"参数检查"}; funccheck{"func_name是否在管理列表中"} checkspace{"参数中是否有space_name"}; spacecount{"space_name中是否仅有一个元素"} spacedelete["删除space_name"] funcdelete["删除func_name"] functype{"类型是否为LUA_TFUNCTION"} deletefunc["管理列表中删除func_name"] finish(["结束"]); start --> paramcheck paramcheck --> |Y|funccheck paramcheck --> |N|finish funccheck --> |N|finish funccheck --> |Y|checkspace checkspace --> |Y|spacecount checkspace --> |N|funcdelete spacecount --> |Y|spacedelete spacedelete --> funcdelete spacecount --> |N|funcdelete funcdelete --> functype functype --> |Y|deletefunc functype --> |N|finish deletefunc --> finish ``` ```mermaid --- title: 数据注册 lua_cbinding_data --- flowchart TD; start(["开始"]); paramcheck{"参数检查"}; checkspace{"参数中是否有space_name"}; getspace["状态机中获取space_name"]; spacecheck{"space_name是否存在"}; spacetablecheck{"space_name类型检查,是否为table类型"}; createspace["创建space_name"]; datacheck{"data_name是否存在"}; createdata["注册数据"]; adddata["data_name加入管理列表中"] finish(["结束"]); start --> paramcheck paramcheck --> |Y|checkspace paramcheck --> |N|finish checkspace --> |Y|getspace checkspace --> |N|funccheck getspace --> spacecheck spacecheck --> |Y|spacetablecheck spacecheck --> |N|createspace createspace --> funccheck spacetablecheck --> |N|finish spacetablecheck --> |Y|datacheck datacheck --> |N|createdata datacheck --> |Y|finish createdata --> adddata adddata --> finish ``` ```mermaid --- title: 数据卸载 lua_cbinding_data_remove --- flowchart TD; start(["开始"]); paramcheck{"参数检查"}; datacheck{"data_name是否在管理列表中"} checkspace{"参数中是否有space_name"}; spacecount{"space_name中是否仅有一个元素"} spacedelete["删除space_name"] datadelete["删除data_name"] deletedata["管理列表中删除data_name"] finish(["结束"]); start --> paramcheck paramcheck --> |Y|datacheck paramcheck --> |N|finish datacheck --> |N|finish datacheck --> |Y|checkspace checkspace --> |Y|spacecount checkspace --> |N|datadelete spacecount --> |Y|spacedelete spacedelete --> datadelete spacecount --> |N|datadelete datadelete --> deletedata deletedata --> finish ``` ### Lua与C数据转换 1. 根据不同的数据类型调用不同的Lua原生函数进行出入栈操作; 2. context本质是一个预分配并完成引用关联的lua-table,在lua状态机中可以不受限制的使用; 3. 后续可能会根据数据类型进行lua和C的内存转换,当前不支持内存共享使用; 4. lua元素在出栈过程中,table类型的变量只创建引用并返回引用编号; #### 数据结构 ```C 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; }; }; struct lua_context { lua_State *context_state; int context_ref_id; }; ``` ### 状态机管理 1. 每个线程中创建一个状态机,将该线程中加载的所有插件全部注册在该状态机中; #### 数据结构 ```C struct lua_thread_state { /* 创建状态机的线程ID */ int thread_id; /* 已经插入的插件数量 */ int thread_plugin_count; /* 生成的状态机 */ lua_State *thread_state; // struct lua_pl_state_private * lua_thread_private; /* 该线程状态机中注册的插件列表 */ UT_array *thread_env_array; /* 状态机的启动时间 */ time_t thread_begin_time; }; ``` #### 函数 | 函数名称 | 参数 | 返回值 | 功能 | | --- | --- | --- | --- | | lua_plugin_manage_state_load | struct lua_plugin_manage_schema *schema
int thread_count | >=0状态机创建成功的数量,<0加载失败 | 在schema中根据线程数量创建多个状态机并完成状态机的初始化 | thread_state_instance_init | struct lua_thread_state *thread_state
int state_id | 0表示成功,其他表示失败 | 初始化一个状态机的实例,包括创建lua_State、绑定函数、绑定全局变量等 | thread_state_instance_destory | void * elt | void | 销毁一个状态机,清空状态机中所有注册的插件并关闭状态机 | thread_state_instance_load | struct lua_thread_state *thread_state
struct lua_plugin_manage_schema *schema | 0表示成功,其他表示失败 | 根据配置数量创建plugin_env,并依次调用插件加载函数完成插件的初始化 ```mermaid --- title: lua_plugin_manage_state_load --- flowchart TD; start(["开始"]); paramcheck{"参数检查"}; initstatearray["初始化schema中状态机队列"]; checkstatecount{"状态机数量与线程数量一致"}; createstate["创建新的状态机"]; insertstate["创建完成的新状态机插入至schema队列中"]; checkstateinit{"状态机全部完成初始化"}; initstate["初始化状态机"]; finish(["结束"]); start --> paramcheck paramcheck --> |Y|initstatearray paramcheck --> |N|finish initstatearray --> checkstatecount; checkstatecount --> |Y|checkstateinit; checkstatecount --> |N|createstate; createstate --> insertstate; insertstate --> checkstatecount; checkstateinit --> |Y|finish checkstateinit --> |N|initstate; initstate --> checkstateinit; ``` ```mermaid --- title: thread_state_instance_init --- flowchart TD; start(["开始"]); paramcheck{"参数检查"}; newstate["创建状态机"]; bindfunc["绑定函数"]; binddata["绑定全局变量"]; finish(["结束"]); start --> paramcheck paramcheck --> |Y|newstate praamcheck --> |N|finish newstate --> bindfunc bindfunc --> binddata binddata --> finish ``` ```mermaid --- title: thread_state_instance_destory --- flowchart TD; start(["开始"]); paramcheck{"参数检查"}; unloadplugin["依次卸载所有插件"]; closestate["关闭状态机"]; finish(["结束"]); start --> paramcheck paramcheck --> |Y|unloadplugin paramcheck --> |N|finish unloadplugin --> closestate closestate --> finish ``` ```mermaid --- title: thread_state_instance_load --- flowchart TD; start(["开始"]); paramcheck{"参数检查"}; plugincount{"完成所有插件初始化"}; initpluginenv["初始化插件环境变量"]; loadcount{"完成所有插件加载"}; loadpluginenv["调用插件加载函数"]; finish(["结束"]); start --> paramcheck paramcheck --> |Y|plugincount paramcheck --> |N|finish plugincount --> |N|initpluginenv plugincount --> |Y|loadcount initpluginenv --> plugincount loadcount --> |Y|finish loadcount --> |N|loadpluginenv loadpluginenv --> loadcount ``` ### 插件管理 整体原则:每一个Lua插件在stellar的插件管理器中为一个单独的插件,插件在C插件管理器中共用同一个函数,在调用lua插件函数时根据插件的编号及注册使用的plugin_env查找插件的实际lua函数并完成调用; #### 数据结构 ```C /* 每一个插件的函数信息 */ struct lua_session_plugin { /* 插件注册完成后得到的插件编号 */ int plugin_id; /* ctx_new函数 */ struct lua_script plugin_ctx_new_script; /* ctx_free函数 */ struct lua_script plugin_ctx_free_script; /* on_message函数 */ // struct lua_script plugin_on_message_script; }; struct lua_plugin_env { /* 插件注册的状态机 */ lua_State *plugin_env_state; /* 该环境数据中包含的所有插件列表 */ UT_array *plugin_env_plugin_array; /* 加载插件的lua函数 */ struct lua_script plugin_env_load_func; /* 卸载插件的lua函数 */ struct lua_script plugin_env_unload_func; /* 该插件运行环境数据的名称, 在创建时同时在状态机中创建该名称的命名空间 */ /* 插件申请lua内的全局变量可以保存在该命名空间内, 防止被其他内容覆盖 */ // char *plugin_env_name; /* 在lua中保存运行数据的引用ID */ int plugin_env_ref_id; /* plugin_env */ }; ``` #### 函数 | 函数名称 | 参数 | 返回值 | 功能 | | --- | --- | --- | --- | | session_plugin_instance_init | struct lua_session_plugin *session_plugin
lua_State *state
int plugin_id
int new_refid
int free_refid | 0表示成功,其他表示失败 | 初始化一个运行在会话中的插件 | session_plugin_instance_destory | void *elt | void | 销毁一个运行在会话中的插件 | plugin_env_instance_init | struct lua_plugin_env *plugin_env
lua_State *state
struct lua_config_specific *specific | 0表示成功,其他表示失败 | 根据specific配置初始化一个plugin_env,在此过程中仅将函数加载完成,并未进行load函数调用,load函数在状态机加载完成所有插件后统一调用 | plugin_env_instance_destory | void *elt | void | 销毁一个插件运行环境变量 ```mermaid --- title: session_plugin_instance_init --- flowchart TD; start(["开始"]); paramcheck{"参数检查"}; init["根据引用id分别初始化ctx_new及ctx_free"]; finish(["结束"]); start --> paramcheck paramcheck --> |Y|init paramcheck --> |N|finish init --> finish ``` ```mermaid --- title: session_plugin_instance_destory --- flowchart TD; start(["开始"]); paramcheck{"参数检查"}; delete["分别删除状态机中的引用"]; finish(["结束"]); start --> paramcheck paramcheck --> |Y|delete paramcheck --> |N|finish delete --> finish ``` ```mermaid --- title: plugin_env_instance_init --- flowchart TD; start(["开始"]); paramcheck{"参数检查"}; init["根据名称分别初始化ctx_new及ctx_free"]; createenv["创建该插件pluginenv"]; finish(["结束"]); start --> paramcheck paramcheck --> |Y|init paramcheck --> |N|finish init --> createenv createenv --> finish ``` ```mermaid --- title: plugin_env_instance_destory --- flowchart TD; start(["开始"]); paramcheck{"参数检查"}; unload["调用unload函数"]; unregist["卸载所有在该env中的插件"]; deletefunc["删除load及unload函数在状态机中的引用"]; deleteenv["删除创建的plugin_env"]; finish(["结束"]); start --> paramcheck paramcheck --> |Y|unload paramcheck --> |N|finish unload --> unregist unregist --> deletefunc deletefunc --> deleteenv deleteenv --> finish ``` ### 脚本管理 #### 数据结构 ```C /* 一个可以运行的lua函数 */ /* 加载过程中生成引用, 后续使用过程中使用引用编号进行调用 */ struct lua_script { /* 该函数注册时注册至的状态机, 运行过程中使用该状态机调用函数 */ lua_State *script_state; /* 该函数的引用ID */ int script_ref_id; /* 运行成功次数 */ int script_run_success; /* 运行失败次数 */ int script_run_failed; /* 最后一次运行开始时间 */ clock_t script_last_ms_start; /* 最后一次运行结束时间 */ clock_t script_last_ms_end; /* 运行总用时 */ clock_t script_total_ms; }; ``` #### 函数 | 函数名称 | 参数 | 返回值 | 功能 | | --- | --- | --- | --- | | script_instance_init_byname | struct lua_script *script
lua_State *state
const char *filepath
const char *funcname | 0表示成功,其他表示失败 | 根据文件名及函数名称从lua脚本中初始化一个脚本 | script_instance_init_byrefid | struct lua_script *script
lua_State *state
int ref_id | 0表示成功,其他表示失败 | 根据一个已经在状态机中生成引用的引用编号初始化一个脚本 | script_instance_clean | struct lua_script *script | void | 清理一个脚本实例 | script_execute | struct lua_script *script
int pcount
struct lua_cdata *param
int rmaxcount
struct lua_cdata *rvalue | 0表示成功,其他表示失败 | 运行一个脚本 ```mermaid --- title: script_instance_init_byname --- flowchart TD; start(["开始"]); paramcheck{"参数检查"}; fileload["加载lua文件"]; findfunc["在文件中寻找对应函数"]; createref["创建引用"]; initscript["初始化脚本实例"]; finish(["结束"]); start --> paramcheck paramcheck --> |Y|fileload paramcheck --> |N|finish fileload --> findfunc findfunc --> createref createref --> initscript initscript --> finish ``` ```mermaid --- title: script_instance_init_byrefid --- flowchart TD; start(["开始"]); paramcheck{"参数检查"}; initscript["初始化脚本实例"]; finish(["结束"]); start --> paramcheck paramcheck --> |Y|initscript paramcheck --> |N|finish initscript --> finish ``` ```mermaid --- title: script_instance_clean --- flowchart TD; start(["开始"]); paramcheck{"参数检查"}; delete["状态机中删除该引用"]; finish(["结束"]); start --> paramcheck paramcheck --> |Y|delete paramcheck --> |N|finish delete --> finish ``` ```mermaid --- title: script_execute --- flowchart TD; start(["开始"]); paramcheck{"参数检查"}; getref["根据refid加载函数"]; pushparam["传入参数"]; logtime["记录时间"]; execute["调用函数"]; popreturn["取出参数"]; finish(["结束"]); start --> paramcheck paramcheck --> |Y|getref paramcheck --> |N|finish getref --> pushparam pushparam --> logtime logtime --> execute execute --> popreturn popreturn --> finish ``` ### 配置管理 #### 数据结构 ```C /* 根据配置文件加载过程中保存插件信息的临时结构 */ struct lua_config_specific { /* 插件需要使用的文件名 */ char *config_specific_file; /* 插件名称 */ // char *config_specific_name; /* 加载插件需要调用的函数名称 */ char *config_specific_load_func; /* 卸载插件需要调用的函数名称 */ char *config_specific_unload_func; }; ``` #### 函数 | 函数名称 | 参数 | 返回值 | 功能 | | --- | --- | --- | --- | | specific_instance_copy | void *dst
const void *src | void | 拷贝一个配置结构实例,拷贝过程为深拷贝 | specific_instance_destory | void *elt | void | 销毁一个配置结构实例,释放内部元素占用的内存 ```mermaid --- title: specific_instance_copy --- flowchart TD; start(["开始"]); copy["依次拷贝内部成员"] finish(["结束"]); start --> copy copy --> finish ``` ```mermaid --- title: specific_instance_destory --- flowchart TD; start(["开始"]); free["释放内部成员"] finish(["结束"]); start --> free free --> finish ``` ### C注册函数 | 函数名称 | 参数 | 返回值 | 功能 | | --- | --- | --- | --- | | lpm_ctx_new_func | struct session *sess
void *plugin_env | 在该session中创建的context实例 | session创建时调用 | lpm_ctx_free_func | struct session *sess
void *sess_ctx
void *plugin_env | void | session销毁时调用 ```mermaid --- title: lpm_ctx_new_func --- flowchart TD; start(["开始"]); paramcheck{"参数检查"}; getpluginid["获取pluginid"]; searchid["在pluginenv中查找该pluginid"]; idcheck{"找到该id对应的插件"}; newcontext["创建新的context"]; execute["调用该插件实际的lua函数"]; finish(["结束"]); start --> paramcheck paramcheck --> |Y|getpluginid paramcheck --> |N|finish getpluginid --> searchid searchid --> idcheck idcheck --> |Y|newcontext idcheck --> |N|finish newcontext --> execute execute --> finish ``` ```mermaid --- title: lpm_ctx_free_func --- flowchart TD; start(["开始"]); paramcheck{"参数检查"}; getpluginid["获取pluginid"]; searchid["在pluginenv中查找该pluginid"]; idcheck{"找到该id对应的插件"}; execute["调用该插件实际的lua函数"]; finish(["结束"]); start --> paramcheck paramcheck --> |Y|getpluginid paramcheck --> |N|finish getpluginid --> searchid searchid --> idcheck idcheck --> |Y|execute idcheck --> |N|finish execute --> finish ``` ### Lua注册函数 | 函数名称 | 参数 | 返回值 | 功能 | | --- | --- | --- | --- | | lua_plugin_manage_session_regist | lua_State * state | 0无需处理返回值,1需处理返回值 | lua中调用该函数注册插件,注册完成后调用方式为调用plugin_manage.register ```mermaid --- title: lua_plugin_manage_session_regist --- flowchart TD; start(["开始"]); paramcheck{"参数数量检查"}; paramtypecheck{"参数类型检查"}; getpluginenv["获取plugin_env"]; getfreeref["将ctx_free函数创建引用"]; getnewref["将ctx_new函数创建引用"]; getstellar["获取stellar"]; regist["调用stellar_session_plugin_register"]; insertplugin["将插件id与函数对应关系插入plugin_env"]; returnid["返回pluginid"]; finish(["结束"]); start --> paramcheck paramcheck --> |Y|paramtypecheck paramcheck --> |N|finish paramtypecheck --> |Y|getpluginenv paramtypecheck --> |N|finish getpluginenv --> getfreeref getfreeref --> getnewref getnewref --> getstellar getstellar --> regist regist --> insertplugin insertplugin --> returnid returnid --> finish ``` ## 安全性 ### 重名的情况 在Lua中并不会校验是否存在重名变量、重名函数等,出现重名的变量或函数会直接将旧的数据覆盖。 自定义数据冲突 自定义数据如果出现重名的情况,以先注册的为准,后续的函数或数据在注册中会报错 插件数据冲突 插件中的函数在初始化过程中会生成引用ID,在Lua中被强引用的数据即使出现重名情况也不会被删除覆盖,调用过程中根据引用ID进行调用,函数重名不会产生影响 插件中的全局变量在初始化过程中可以通过提供给Lua的接口将全局变量注册成为一个状态机中的全局变量,该全局变量与自定义数据全局变量的维护及保存逻辑一致,后续注册插件过程中如果出现与当前全局变量冲突的数据会导致插件注册失败 自定义数据与插件数据冲突 自定义数据优先级高于插件数据,插件数据注册过程中如果与已存在的数据冲突会注册失败