This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
niubinghui-luapluginmanage/docs/summaryDesign.md
2024-08-07 15:05:58 +08:00

859 lines
31 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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<br>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<br>struct lua_cdata *cdata | 0表示成功其他表示失败 | 将一个data结构入栈
| lua_cdata_pop_stack | lua_State *state<br>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<br>void *plugin_env | 在该session中创建的context实例 | session创建时调用
| lpm_ctx_free_func | struct session *sess<br>void *sess_ctx<br>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<br>lua_CFunction bind_function<br>const char *function_name<br>const char *space_name | 0表示成功其他表示失败 | 向lua状态机中注册一个函数
| lua_cbinding_function_remove | lua_State *state<br>const char *function_name<br>const char *space_name | 0表示成功其他表示失败 | 从状态机中移除一个已经完成注册的函数
| lua_cbinding_data | lua_State *state<br>struct lua_binding_data *data | 0表示成功其他表示失败 | 向lua状态机中注册一段数据该数据在状态机中作为全局变量存在
| lua_cbinding_data_remove | lua_State *state<br>const char *data_name<br>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<br>int thread_count | >=0状态机创建成功的数量<0加载失败 | 在schema中根据线程数量创建多个状态机并完成状态机的初始化
| thread_state_instance_init | struct lua_thread_state *thread_state<br>int state_id | 0表示成功其他表示失败 | 初始化一个状态机的实例包括创建lua_State、绑定函数、绑定全局变量等
| thread_state_instance_destory | void * elt | void | 销毁一个状态机,清空状态机中所有注册的插件并关闭状态机
| thread_state_instance_load | struct lua_thread_state *thread_state<br>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<br>lua_State *state<br>int plugin_id<br>int new_refid<br>int free_refid | 0表示成功其他表示失败 | 初始化一个运行在会话中的插件
| session_plugin_instance_destory | void *elt | void | 销毁一个运行在会话中的插件
| plugin_env_instance_init | struct lua_plugin_env *plugin_env<br>lua_State *state<br>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<br>lua_State *state<br>const char *filepath<br>const char *funcname | 0表示成功其他表示失败 | 根据文件名及函数名称从lua脚本中初始化一个脚本
| script_instance_init_byrefid | struct lua_script *script<br>lua_State *state<br>int ref_id | 0表示成功其他表示失败 | 根据一个已经在状态机中生成引用的引用编号初始化一个脚本
| script_instance_clean | struct lua_script *script | void | 清理一个脚本实例
| script_execute | struct lua_script *script<br>int pcount<br>struct lua_cdata *param<br>int rmaxcount<br>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<br>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<br>void *plugin_env | 在该session中创建的context实例 | session创建时调用
| lpm_ctx_free_func | struct session *sess<br>void *sess_ctx<br>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的接口将全局变量注册成为一个状态机中的全局变量该全局变量与自定义数据全局变量的维护及保存逻辑一致后续注册插件过程中如果出现与当前全局变量冲突的数据会导致插件注册失败
自定义数据与插件数据冲突
自定义数据优先级高于插件数据,插件数据注册过程中如果与已存在的数据冲突会注册失败