Plugin Management support C plugin

This commit is contained in:
luwenpeng
2022-07-27 18:32:22 +08:00
parent 649d29e538
commit 50111e7cd0
35 changed files with 4220 additions and 193 deletions

View File

@@ -1,106 +1,313 @@
#include "deps/uthash/uthash.h"
#include "sdk/include/session.h"
#include "sdk/include/plugin.h"
#include "session_manager.h"
#include "plugin_manager.h"
#include "plugin_manager_util.h"
#include "plugin_manager_config.h"
#include "plugin_manager_module.h"
#include <sys/queue.h>
#include <assert.h>
#include <errno.h>
/******************************************************************************
* CallBack Static Hash Table (For Global)
* CallBack Runtime (For Per Session)
******************************************************************************/
struct session_event_callback_static
struct eventcb_runtime
{
enum session_event_type event;
fn_session_event_callback *callback;
};
/*
* Hast table
*
* key: string -> session_type
* val: array -> event_cbs
*/
struct managed_session_event_callback
{
char session_type[16];
struct session_event_callback_static event_cbs[0]; // dynamic array
// Record the number of callback functions that want to process the current session
int event_cbs_num;
UT_hash_handle hh;
};
/******************************************************************************
* CallBack Runtime Array (For Per Session)
******************************************************************************/
struct session_event_callback_runtime
{
int skip; // for skip this plugin callback
void *callback_args;
int skip;
void *cb_args;
enum session_event_type event;
fn_session_event_callback *callback;
fn_session_event_callback *cb;
};
struct session_plugin_ctx
{
int event_cbs_num;
struct session_event_callback_runtime event_cbs[0]; // dynamic array
int current_plugin_index;
int eventcb_num;
struct eventcb_runtime *eventcbs;
};
/******************************************************************************
* struct plugin_manager
* CallBack Static (For Per Plugin Manager)
******************************************************************************/
/*
* Each plugin has an init_cb and an exit_cb, but may have multiple entry_cb.
* entry_cb is stored in the global_session_callback_ctx.
*/
struct plugin_ctx
struct eventcb_static
{
char *name;
char *library;
/*
* Stores the context generated by the plugin initialization,
* which is used to release resources when the plugin ends.
*/
void *pme;
plugin_init_callback *init_cb;
plugin_exit_callback *exit_cb;
enum session_event_type event;
fn_session_event_callback *cb;
};
struct plugin_manager_eventcb
{
char session_name[MAX_SESSION_NAME_LENGTH]; // key
int eventcb_num; // val size
struct eventcb_static *eventcbs; // val: dynamic array
UT_hash_handle hh;
};
/******************************************************************************
* Struct plugin_manager
******************************************************************************/
struct plugin_manager
{
struct managed_session_event_callback *cb_table;
struct plugin_ctx plugins[MAX_PLUGIN_NUM];
int used_module_num;
int used_config_num;
int used_evencb_num; // only plugin register eventcb numbers
struct plugin_manager_module *modules[MAX_PLUGIN_NUM];
struct plugin_manager_config *configs[MAX_PLUGIN_NUM];
struct plugin_manager_eventcb *evcb_htable;
};
/******************************************************************************
* Private API
* Create/Destory plugin ctx (per session)
******************************************************************************/
static void plugin_manager_handle_opening_event(struct plugin_manager *plug_mgr, struct stellar_event *event)
static struct session_plugin_ctx *plugin_manager_create_plugin_ctx(struct plugin_manager *plug_mgr, const char *session_name)
{
if (session_name == NULL || strlen(session_name) == 0)
{
plugin_manager_log(ERROR, "invalid parameter, session name is empty");
return NULL;
}
struct plugin_manager_eventcb *elem;
HASH_FIND_STR(plug_mgr->evcb_htable, session_name, elem);
if (elem == NULL)
{
plugin_manager_log(ERROR, "can't find event callback for session name '%s'", session_name);
return NULL;
}
else
{
struct session_plugin_ctx *plug_ctx = safe_alloc(struct session_plugin_ctx, 1);
plug_ctx->eventcb_num = elem->eventcb_num;
plug_ctx->eventcbs = safe_alloc(struct eventcb_runtime, plug_ctx->eventcb_num);
for (int i = 0; i < plug_ctx->eventcb_num; i++)
{
plug_ctx->eventcbs[i].skip = 0;
plug_ctx->eventcbs[i].event = elem->eventcbs[i].event;
plug_ctx->eventcbs[i].cb = elem->eventcbs[i].cb;
plug_ctx->eventcbs[i].cb_args = NULL;
}
return plug_ctx;
}
}
static void plugin_manager_handle_data_event(struct plugin_manager *plug_mgr, struct stellar_event *event)
{
}
static void plugin_manager_handle_closing_event(struct plugin_manager *plug_mgr, struct stellar_event *event)
static void plugin_manager_destory_plugin_ctx(struct session_plugin_ctx *plug_ctx)
{
if (plug_ctx)
{
safe_free(plug_ctx->eventcbs);
safe_free(plug_ctx);
}
}
/******************************************************************************
* Public API
* Tools for managing plugins
******************************************************************************/
static int plugin_manager_parse_plugins(struct plugin_manager *plug_mgr, const char *prefix, const char *file)
{
char plugin_inf[4096] = {0};
char line_buffer[4096] = {0};
if (strlen(prefix) <= 0)
{
plugin_manager_log(ERROR, "Invalid parameter, plugin config file prefix cannot be empty");
return -1;
}
if (strlen(file) <= 0)
{
plugin_manager_log(ERROR, "Invalid parameter, plugin config file name cannot be empty");
return -1;
}
strcat_prefix_and_file(prefix, file, plugin_inf, sizeof(plugin_inf));
FILE *fp = fopen(plugin_inf, "r");
if (fp == NULL)
{
plugin_manager_log(ERROR, "can't open %s, %s", plugin_inf, strerror(errno));
return -1;
}
while (fgets(line_buffer, sizeof(line_buffer), fp))
{
if ('#' == line_buffer[0] || '\n' == line_buffer[0])
{
memset(line_buffer, 0, sizeof(line_buffer));
continue;
}
if (plug_mgr->used_config_num >= MAX_PLUGIN_NUM)
{
plugin_manager_log(ERROR, "the number of registered plugins exceeds the limit and cannot exceed %d", MAX_PLUGIN_NUM);
goto err;
}
struct plugin_manager_config *config = plugin_mangager_config_create();
if (plugin_mangager_config_parse(config, prefix, line_buffer) == -1)
{
plugin_mangager_config_destory(config);
goto err;
}
plug_mgr->configs[plug_mgr->used_config_num] = config;
plug_mgr->used_config_num++;
memset(line_buffer, 0, sizeof(line_buffer));
}
fclose(fp);
return 0;
err:
if (fp)
{
fclose(fp);
fp = NULL;
}
return -1;
}
static int plugin_manager_open_plugins(struct plugin_manager *plug_mgr)
{
for (int i = 0; i < plug_mgr->used_config_num; i++)
{
struct plugin_manager_config *config = plug_mgr->configs[i];
struct plugin_manager_module *module = plugin_manager_module_open(config);
if (module == NULL)
{
return -1;
}
plug_mgr->modules[plug_mgr->used_module_num] = module;
plug_mgr->used_module_num++;
}
return 0;
}
static int plugin_manager_register_plugins(struct plugin_manager *plug_mgr)
{
for (int i = 0; i < plug_mgr->used_module_num; i++)
{
struct plugin_manager_module *module = plug_mgr->modules[i];
if (plugin_manager_module_register(plug_mgr, module) == -1)
{
return -1;
}
plug_mgr->used_evencb_num++;
}
return 0;
}
static int plugin_manager_init_plugins(struct plugin_manager *plug_mgr)
{
for (int i = 0; i < plug_mgr->used_module_num; i++)
{
struct plugin_manager_module *module = plug_mgr->modules[i];
if (plugin_manager_module_init(module) == -1)
{
return -1;
}
double percentage = ((double)(i + 1)) / ((double)plug_mgr->used_module_num) * ((double)100);
plugin_manager_log(INFO, "Plugin initialization progress: [%.2f%]", percentage);
}
return 0;
}
static void plugin_manager_exit_plugins(struct plugin_manager *plug_mgr)
{
if (plug_mgr && plug_mgr->used_module_num)
{
for (int i = 0; i < plug_mgr->used_module_num; i++)
{
struct plugin_manager_module *module = plug_mgr->modules[i];
plugin_manager_module_exit(module);
}
}
}
static void plugin_manager_close_plugins(struct plugin_manager *plug_mgr)
{
if (plug_mgr && plug_mgr->used_module_num)
{
for (int i = 0; i < plug_mgr->used_module_num; i++)
{
struct plugin_manager_module *module = plug_mgr->modules[i];
plugin_manager_module_close(module);
}
plug_mgr->used_module_num = 0;
}
}
// deparse for destory parse
static void plugin_manager_deparse_plugins(struct plugin_manager *plug_mgr)
{
if (plug_mgr && plug_mgr->used_config_num)
{
for (int i = 0; i < plug_mgr->used_config_num; i++)
{
struct plugin_manager_config *config = plug_mgr->configs[i];
plugin_mangager_config_destory(config);
}
plug_mgr->used_config_num = 0;
}
}
/******************************************************************************
* Public API for managing plugins
******************************************************************************/
int plugin_manager_load(struct plugin_manager *plug_mgr, const char *prefix, const char *file)
{
if (plugin_manager_parse_plugins(plug_mgr, prefix, file) == -1)
{
return -1;
}
if (plugin_manager_open_plugins(plug_mgr) == -1)
{
return -1;
}
if (plugin_manager_register_plugins(plug_mgr) == -1)
{
return -1;
}
if (plugin_manager_init_plugins(plug_mgr) == -1)
{
return -1;
}
return 0;
}
void plugin_manager_unload(struct plugin_manager *plug_mgr)
{
plugin_manager_exit_plugins(plug_mgr);
plugin_manager_close_plugins(plug_mgr);
plugin_manager_deparse_plugins(plug_mgr);
}
struct plugin_manager *plugin_manager_create()
{
struct plugin_manager *plug_mgr = NULL;
struct plugin_manager *plug_mgr = safe_alloc(struct plugin_manager, 1);
plug_mgr->used_module_num = 0;
plug_mgr->used_config_num = 0;
plug_mgr->used_evencb_num = 0;
plug_mgr->evcb_htable = NULL;
return plug_mgr;
}
@@ -109,45 +316,138 @@ void plugin_manager_destory(struct plugin_manager *plug_mgr)
{
if (plug_mgr)
{
if (plug_mgr->evcb_htable)
{
struct plugin_manager_eventcb *elem;
struct plugin_manager_eventcb *tmp;
HASH_ITER(hh, plug_mgr->evcb_htable, elem, tmp)
{
HASH_DEL(plug_mgr->evcb_htable, elem);
safe_free(elem->eventcbs);
safe_free(elem);
}
plug_mgr->evcb_htable = NULL;
plug_mgr->used_evencb_num = 0;
}
plugin_manager_unload(plug_mgr);
safe_free(plug_mgr);
}
}
int plugin_manager_load(struct plugin_manager *plug_mgr, const char *plugin_file)
int plugin_manager_register(struct plugin_manager *plug_mgr, const char *session_name, enum session_event_type event, fn_session_event_callback *cb)
{
return 0;
}
if (strlen(session_name) <= 0)
{
plugin_manager_log(ERROR, "invalid parameter, session name is empty");
return -1;
}
void plugin_manager_unload(struct plugin_manager *plug_mgr)
{
}
if (strlen(session_name) > MAX_SESSION_NAME_LENGTH)
{
plugin_manager_log(ERROR, "invalid parameter, session name '%s' is too long and exceeds '%d' bytes", session_name, MAX_SESSION_NAME_LENGTH);
return -1;
}
if (cb == NULL)
{
plugin_manager_log(ERROR, "invalid parameter, the callback corresponding to the session name '%s' is null", session_name);
return -1;
}
struct plugin_manager_eventcb *elem;
HASH_FIND_STR(plug_mgr->evcb_htable, session_name, elem);
// session_name exists, add a new cb to the end of the eventcbs dynamic array
if (elem)
{
elem->eventcbs = (struct eventcb_static *)realloc(elem->eventcbs, (elem->eventcb_num + 1) * sizeof(struct eventcb_static));
elem->eventcbs[elem->eventcb_num].event = event;
elem->eventcbs[elem->eventcb_num].cb = cb;
elem->eventcb_num++;
}
// session_name does not exist, allocate a new node elem, and add elem to the hash table
else
{
elem = safe_alloc(struct plugin_manager_eventcb, 1);
memcpy(elem->session_name, session_name, strlen(session_name));
elem->eventcbs = (struct eventcb_static *)realloc(elem->eventcbs, (elem->eventcb_num + 1) * sizeof(struct eventcb_static));
elem->eventcbs[elem->eventcb_num].event = event;
elem->eventcbs[elem->eventcb_num].cb = cb;
elem->eventcb_num++;
HASH_ADD_STR(plug_mgr->evcb_htable, session_name, elem);
}
int plugin_manager_register(struct plugin_manager *plug_mgr, const char *session_type, fn_session_event_callback *callback)
{
return 0;
}
void plugin_manager_dispatch(struct plugin_manager *plug_mgr, struct stellar_event *event)
{
assert(event);
struct stellar_session_event_data *event_data = event->session_event_data;
assert(event_data);
session_event_type type = event_data->type;
const struct stellar_session *seesion = stellar_event_get_session(event);
struct session_plugin_ctx *plug_ctx = stellar_event_get_plugin_ctx(event);
enum session_event_type event_type = stellar_event_get_type(event);
const char *session_name = stellar_event_get_session_name(event);
struct stellar_packet *packet = stellar_event_get_packet(event);
uint16_t payload_len = stellar_event_get_payload_length(event);
const char *payload = stellar_event_get_payload(event);
switch (type)
assert(seesion);
assert(session_name);
// the same session may trigger multi times opening events
if (event_type & SESSION_EVENT_OPENING)
{
case SESSION_EVENT_OPENING:
plugin_manager_handle_opening_event(plug_mgr, event);
break;
case SESSION_EVENT_RAWPKT: /* fall through */
case SESSION_EVENT_ORDPKT: /* fall through */
case SESSION_EVENT_META: /* fall through */
plugin_manager_handle_data_event(plug_mgr, event);
break;
case SESSION_EVENT_CLOSING:
plugin_manager_handle_closing_event(plug_mgr, event);
break;
default:
// TODO log error
break;
if (plug_ctx == NULL)
{
plug_ctx = plugin_manager_create_plugin_ctx(plug_mgr, session_name);
if (plug_ctx == NULL)
{
plugin_manager_log(ERROR, "can't create runtime plugin ctx for session '%s', Please check whether the callback is registered in the current session");
return;
}
stellar_event_set_plugin_ctx(event, plug_ctx);
}
}
}
if (plug_ctx)
{
for (int i = 0; i < plug_ctx->eventcb_num; i++)
{
plug_ctx->current_plugin_index = i;
struct eventcb_runtime *runtime = &plug_ctx->eventcbs[i];
if (runtime->skip)
{
continue;
}
if (runtime->event & event_type)
{
runtime->cb(seesion, event_type, packet, payload, payload_len, &runtime->cb_args);
}
}
}
else
{
plugin_manager_log(ERROR, "session '%s' runtime plugin ctx is null when running event callback", session_name);
abort();
}
if (event_type & SESSION_EVENT_CLOSING)
{
plugin_manager_destory_plugin_ctx(plug_ctx);
stellar_event_set_plugin_ctx(event, NULL);
}
}
/******************************************************************************
* Suppport LUA plugins
******************************************************************************/
// TODO