summaryrefslogtreecommitdiff
path: root/docs/summaryDesign.md
blob: 0559f08ab1ece111c3a23b71708694cd7a759b81 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
# LuaPluginManage
- [LuaPluginManage](#luapluginmanage)
  - [总述](#总述)
    - [整体功能](#整体功能)
    - [状态机(state)](#状态机state)
    - [函数(function)](#函数function)
    - [数据(data)](#数据data)
    - [插件(plugin)](#插件plugin)
    - [模块(model)](#模块model)
    - [代码块(chunk)](#代码块chunk)
    - [数据转换\*](#数据转换)
  - [接口](#接口)
    - [外部接口](#外部接口)
    - [内部接口](#内部接口)
    - [C注册函数](#c注册函数)
    - [代码块](#代码块)
    - [Lua注册函数](#lua注册函数)
  - [总体设计](#总体设计)
    - [初始化](#初始化)
    - [退出](#退出)
  - [功能模块](#功能模块)
    - [各功能结构之间关系](#各功能结构之间关系)
    - [函数及全局变量注册](#函数及全局变量注册)
      - [数据结构](#数据结构)
      - [函数](#函数)
    - [Lua与C数据转换](#lua与c数据转换)
      - [数据结构](#数据结构-1)
    - [状态机管理](#状态机管理)
      - [函数](#函数-1)
    - [插件管理](#插件管理)
      - [数据结构](#数据结构-2)
    - [模块管理](#模块管理)
      - [数据结构](#数据结构-3)
    - [代码块管理](#代码块管理)
      - [函数](#函数-2)
    - [配置管理](#配置管理)
      - [数据结构](#数据结构-4)
    - [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中保存的数据,并可以对该数据进行修改、维护;
### 状态机(state)
状态机用于保存Lua运行虚拟机在运行过程中所有的环境表、注册表、堆栈、数据段、上下文等数据。Lua状态机是Lua运行过程中对外暴露的唯一数据结构,其余数据结构均已经在Lua内部隐藏,所有对Lua的操作均需要通过改变状态机的状态来实现。一个Lua状态机可以理解为一个Lua的线程,该状态机和C的线程一样,拥有独立的内存空间。  
创建:安全的新建一个空的状态机  
删除:释放一个状态机,删除其内部所有数据占用的内存并释放一个状态机实例  
初始化:状态机初始化过程中加载运行时必要的Lua组件,并根据配置文件将各个Lua插件加载在状态机中  
获取运行错误*:获取状态机运行过程中的错误  
获取运行状态*:获取状态机运行状态,包括运行时间、加载插件数量、运行耗时等
### 函数(function)
向Lua内部注册一个函数,可供Lua程序在运行过程中调用。如向lua中传入数据结构时,可通过注册函数的方式向Lua提供数据的获取方法。或通过注册函数向Lua提供其他模块的外部接口。  
注册:向Lua状态机中注册一个格式要求符合lpm_cbinding_function类型的函数,该函数可供Lua脚本调用  
删除:从Lua状态机中删除一个C注册的函数  
安全检查*:提供一个标准化的定义方式,在Lua插件编写过程中可通过该定义方式得知运行过程中存在的注册函数名称、参数类型等,防止在调用过程中出错;在Lua脚本加载前对其内部调用的C函数进行安全性检查,检查如传入参数个数、参数类型等  
自动化函数翻译*:通过特定方法能够自动将一些C函数转换为Lua的注册函数格式  
### 数据(data)
向Lua内部注册一个函数,可供Lua脚本在运行过程中使用。如向Lua中传入运行程序版本、运行环境信息、系统信息等。  
注册:向状态机中注册一个全局变量,变量类型可以为数字、字符串;如需注册一个数据结构需同时注册该数据结构的成员获取方法  
删除:从状态机中删除一个全局变量  
数据范式化*:将一段Lua数据范式化为一段json或其他特定格式,方便输出或在其他程序中调用
### 插件(plugin)
插件为一整个Lua功能模块,与C中的插件含义相同。  
插件加载:将一个插件加载至插件管理器中  
插件卸载:从插件管理器中卸载一个插件  
会话插件加载:将一个会话插件加载至session_plugin_manage中  
会话插件卸载:从session_plugin_manage中删除一个会话插件  
注册会话插件:此功能仅在lua端暴露,不在C接口中。在插件加载过程中可注册会话插件 
订阅会话消息:此功能仅在lua端暴露,不在C接口中。在插件加载过程中可订阅一个会话中特定id的会话消息  
处理会话消息:处理会话过程中的数据  
### 模块(model)
模块为加载Lua的一个通用文件,模块与配置项一一对应,将一个配置项加载为一个插件管理器中的模块
模块加载:向插件管理器中插入一个新的模块
由于模块没有唯一标识,在模块插入后不支持单独卸载,在插件管理器整体退出过程中会卸载所有插入的模块
### 代码块(chunk)
代码块可以是一段Lua代码、一个Lua文件或一个Lua函数。在注册过程中,在状态机中加载一段lua代码,并将其通过引用方式确定其一个引用编号,调用过程中通过引用编号在状态机中调用一段代码。参数及返回值的传递通过数据模块进行。目前支持的数据类型包括数字、字符串、table、userdata。
代码块执行:执行一段代码,并获取其执行结果
### 数据转换*
将Lua数据翻译为C中可读可写可持久化保存的数据,也可以将一个由Lua转换为C数据得到的序列化数据转换为Lua中的数据结构
Lua转换至C:将Lua数据序列化成为C中一段内存数据
C转换至Lua:将C中数据反序列化为Lua中一段数据

## 接口
### 外部接口
| 函数名称 | 参数 | 返回值 | 功能 |
| --- | --- | --- | --- |
| lua_plugin_manage_init | struct stellar * st<br>int specific_count<br>struct lua_config_specific *specifics | 创建的lua插件管理器实例指针 | 根据配置文件创建一个lua插件管理器实例,并在函数内完成配置加载及初始化过程
| lua_plugin_manage_exit | struct lua_plugin_manage_schema * lua_plug_mgr | void | 清理一个lua插件管理器实例,清除内部所有数据
| lua_plugin_manage_load_one_specific | struct lua_plugin_manage_schema *schema<br>struct lua_config_specific *specific | 0成功,其他失败 | 在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销毁时调用
| lpm_message_free_func | struct session *sess<br>void *msg<br>void *msg_free_arg | void | 在消息释放过程中调用的函数
| lpm_on_session_msg_func | struct session *sess<br>int topic_id<br>const void *msg<br>void *sess_ctx<br>void *plugin_env | void | 触发消息时调用

### 代码块
| 函数名称 | 参数 | 返回值 | 功能 |
| --- | --- | --- | --- |
| lua_chunk_execute | lua_State *state<br>int ref_id<br>int pcount<br>struct lua_cdata *params<br>int rcount<br>struct lua_cdata *returns | int | 调用并执行一个Lua代码块,该代码段需要提前生成一个引用ID,通过该引用ID进行执行

### Lua注册函数
| 函数名称 | 参数 | 返回值 | 功能 |
| --- | --- | --- | --- |
| lua_plugin_manage_session_regist | lua_State * state | 0无需处理返回值,1需处理返回值 | lua中调用该函数注册插件,注册完成后调用方式为调用plugin_manage.register
| lua_session_get_type | lua_State * state | 1有返回值 | 获取sessiontype
| lua_mq_create_topic | lua_State *state | 1有返回值,0处理失败或无返回值 | 创建一个新的topic
| lua_mq_get_topic_id | lua_State *state | 1有返回值,0处理失败或无返回值 | 根据topic名称获取某个topic的编号
| lua_mq_update_topic | lua_State *state | 1有返回值,0处理失败或无返回值 | 更新一个topic,更新其释放函数及释放私有数据
| lua_mq_destory_topic | lua_State *state | 1有返回值,0处理失败或无返回值 | 销毁一个topic
| lua_mq_subscribe_topic | lua_State *state | 1有返回值,0处理失败或无返回值 | 订阅一个topic,根据plugin编号订阅
| lua_mq_topic_is_active | lua_State *state | 1有返回值,0处理失败或无返回值 | 判断topic当前的活跃状态
| lua_mq_publish_message | lua_State *state | 1有返回值,0处理失败或无返回值 | 在topic中发布一条消息
| lua_mq_ignore_message | lua_State *state | 1有返回值,0处理失败或无返回值 | 在会话中忽略一个消息
| lua_mq_unignore_message | lua_State *state | 1有返回值,0处理失败或无返回值 | 在会话中取消忽略一个消息

## 总体设计
### 初始化
```mermaid
---
title: lua_plugin_manage_init
---
flowchart TD;
    start(["开始"]);
    createschema["calloc新的schema"];
    initmessagemq["初始化消息队列"];
    getthreadnum["获取线程数量"];
    createstate["根据线程数量创建对应状态机"];
    getmodelnum["获取需要加载的模块数量"];
    createmodel["根据模块数量预分配内存"];
    finishload{"所有状态机完成初始化"};
    initstate["初始化状态机"];
    finishstate{"状态机完成所有模块加载"};
    loadspecific["状态机加载一个模块"];
    callload["调用该模块加载函数"];
    finish(["结束"]);

    start --> createschema
    createschema --> initmessagemq
    initmessagemq --> getthreadnum
    getthreadnum --> createstate
    createstate --> getmodelnum
    getmodelnum --> createmodel
    createmodel --> finishload
    finishload --> |N|initstate
    finishload --> |Y|finish
    initstate --> finishstate
    finishstate --> |N|loadspecific
    finishstate --> |Y|finishload
    loadspecific --> callload
    callload --> finishstate
```
1. 创建一个新的schema实例
2. 将配置文件中配置信息加载至schema实例中暂存
3. 在schema中按照线程数量创建状态机,并完成初始化

### 退出
```mermaid
---
title: lua_plugin_manage_exit
---
flowchart TD;
    start(["开始"]);
    freestate["依次释放所有状态机"];
    freemodel["释放所有模块"];
    freemessage["释放所有消息队列"];
    finish(["结束"]);

    start --> freestate
    freestate --> freemodel
    freemodel --> freemessage
    freemessage --> finish
```

## 功能模块
### 各功能结构之间关系
```mermaid
---
title: 各结构体之间依赖关系
---
erDiagram
    lua_plugin_manage_schema {
        stellar st
        int state_count
        lua_State[] state
        int model_count
        lua_model[] model
        int mq_count
        array message_mq_array
    }
```

### 函数及全局变量注册
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. 每个线程中创建一个状态机,将该线程中加载的所有插件全部注册在该状态机中;

#### 函数
| 函数名称 | 参数 | 返回值 | 功能 |
| --- | --- | --- | --- |
| thread_state_init | int thread_id | 创建成功的状态机指针 | 创建一个状态机,并完成基础信息初始化

```mermaid
---
title: thread_state_init
---
flowchart TD;
    start(["开始"]);
    paramcheck{"参数检查"};
    newstate["创建状态机"];
    bindfunc["绑定函数"];
    binddata["绑定全局变量"];
    setthread["设置线程ID全局变量"];
    finish(["结束"]);

    start --> paramcheck
    paramcheck --> |Y|newstate
    praamcheck --> |N|finish
    newstate --> bindfunc
    bindfunc --> binddata
    binddata --> setthread
    setthread --> finish
```

### 插件管理
整体原则:每一个Lua插件在stellar的插件管理器中为一个单独的插件,插件在C插件管理器中共用同一个函数,在调用lua插件函数时根据插件的编号及注册使用的plugin_env查找插件的实际lua函数并完成调用;

#### 数据结构
```C
/* 保存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;
};
```

### 模块管理
#### 数据结构

### 代码块管理
#### 函数
| 函数名称 | 参数 | 返回值 | 功能 |
| --- | --- | --- | --- |
| lua_chunk_execute | lua_State *state<br>int ref_id<br>int pcount<br>struct lua_cdata *params<br>int rcount<br>struct lua_cdata *returns | 0运行成功,其他表示运行失败 | 调用一个lua代码块

```mermaid
---
title: lua_chunk_execute
---
flowchart TD;
    start(["开始"]);
    paramcheck{"参数检查"};
    getref["根据refid加载函数"];
    pushparam["传入参数"];
    execute["调用函数"];
    popreturn["取出参数"];
    finish(["结束"]);

    start --> paramcheck
    paramcheck --> |Y|getref
    paramcheck --> |N|finish
    getref --> pushparam
    pushparam --> 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;
};
```

### 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的接口将全局变量注册成为一个状态机中的全局变量,该全局变量与自定义数据全局变量的维护及保存逻辑一致,后续注册插件过程中如果出现与当前全局变量冲突的数据会导致插件注册失败

自定义数据与插件数据冲突  
自定义数据优先级高于插件数据,插件数据注册过程中如果与已存在的数据冲突会注册失败

## 使用限制
1. 在加载的Lua插件中尽量不使用全局变量,否则可能出现由于加载顺序问题导致全局变量被覆盖,使结果不符合预期的情况;可以将需要全局保存的数据注册为状态机中的全局变量,或将需要全局保存的数据写入env变量中解决此问题。