summaryrefslogtreecommitdiff
path: root/src/lua_plugin_binding.c
blob: 083da96050279cf04b8dfe92176365b3670d4ba7 (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
/*************************************************************************
    > File Name: lua_plugin_binding.c
    > Author:
    > Created Time: 2024-08
    > Encoding : UTF-8
 ************************************************************************/

/*************************************************************************
 * version
 * [ v0.1 ]
 * 08 -02
 * 1. 实现函数
 *    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;
 *    int lua_plugin_manage_regist;
 * ** 注册函数lua_plugin_manage_session_regist还需要补充
 *
 * 08-12
 * 1. 修改函数lua_cbinding_function, 参数与lua_cbinding_data保持统一
 * 2. 修改部分函数返回值, 使用枚举代替错误码返回值, 方便统一处理
 * 
 * 08-14
 * 1. 将所有待注册函数移动至新文件中, 不再此文件中实现
 ************************************************************************/
#include "lua_plugin_manage_internal.h"
#include "lua_binding_functions.h"

#include <stdlib.h>
#include <string.h>

/* 需要注册至状态机中的函数定义在链表中, 会依次完成注册 */
struct lua_binding_function lua_bind_functions[] = {
    {lua_plugin_manage_regist, "register", "plugin_manage"},
    // {lua_session_get_id, "getid", "session"},
    // {lua_session_set_id, "setid", "session"},
    {lua_session_get_type, "gettype", "session"},
    // {lua_session_set_type, "settype", "session"},
    {lua_mq_create_topic, "createtopic", "message"},
    {lua_mq_get_topic_id, "gettopicid", "message"},
    {lua_mq_update_topic, "updatetopic", "message"},
    {lua_mq_destory_topic, "destorytopic", "message"},
    {lua_mq_subscribe_topic, "subscribetopic", "message"},
    {lua_mq_topic_is_active, "topicisactive", "message"},
    {lua_mq_publish_message, "publishmessage", "message"},
    {lua_mq_ignore_message, "ignoremessage", "message"},
    {lua_mq_unignore_message, "unignoremessage", "message"},
    {NULL, NULL, NULL},
};

/* 需要注册至状态机中的数据定义在链表中, 会依次完成注册 */
/* 为了实现注册过程的统一, 所有数据类型均使用string作为value格式 */
struct lua_binding_data lua_bind_datas[] = {
    {DATATYPE_BOOL, "true", "test_data_bool", "plugin_manage"},
    {DATATYPE_INT, "1000", "test_data_int", "plugin_manage"},
    {DATATYPE_NUM, "100.001", "test_data_double", "plugin_manage"},
    {DATATYPE_STRING, "this is a string test", "test_data_string", "plugin_manage"},
    {DATATYPE_END, NULL, NULL, NULL},
};

/* 向lua状态机中注册一个函数 */
int lua_cbinding_function(lua_State *state, struct lua_binding_function *function);
/* 从lua状态机中移除一个已经注册的函数 */
int lua_cbinding_function_remove(lua_State *state, const char *function_name, const char *space_name);
/* 将一个全局数据注册至状态机中 */
int lua_cbinding_data(lua_State *state, struct lua_binding_data *data);
/* 从状态机中移除一个已经注册的全局数据 */
int lua_cbinding_data_remove(lua_State *state, const char *data_name, const char *space_name);

/*
 * Function: lua_cbinding_function
 * Input: | lua_State *                   | state    | 需要注册函数的状态机
 *        | struct lua_binding_function * | function | 需要绑定的function函数结构
 * Output:
 * Return: enum LUA_PLUGIN_RETURN
 * Description: 将一个C函数注册至lua中
 */
int lua_cbinding_function(
    lua_State *state,
    struct lua_binding_function *bind_function)
{
    if (__glibc_unlikely(!state || !bind_function))
        return PARAM_ERR;
    if (__glibc_unlikely(!bind_function->function || !bind_function->function_name))
        return PARAM_ERR;
#ifdef LUAPLUGIN_BASIC_UNITTEST
    LOGDEBUG("bind function to state, function %p, name %s, spacename %s",
             bind_function->function,
             bind_function->function_name,
             (bind_function->space_name) ? bind_function->space_name : "no");
#endif

    if (bind_function->space_name)
    {
        /* 包含space_name, 调用时为 space_name.function_name */
        lua_getglobal(state, bind_function->space_name);
        if (lua_gettop(state) == 0 || lua_type(state, -1) == LUA_TNIL)
        {
            /* 没有该命名空间, 创建一个 */
            lua_newtable(state);
            lua_setglobal(state, bind_function->space_name);
            lua_settop(state, 0);
            lua_getglobal(state, bind_function->space_name);
        }
        else
        {
            /* 该全局已经存在 */
            if (lua_type(state, -1) != LUA_TTABLE)
            {
                /* spacename已经被占用, 并且不是table, 无法插入数据 */
                lua_settop(state, 0);
                return BIND_NAMESPACE_TYPE_ERR;
            }

            lua_getfield(state, -1, bind_function->function_name);
            if (lua_type(state, -1) != LUA_TNIL)
            {
                /* 在待插入的global table中存在与function_name重名的成员 */
                lua_settop(state, 0);
                return BIND_FUNCTION_TYPE_ERR;
            }
            lua_pop(state, 1); /* 正确的情况下此时栈顶为nil, 弹出一个nil值 */
        }

        lua_pushcfunction(state, bind_function->function);
        lua_setfield(state, -2, bind_function->function_name);
    }
    else
    {
        lua_getglobal(state, bind_function->function_name);
        if (lua_type(state, -1) != LUA_TNIL)
        {
            /* 存在与function_name重名的全局成员 */
            lua_settop(state, 0);
            return BIND_FUNCTION_TYPE_ERR;
        }
        lua_pop(state, 1);

        /* 不包含space_name, 调用时直接使用function_name调用 */
        lua_pushcfunction(state, bind_function->function);
        lua_setglobal(state, bind_function->function_name);
    }

    lua_settop(state, 0); /* 操作完成, 弹出所有元素 */
    return SUCCESS;
}

/*
 * Function: lua_cbinding_function_remove
 * Input: | lua_State *  | state         | 需要删除注册函数的状态机
 *        | const char * | function_name | 需要删除的函数名称
 *        | const char * | space_name    | 需要删除的命名空间名称
 * Output:
 * Return: enum LUA_PLUGIN_RETURN
 * Description: 从状态机中删除一个C注册的函数, 删除过程中将该函数在lua状态的引用置为nil
 */
int lua_cbinding_function_remove(
    lua_State *state,
    const char *function_name,
    const char *space_name)
{
    if (__glibc_unlikely(!state || !function_name))
        return PARAM_ERR;

    if (space_name)
    {
        /* 检查该命名空间是否存在 */
        lua_getglobal(state, space_name);
        if (lua_type(state, -1) != LUA_TTABLE)
        {
            /* 命名空间存在且不是table */
            lua_settop(state, 0);
            return BIND_NAMESPACE_TYPE_ERR;
        }
        /* 检查该命名空间内是否存在function_name */
        lua_getfield(state, -1, function_name);
        if (lua_type(state, -1) != LUA_TFUNCTION)
        {
            /* 命名空间存在内部元素名称为function_name, 但是类型不符 */
            lua_settop(state, 0);
            return BIND_FUNCTION_TYPE_ERR;
        }
        /* 删除该函数 */
        lua_pop(state, 1);
        lua_pushnil(state);
        lua_setfield(state, -2, function_name);
    }
    else
    {
        /* 获取全局数据, 检查function_name */
        lua_getglobal(state, function_name);
        if (lua_type(state, -1) != LUA_TFUNCTION)
        {
            /* 类型不符 */
            lua_settop(state, 0);
            return BIND_FUNCTION_TYPE_ERR;
        }
        /* 删除该函数 */
        lua_pop(state, 1);
        lua_pushnil(state);
        lua_setglobal(state, function_name);
    }

    lua_settop(state, 0); /* 操作完成, 弹出所有元素 */
    return SUCCESS;
}

/*
 * Function: lua_cbinding_data
 * Input: | lua_State *               | state | 需要注册数据的状态机
 *        | struct lua_binding_data * | data  | 需要注册至状态机中的数据
 * Output:
 * Return: enum LUA_PLUGIN_RETURN
 * Description: 将一个变量注册至lua状态机中
 */
int lua_cbinding_data(
    lua_State *state,
    struct lua_binding_data *data)
{
    if (__glibc_unlikely(!state || !data))
    {
        return PARAM_ERR;
    }
    enum DATATYPE data_type = data->data_type;
    char *value = data->data_value;
    char *data_name = data->data_name;
    char *space_name = data->space_name;
    if (__glibc_unlikely(!value || !data_name))
        return PARAM_ERR;
#ifdef LUAPLUGIN_BASIC_UNITTEST
    LOGDEBUG("bind data to state, type %d, data %s, name %s, spacename %s",
             data_type, value, data_name, (space_name) ? space_name : "no");
#endif

    if (space_name)
    {
        /* 包含space_name */
        lua_getglobal(state, space_name);
        if (lua_gettop(state) == 0 || lua_type(state, -1) == LUA_TNIL)
        {
            /* 没有该命名空间, 创建一个 */
            lua_newtable(state);
            lua_setglobal(state, space_name);
            lua_settop(state, 0);
            lua_getglobal(state, space_name);
        }
        else
        {
            /* 该全局已经存在 */
            if (lua_type(state, -1) != LUA_TTABLE)
            {
                /* spacename已经被占用, 并且不是table, 无法插入数据 */
                lua_settop(state, 0);
                return BIND_NAMESPACE_TYPE_ERR;
            }

            lua_getfield(state, -1, data_name);
            if (lua_type(state, -1) != LUA_TNIL)
            {
                /* 在待插入的global table中存在与function_name重名的成员 */
                lua_settop(state, 0);
                return BIND_DATA_TYPE_ERR;
            }
            lua_pop(state, 1); /* 正确的情况下此时栈顶为nil, 弹出一个nil值 */
        }

        /* 不同类型需要使用不同的入栈函数 */
        switch (data_type)
        {
        case DATATYPE_BOOL:
            if (strstr(value, "true") || strstr(value, "TRUE"))
                lua_pushboolean(state, 1);
            else if (strstr(value, "false") || strstr(value, "FALSE"))
                lua_pushboolean(state, 0);
            break;
        case DATATYPE_INT:
            lua_pushinteger(state, atoi(value));
            break;
        case DATATYPE_NUM:
            lua_pushnumber(state, (lua_Number)atof(value));
            break;
        case DATATYPE_STRING:
            lua_pushstring(state, (const char *)value);
            break;
        default:
            /* 未识别的类型 */
            lua_settop(state, 0);
            return BIND_DATA_TYPE_UNKNOWN;
        }
        lua_setfield(state, -2, data_name);
    }
    else
    {
        lua_getglobal(state, data_name);
        if (lua_type(state, -1) != LUA_TNIL)
        {
            lua_settop(state, 0);
            /* 存在与data_name重名的全局成员 */
            return BIND_DATA_TYPE_ERR;
        }
        lua_pop(state, 1);

        /* 不同类型需要使用不同的入栈函数 */
        switch (data_type)
        {
        case DATATYPE_BOOL:
            if (strstr(value, "true") || strstr(value, "TRUE"))
                lua_pushboolean(state, 1);
            else if (strstr(value, "false") || strstr(value, "FALSE"))
                lua_pushboolean(state, 0);
            break;
        case DATATYPE_INT:
            lua_pushinteger(state, atoi(value));
            break;
        case DATATYPE_NUM:
            lua_pushnumber(state, (lua_Number)atof(value));
            break;
        case DATATYPE_STRING:
            lua_pushstring(state, (const char *)value);
            break;
        default:
            /* 未识别的类型 */
            lua_settop(state, 0);
            return BIND_DATA_TYPE_UNKNOWN;
        }
        lua_setglobal(state, data_name);
    }

    lua_settop(state, 0); /* 操作完成, 弹出所有元素 */
    return SUCCESS;
}

/*
 * Function: lua_cbinding_data_remove
 * Input: | lua_State *  | state      | 需要删除注册数据的状态机
 *        | const char * | data_name  | 需要删除的数据名称
 *        | const char * | space_name | 需要删除的命名空间名称
 * Output:
 * Return: enum LUA_PLUGIN_RETURN
 * Description: 从状态机中删除一个C注册的数据, 删除过程中将该名称在lua状态的引用置为nil
 */
int lua_cbinding_data_remove(
    lua_State *state,
    const char *data_name,
    const char *space_name)
{
    if (__glibc_unlikely(!state || !data_name))
        return PARAM_ERR;

    if (space_name)
    {
        /* 检查该命名空间是否存在 */
        lua_getglobal(state, space_name);
        if (lua_type(state, -1) != LUA_TTABLE)
        {
            /* 命名空间存在且不是table */
            lua_settop(state, 0);
            return BIND_NAMESPACE_TYPE_ERR;
        }
        /* 检查该命名空间内是否存在data_name */
        lua_getfield(state, -1, data_name);
        int data_type = lua_type(state, -1);
        if (data_type != LUA_TSTRING && data_type != LUA_TNUMBER && data_type != LUA_TBOOLEAN)
        {
            /* 命名空间存在内部元素名称为data_name, 但是类型不符 */
            lua_settop(state, 0);
            return BIND_DATA_TYPE_ERR;
        }
        else if (data_type == LUA_TNIL)
        {
            /* 没有该名称的元素 */
            lua_settop(state, 0);
            return SUCCESS;
        }
        /* 删除该函数 */
        lua_pop(state, 1);
        lua_pushnil(state);
        lua_setfield(state, -2, data_name);
    }
    else
    {
        /* 获取全局数据, 检查function_name */
        lua_getglobal(state, data_name);
        int data_type = lua_type(state, -1);
        if (data_type != LUA_TSTRING && data_type != LUA_TNUMBER && data_type != LUA_TBOOLEAN)
        {
            /* 类型不符 */
            lua_settop(state, 0);
            return BIND_DATA_TYPE_ERR;
        }
        else if (data_type == LUA_TNIL)
        {
            /* 没有该名称的元素 */
            lua_settop(state, 0);
            return SUCCESS;
        }
        /* 删除该函数 */
        lua_pop(state, 1);
        lua_pushnil(state);
        lua_setglobal(state, data_name);
    }

    lua_settop(state, 0); /* 操作完成, 弹出所有元素 */
    return SUCCESS;
}

/*
 * Function: lua_cbinding_functions
 * Input: | lua_State * | state | 需要绑定函数的状态机实例
 * Output:
 * Return: | -1 | 参数错误
 *         | 0  | 成功
 *         | >0 | 绑定出错的数据数量
 * Description: 绑定所有需要在lua中调用的C函数
 */
int lua_cbinding_functions(lua_State *state)
{
    if (__glibc_unlikely(!state))
        return PARAM_ERR;
    int bind_function_count = sizeof(lua_bind_functions) / sizeof(struct lua_binding_function);

    int bind_ret = 0;
    int failed_count = 0;
    for (int i = 0; i < bind_function_count; ++i)
    {
        if (lua_bind_functions[i].function && lua_bind_functions[i].function_name)
        {
            bind_ret = lua_cbinding_function(state, &lua_bind_functions[i]);
            if (bind_ret)
            {
                LOGERROR("binding function failed, ret is %d, function name is %s\n", bind_ret, lua_bind_functions[i].function_name);
                failed_count += 1;
            }
        }
    }
    return failed_count;
}

/*
 * Function: lua_cbinding_datas
 * Input: | lua_State * | state | 需要绑定数据的状态机实例
 * Output:
 * Return: | -1 | 参数错误
 *         | 0  | 成功
 *         | >0 | 绑定出错的数据数量
 * Description: 绑定所有data数据
 */
int lua_cbinding_datas(lua_State *state)
{
    if (__glibc_unlikely(!state))
        return -1;
    int bind_data_count = sizeof(lua_bind_datas) / sizeof(struct lua_binding_data);

    int bind_ret = 0;
    int failed_count = 0;
    for (int i = 0; i < bind_data_count; ++i)
    {
        if (lua_bind_datas[i].data_value && lua_bind_datas[i].data_name)
        {
            bind_ret = lua_cbinding_data(state, &lua_bind_datas[i]);
            if (bind_ret)
            {
                LOGERROR("binding data failed, ret is %d, data is [%s]%s", bind_ret, lua_bind_datas[i].data_name, lua_bind_datas[i].data_value);
                failed_count += 1;
            }
        }
    }
    return failed_count;
}