diff --git a/docs/summaryDesign.md b/docs/summaryDesign.md index 9abbe62..c3169f0 100644 --- a/docs/summaryDesign.md +++ b/docs/summaryDesign.md @@ -1,4 +1,43 @@ # 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插件的管理功能,功能整体包括如下部分: @@ -34,93 +73,135 @@ 注册会话插件:此功能仅在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 +title: lua_plugin_manage_init --- flowchart TD; - start(["开始"]); - create["创建状态机"]; - bindfunc["绑定函数"]; - binddata["绑定数据"]; - init["读取配置文件并获取插件"] - load["加载插件"]; + createschema["calloc新的schema"]; + loadconfig["从配置文件中加载配置"]; + configcheck{"检查返回值"}; + threadcount["获取线程数量"]; + loadthread["每个线程中创建新的状态机"]; + freeschema["清理schema"]; finish(["结束"]); - start --> create - create --> bindfunc - bindfunc --> binddata - binddata --> init - init --> load - load --> finish + start --> createschema + createschema --> loadconfig + loadconfig --> configcheck + configcheck --> |<0|freeschema + configcheck --> |>=0|threadcount; + threadcount --> loadthread + loadthread --> finish + freeschema --> finish ``` -1. 创建一个状态机实例,后续所有的运行全部依赖于该状态机; -2. 将自定义的C函数绑定至状态机中,功能详见[C函数管理](#函数管理); -3. 将一些自定义的数据注册至状态机中,功能详见[数据管理](#数据管理); -4. 进行初始化,根据一个配置文件,加载文件中声明需要加载的所有插件。此时,插件仅是在将必要的信息暂存在状态机中; -5. 加载插件,依次调用每一个插件中的load函数,功能详见[插件管理](#插件管理); -### 运行 -运行过程中所有调用均通过现在的stellar中的plugin_manage于session_plugin_manage进行调用,运行过程中不会主动运行。 +1. 创建一个新的schema实例 +2. 将配置文件中配置信息加载至schema实例中暂存 +3. 在schema中按照线程数量创建状态机,并完成初始化 + ### 退出 ```mermaid --- -title: lua plugin manage exit +title: lua_plugin_manage_exit --- flowchart TD; - start(["开始"]); - unload["依次卸载插件"]; - clean["关闭状态机"]; + freespecific["依次清理加载的配置信息"]; + freethread["依次关闭线程中的状态机"]; + freeschema["清理schema"]; finish(["结束"]); - start --> unload - unload --> clean - clean --> finish + start --> freespecific + freespecific --> freethread + freethread --> freeschema + freeschema --> finish ``` -1. 依次调用插件管理中每一个插件的unload函数,功能详见[插件管理](#插件管理); -2. 关闭状态机并释放占用的资源; -## 外部接口 -C端函数: -| 函数名称 | 参数 | 返回值 | 功能 | -| --- | --- | --- | --- | -| lpm_state_instance_create | void | 创建完成的状态机指针,NULL为创建失败 | 创建一个状态机实例。 -| lpm_state_instance_init | struct stellar * st
struct lpm_state * state
const char * filename | 0表示成功,其他表示失败 | 根据一个配置文件对一个状态机实例进行初始化 -| lpm_state_instance_free | struct lpm_state * | int | 释放一个状态机实实例,释放其占用内存 -| lpm_cdata_clean | struct lpm_cdata * | void | 清理一个struct lpm_cdata实例内所有数据,删除其内部数据占用的内存 -| lpm_cbinding_get_params_count | struct lpm_state * state | 传入的参数数量,负数为获取失败 | 该函数用于C函数获取lua在调用C函数时传入的参数个数 -| lpm_cbinding_get_params | struct lpm_state * state
int index
struct lpm_cdata * data | 0表示成功,其他表示失败 | 获取传入C中的具体参数内容,index表示参数下标,data为具体参数内容 -| lpm_cbinding_push_return | struct lpm_state * state
int count
struct lpm_cdata * data | 0表示成功,其他表示失败 | 将C函数运行结果传入Lua中,count表示传入的数据数量,data为具体数据 -| lpm_cbinding_function_register | struct lpm_state * state
lpm_cbinding_function function
const char * func_name
const char * space_name | 0表示成功,其他表示失败 | 将一个C函数注册至Lua中,在Lua中调用方式为space_name.func_name的形式,如果space_name为空时可通过func_name进行调用 -| lpm_cbinding_function_remove | struct lpm_state * state
const char * func_name
const char * space_name | 0表示成功,其他表示失败 | 从Lua状态机中删除一个函数 -| lpm_cdata_register | struct lpm_state * state
struct lpm_cdata * data
const char * data_name
const char * space_name | 0表示成功,其他表示失败 | 将一个C数据传入Lua中,并可作为Lua的全局变量使用,在Lua中使用方式为space_name.data_name,当space_name为空时可直接使用data_name获取该变量的值 -| lpm_cdata_remove | struct lpm_state * state
const char * data_name
const char * space_name | 0表示成功,其他表示失败 | 从Lua状态机中删除一个全局变量 -| lpm_plugin_load | struct stellar * st | 返回插件的私有运行数据 | 提供至stellar中plugin manage的插件注册函数 -| lpm_plugin_unload | void * plugin_env | void | 提供至stellar中plugin manage的插件卸载函数 -| lpm_ctx_new_func | struct session * sess
void * plugin_env | 在该session上插件的私有数据 | 提供至stellar中session plugin manage的函数,在会话创建过程中调用,创建该会话中的插件私有数据 -| lpm_ctx_free_func | struct session * sess
void * sess_ctx
void * plugin_env | void | 提供至stellar中session plugin manage的函数,在会话结束时调用,删除在会话上的插件私有数据 -| lpm_on_session_msg_func | struct session * sess
int topic_id
const void * msg
void * sess_ctx
void * plugin_env | void | 会话中的消息处理函数 -| lpm_trans_data_luatoc | struct lpm_state * state
struct lpm_cdata * data | 0表示成功,其他表示失败 | 将状态机中当前栈顶的数据转换为一个C中的cdata结构,并出栈 -| lpm_trans_data_ctolua | struct lpm_state * state
struct lpm_cdata * data | 0表示成功,其他表示失败 | 将一个cdata结构转为一个Lua中的数据,并将该数据置于状态机栈顶 -Lua端函数 ## 功能模块 -### 函数管理 +### 函数及全局变量注册 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: function register +title: 函数注册 lua_cbinding_function --- flowchart TD; - start(["开始"]); paramcheck{"参数检查"}; checkspace{"参数中是否有space_name"}; @@ -152,10 +233,9 @@ flowchart TD; ```mermaid --- -title: function remove +title: 函数卸载 lua_cbinding_function_remove --- flowchart TD; - start(["开始"]); paramcheck{"参数检查"}; funccheck{"func_name是否在管理列表中"} @@ -182,14 +262,12 @@ flowchart TD; functype --> |N|finish deletefunc --> finish ``` -### 数据管理 -与函数管理流程相同,不同之处在于函数删除时会检查Lua中数据类型是否为function,但是在全局变量删除时不会做该校验 + ```mermaid --- -title: data register +title: 数据注册 lua_cbinding_data --- flowchart TD; - start(["开始"]); paramcheck{"参数检查"}; checkspace{"参数中是否有space_name"}; @@ -221,10 +299,9 @@ flowchart TD; ```mermaid --- -title: data remove +title: 数据卸载 lua_cbinding_data_remove --- flowchart TD; - start(["开始"]); paramcheck{"参数检查"}; datacheck{"data_name是否在管理列表中"} @@ -248,36 +325,525 @@ flowchart TD; datadelete --> deletedata deletedata --> finish ``` -### 插件管理 -整体原则:每一个Lua插件在stellar的插件管理器中为一个单独的插件,每一个session_plugin在stellar的会话插件管理器中也为一个单独的插件 -解决方案: -1. 在状态机整体init过程中将所有插件仅暂时保存在一个链表中,但是不加载至stellar的插件管理器中。每一次调用lpm_plugin_load函数时从插件链表中取出一个节点,并调用该节点中保存的load函数。之后在使用过程中,其plugin_env中已经保存了插件的所有信息,可通过plugin_env分辨是哪一个插件并调用该插件中数据; -2. 在状态机init过程中为插件分配一个lua_plugin_manage_id,在所有函数调用过程中增加一个参数,每次传入参数时携带该lua_plugin_manage_id -对于会话插件的管理,由于一个插件中可能注册多个会话插件,在会话插件管理上有两种不同的处理方案: -1. plugin_env中维护一个该插件的会话插件列表,在调用Lua会话插件时需要同时传入插件ID,在该列表中查找对应的处理函数进行调用; -2. 会话插件注册过程中复制一个完整的plugin_env,每一个会话插件拥有一个完全独立的plugin_env; ### Lua与C数据转换 -## 数据结构 +1. 根据不同的数据类型调用不同的Lua原生函数进行出入栈操作; +2. context本质是一个预分配并完成引用关联的lua-table,在lua状态机中可以不受限制的使用; +3. 后续可能会根据数据类型进行lua和C的内存转换,当前不支持内存共享使用; +4. lua元素在出栈过程中,table类型的变量只创建引用并返回引用编号; + +#### 数据结构 ```C -struct lpm_cdata { - enum LPM_DATATYPE data_type; - int data_length; - union { - int data_bool; - double data_num; - int data_int; - char * data_string; - struct lpm_ctable * data_table; - void * data_user; - void * data_context; +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中并不会校验是否存在重名变量、重名函数等,出现重名的变量或函数会直接将旧的数据覆盖。