543 lines
18 KiB
C
543 lines
18 KiB
C
/*************************************************************************
|
|
> 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_session_regist;
|
|
* ** 注册函数lua_plugin_manage_session_regist还需要补充
|
|
************************************************************************/
|
|
#include "lua_plugin_manage_internal.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/* 需要注册至lua中供lua调用的所有函数原型 */
|
|
int lua_plugin_manage_session_regist(lua_State * state);
|
|
|
|
/* 需要注册至状态机中的函数定义在链表中, 会依次完成注册 */
|
|
struct lua_binding_function lua_bind_functions[] = {
|
|
{lua_plugin_manage_session_regist, "register", "plugin_manage"},
|
|
{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, lua_CFunction bind_function, const char *function_name, const char *space_name);
|
|
/* 从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 | 需要注册函数的状态机
|
|
* | lua_CFunction | bind_function | 需要注册的函数
|
|
* | const char * | function_name | 注册函数的名称
|
|
* | const char * | space_name | 注册函数的命名空间
|
|
* Output:
|
|
* Return: | 0 | 注册成功
|
|
* | -1 | 传入的参数有错误
|
|
* | -2 | 命名空间已经存在, 且命名空间不是table类型, 无法新增成员
|
|
* | -3 | 命名空间中已经存在函数名称对应成员, 无法完成覆盖
|
|
* | -4 | 存在全局的函数名称, 无法完成注册
|
|
* Description: 将一个C函数注册至lua中
|
|
*/
|
|
int lua_cbinding_function(
|
|
lua_State *state,
|
|
lua_CFunction bind_function,
|
|
const char *function_name,
|
|
const char *space_name)
|
|
{
|
|
if (__glibc_unlikely(!state || !bind_function || !function_name))
|
|
return -1;
|
|
|
|
if (space_name)
|
|
{
|
|
/* 包含space_name, 调用时为 space_name.function_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 -2;
|
|
}
|
|
|
|
lua_getfield(state, -1, function_name);
|
|
if (lua_type(state, -1) != LUA_TNIL)
|
|
{
|
|
/* 在待插入的global table中存在与function_name重名的成员 */
|
|
lua_settop(state, 0);
|
|
return -3;
|
|
}
|
|
lua_pop(state, 1); /* 正确的情况下此时栈顶为nil, 弹出一个nil值 */
|
|
}
|
|
|
|
lua_pushcfunction(state, bind_function);
|
|
lua_setfield(state, -2, function_name);
|
|
}
|
|
else
|
|
{
|
|
lua_getglobal(state, function_name);
|
|
if (lua_type(state, -1) != LUA_TNIL)
|
|
{
|
|
/* 存在与function_name重名的全局成员 */
|
|
lua_settop(state, 0);
|
|
return -4;
|
|
}
|
|
lua_pop(state, 1);
|
|
|
|
/* 不包含space_name, 调用时直接使用function_name调用 */
|
|
lua_pushcfunction(state, bind_function);
|
|
lua_setglobal(state, function_name);
|
|
}
|
|
|
|
lua_settop(state, 0); /* 操作完成, 弹出所有元素 */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Function: lua_cbinding_function_remove
|
|
* Input: | lua_State * | state | 需要删除注册函数的状态机
|
|
* | const char * | function_name | 需要删除的函数名称
|
|
* | const char * | space_name | 需要删除的命名空间名称
|
|
* Output:
|
|
* Return: | 0 | 删除成功
|
|
* | -1 | 参数错误
|
|
* | -2 | 命名空间存在但不是一个table
|
|
* | -3 | 命名空间中存在函数名称对应成员, 但是类型不是函数
|
|
* | -4 | 函数名称对应的成员不是一个函数
|
|
* 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 -1;
|
|
|
|
if (space_name)
|
|
{
|
|
/* 检查该命名空间是否存在 */
|
|
lua_getglobal(state, space_name);
|
|
if (lua_type(state, -1) != LUA_TTABLE)
|
|
{
|
|
/* 命名空间存在且不是table */
|
|
lua_settop(state, 0);
|
|
return -2;
|
|
}
|
|
/* 检查该命名空间内是否存在function_name */
|
|
lua_getfield(state, -1, function_name);
|
|
if (lua_type(state, -1) != LUA_TFUNCTION)
|
|
{
|
|
/* 命名空间存在内部元素名称为function_name, 但是类型不符 */
|
|
lua_settop(state, 0);
|
|
return -3;
|
|
}
|
|
/* 删除该函数 */
|
|
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 -4;
|
|
}
|
|
/* 删除该函数 */
|
|
lua_pop(state, 1);
|
|
lua_pushnil(state);
|
|
lua_setglobal(state, function_name);
|
|
}
|
|
|
|
lua_settop(state, 0); /* 操作完成, 弹出所有元素 */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Function: lua_cbinding_data
|
|
* Input: | lua_State * | state | 需要注册数据的状态机
|
|
* | struct lua_binding_data * | data | 需要注册至状态机中的数据
|
|
* Output:
|
|
* Return: | 0 | 注册成功
|
|
* | -1 | 传入的参数有错误
|
|
* | -2 | 命名空间已经存在, 且命名空间不是table类型, 无法新增成员
|
|
* | -3 | 命名空间中已经存在函数名称对应成员, 无法完成覆盖
|
|
* | -4 | 无法识别data的数据类型
|
|
* | -5 | 全局变量名称已经有成员, 不为空
|
|
* Description: 将一个变量注册至lua状态机中
|
|
*/
|
|
int lua_cbinding_data(
|
|
lua_State *state,
|
|
struct lua_binding_data *data)
|
|
{
|
|
if (__glibc_unlikely(!state || !data))
|
|
{
|
|
return -1;
|
|
}
|
|
enum DATATYPE data_type = data->binding_data_type;
|
|
char *value = data->binding_data_value;
|
|
char *data_name = data->binding_data_name;
|
|
char *space_name = data->binding_data_space_name;
|
|
if (__glibc_unlikely(!value || !data_name))
|
|
return -1;
|
|
|
|
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 -2;
|
|
}
|
|
|
|
lua_getfield(state, -1, data_name);
|
|
if (lua_type(state, -1) != LUA_TNIL)
|
|
{
|
|
/* 在待插入的global table中存在与function_name重名的成员 */
|
|
lua_settop(state, 0);
|
|
return -3;
|
|
}
|
|
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 -4;
|
|
}
|
|
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 -5;
|
|
}
|
|
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 -4;
|
|
}
|
|
lua_setglobal(state, data_name);
|
|
}
|
|
|
|
lua_settop(state, 0); /* 操作完成, 弹出所有元素 */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Function: lua_cbinding_data_remove
|
|
* Input: | lua_State * | state | 需要删除注册数据的状态机
|
|
* | const char * | data_name | 需要删除的数据名称
|
|
* | const char * | space_name | 需要删除的命名空间名称
|
|
* Output:
|
|
* Return: | 0 | 删除成功
|
|
* | -1 | 参数错误
|
|
* | -2 | 命名空间存在但不是一个table
|
|
* | -3 | 命名空间中存在数据名称对应成员, 但是类型不符
|
|
* | -4 | 函数名称对应的成员类型不符
|
|
* 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 -1;
|
|
|
|
if (space_name)
|
|
{
|
|
/* 检查该命名空间是否存在 */
|
|
lua_getglobal(state, space_name);
|
|
if (lua_type(state, -1) != LUA_TTABLE)
|
|
{
|
|
/* 命名空间存在且不是table */
|
|
lua_settop(state, 0);
|
|
return -2;
|
|
}
|
|
/* 检查该命名空间内是否存在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 -3;
|
|
}
|
|
else if (data_type == LUA_TNIL)
|
|
{
|
|
/* 没有该名称的元素 */
|
|
lua_settop(state, 0);
|
|
return 0;
|
|
}
|
|
/* 删除该函数 */
|
|
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 -4;
|
|
}
|
|
else if (data_type == LUA_TNIL)
|
|
{
|
|
/* 没有该名称的元素 */
|
|
lua_settop(state, 0);
|
|
return 0;
|
|
}
|
|
/* 删除该函数 */
|
|
lua_pop(state, 1);
|
|
lua_pushnil(state);
|
|
lua_setglobal(state, data_name);
|
|
}
|
|
|
|
lua_settop(state, 0); /* 操作完成, 弹出所有元素 */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* 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 -1;
|
|
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].binding_function && lua_bind_functions[i].binding_function_name)
|
|
{
|
|
bind_ret = lua_cbinding_function(state,
|
|
lua_bind_functions[i].binding_function,
|
|
(const char *)lua_bind_functions[i].binding_function_name,
|
|
(const char *)lua_bind_functions[i].binding_function_space_name);
|
|
if (bind_ret)
|
|
{
|
|
LOGERROR("binding function failed, ret is %d, function name is %s\n", bind_ret, lua_bind_functions[i].binding_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].binding_data_value && lua_bind_datas[i].binding_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].binding_data_name, lua_bind_datas[i].binding_data_value);
|
|
failed_count += 1;
|
|
}
|
|
}
|
|
}
|
|
return failed_count;
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* Input:
|
|
* Output:
|
|
* Return:
|
|
* Description:
|
|
*/
|
|
int lua_plugin_manage_session_regist(lua_State *state)
|
|
{
|
|
/* 参数个数检查 */
|
|
if (lua_gettop(state) != 4)
|
|
{
|
|
lua_settop(state, 0);
|
|
return 0;
|
|
}
|
|
|
|
/* 参数类型检查 */
|
|
if (lua_type(state, -1) != LUA_TLIGHTUSERDATA || lua_type(state, -2) != LUA_TFUNCTION ||
|
|
lua_type(state, -3) != LUA_TFUNCTION || lua_type(state, -4) != LUA_TLIGHTUSERDATA)
|
|
{
|
|
lua_settop(state, 0);
|
|
return 0;
|
|
}
|
|
|
|
/* 取出处理第四个参数 */
|
|
struct lua_plugin_env *plugin_env = (struct lua_plugin_env *)lua_topointer(state, -1); /* stack 4 */
|
|
if (!plugin_env)
|
|
{
|
|
lua_settop(state, 0);
|
|
return 0;
|
|
}
|
|
lua_pop(state, 1);
|
|
|
|
/* 取出处理第三个参数 */
|
|
int ctx_free_id = luaL_ref(state, LUA_REGISTRYINDEX); /* stack 3 */
|
|
if (ctx_free_id == LUA_REFNIL)
|
|
{
|
|
lua_settop(state, 0);
|
|
return 0;
|
|
}
|
|
|
|
/* 取出处理第二个参数 */
|
|
int ctx_new_id = luaL_ref(state, LUA_REGISTRYINDEX); /* stack 2 */
|
|
if (ctx_new_id == LUA_REFNIL)
|
|
{
|
|
lua_settop(state, 0);
|
|
return 0;
|
|
}
|
|
|
|
/* 取出处理第一个参数 */
|
|
struct stellar * st = (struct stellar *)lua_topointer(state, -1); /* stack 1 */
|
|
if ( !st ) {
|
|
lua_settop(state, 0);
|
|
return 0;
|
|
}
|
|
lua_pop(state, 1);
|
|
|
|
/* 在stellar中注册, 获取注册id */
|
|
int plugin_id = stellar_session_plugin_register(st, lpm_ctx_new_func, lpm_ctx_free_func, (void *)plugin_env);
|
|
#ifdef LUAPLUGIN_BASIC_UNITTEST
|
|
printf("now regist new plugin, plugin id is %d\n", plugin_id);
|
|
#endif
|
|
|
|
/* 将注册完成的新插件插入到队列中 */
|
|
struct lua_session_plugin session_plugin;
|
|
memset(&session_plugin, 0, sizeof(session_plugin));
|
|
session_plugin_instance_init(&session_plugin, state, plugin_id, ctx_new_id, ctx_free_id);
|
|
|
|
utarray_push_back(plugin_env->plugin_env_plugin_array, &session_plugin);
|
|
|
|
lua_settop(state, 0);
|
|
lua_pushinteger(state, plugin_id);
|
|
|
|
return 1;
|
|
}
|