aboutsummaryrefslogtreecommitdiff
path: root/plugin_registry.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugin_registry.c')
-rw-r--r--plugin_registry.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/plugin_registry.c b/plugin_registry.c
new file mode 100644
index 0000000..b6b0dbd
--- /dev/null
+++ b/plugin_registry.c
@@ -0,0 +1,256 @@
+#include "plugins.h"
+#include "plugin_registry.h"
+#include "rcon_host.h"
+#include "common.h"
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#define PLUGIN_ID_GEN_MAX_RETRY 1
+
+static int plugin_count = 0;
+static struct plugin *plugin_arr = NULL;
+static pthread_key_t key_plugin;
+
+static int plugin_generate_id()
+{
+ int retry_count = 0;
+ goto gen;
+gen:
+ if(retry_count > PLUGIN_ID_GEN_MAX_RETRY) return -1;
+ int rand_val = rand();
+ for(int i = 0; i < plugin_count; i ++)
+ {
+ if(plugin_get_by_index(i)->id == rand_val)
+ {
+ retry_count ++;
+ goto gen;
+ }
+ }
+ return rand_val;
+}
+
+static void arr_resize(int new_size)
+{
+ if(new_size == 0)
+ {
+ if(plugin_arr != NULL)
+ {
+ free(plugin_arr);
+ plugin_arr = NULL;
+ }
+ return;
+ }
+ if(plugin_arr == NULL)
+ plugin_arr = calloc(new_size, sizeof(struct plugin));
+ else
+ plugin_arr = realloc(plugin_arr, new_size * sizeof(struct plugin));
+}
+
+int plugin_registry_init()
+{
+ pthread_key_create(&key_plugin, NULL);
+ return 0;
+}
+
+void plugin_registry_free()
+{
+ plugin_count = 0;
+ arr_resize(0);
+ pthread_key_delete(key_plugin);
+}
+
+int plugin_size()
+{
+ return plugin_count;
+}
+
+static int plugin_id_to_index(int id)
+{
+ for(int i = 0; i < plugin_count; i ++)
+ {
+ if(plugin_arr[i].id == id)
+ return i;
+ }
+ return -1;
+}
+
+struct plugin *plugin_get(int id)
+{
+ const int index = plugin_id_to_index(id);
+ if(index < 0)
+ return NULL;
+ return &plugin_arr[index];
+}
+
+struct plugin *plugin_get_by_index(int index)
+{
+ return &plugin_arr[index];
+}
+
+int plugin_registry_unload(int stderr_fd, int id)
+{
+ int r = 0;
+ const int index = plugin_id_to_index(id);
+ if(index < 0)
+ {
+ r = EPLUGINNOTFOUND;
+ goto cleanup;
+ }
+ struct plugin *plug = plugin_get_by_index(index);
+ r = plugin_unload(stderr_fd, plug);
+ if(r) goto cleanup;
+ memcpy(plug, &plugin_arr[index + 1], (plugin_count - 1 - index) * sizeof(struct plugin));
+ arr_resize(-- plugin_count);
+ goto cleanup;
+cleanup:
+ return r;
+}
+
+int plugin_registry_load(int stderr_fd, const char *path, int *id)
+{
+ int r = 0;
+ const int id_gen = plugin_generate_id();
+ if(id_gen <= 0)
+ {
+ r = EPLUGINEXCEED;
+ goto cleanup;
+ }
+ arr_resize(++ plugin_count);
+ r = plugin_load(stderr_fd, path, id_gen, &plugin_arr[plugin_count - 1]);
+ if(r)
+ {
+ arr_resize(-- plugin_count);
+ goto cleanup;
+ }
+ *id = id_gen;
+ goto cleanup;
+cleanup:
+ return r;
+}
+
+static int api_rcon_send_wrapper(int pkt_id, char *command)
+{
+ int r = 0;
+ const struct plugin *plug = pthread_getspecific(key_plugin);
+ printf(_("[rcon#%d] -> '%s' (%d)\n"),
+ plug->id,
+ command,
+ pkt_id);
+ // TODO: The plugin identity may have future usages.
+ r = rcon_host_send(pkt_id, command);
+ if(r) goto cleanup;
+cleanup:
+ return r;
+}
+
+static int api_rcon_recv_wrapper(int *pkt_id, char *out)
+{
+ int r = 0;
+ const struct plugin *plug = pthread_getspecific(key_plugin);
+ // TODO: The plugin identity may have future usages.
+ r = rcon_host_recv(pkt_id, out);
+ if(!r)
+ printf(_("[rcon#%d] <- %s (%d)\n"),
+ plug->id,
+ out,
+ *pkt_id);
+ if(r) goto cleanup;
+cleanup:
+ return r;
+}
+
+void plugcall_setup_handle(struct plugin *plugin, struct epg_handle *handle)
+{
+ pthread_setspecific(key_plugin, plugin);
+ handle->id = plugin->id;
+ handle->rcon_send = &api_rcon_send_wrapper;
+ handle->rcon_recv = &api_rcon_recv_wrapper;
+}
+
+#define PLUGCALL_PRE(X) \
+ struct epg_handle handle; \
+ struct plugin_call_job_args *args = arg; \
+ struct plugin *plugin = plugin_get_by_index(args->id); \
+ plugcall_setup_handle(plugin, &handle);
+
+#define PLUGCALL_POST(X) \
+ if(args->arg1 != NULL) free(args->arg1); \
+ if(args->arg2 != NULL) free(args->arg2); \
+ if(args->arg3 != NULL) free(args->arg3); \
+ if(args->arg4 != NULL) free(args->arg4); \
+ if(args->arg5 != NULL) free(args->arg5); \
+ free(args);
+
+void plugcall_player_join(void *arg)
+{
+ PLUGCALL_PRE(arg)
+ plugin->fc_player_join(&handle, args->arg1);
+ PLUGCALL_POST(arg)
+}
+
+void plugcall_player_leave(void *arg)
+{
+ PLUGCALL_PRE(arg)
+ plugin->fc_player_leave(&handle, args->arg1, args->arg2);
+ PLUGCALL_POST(arg)
+}
+
+void plugcall_player_achievement(void *arg)
+{
+ PLUGCALL_PRE(arg)
+ plugin->fc_player_achievement(&handle, args->arg1, args->arg2);
+ PLUGCALL_POST(arg)
+}
+
+void plugcall_player_challenge(void *arg)
+{
+ PLUGCALL_PRE(arg)
+ plugin->fc_player_challenge(&handle, args->arg1, args->arg2);
+ PLUGCALL_POST(arg)
+}
+
+void plugcall_player_goal(void *arg)
+{
+ PLUGCALL_PRE(arg)
+ plugin->fc_player_goal(&handle, args->arg1, args->arg2);
+ PLUGCALL_POST(arg)
+}
+
+void plugcall_player_say(void *arg)
+{
+ PLUGCALL_PRE(arg)
+ plugin->fc_player_say(&handle, args->arg1, args->arg2);
+ PLUGCALL_POST(arg)
+}
+
+void plugcall_player_die(void *arg)
+{
+ PLUGCALL_PRE(arg)
+ plugin->fc_player_die(&handle, args->arg1, args->arg2);
+ PLUGCALL_POST(arg)
+}
+
+void plugcall_server_stopping(void *arg)
+{
+ PLUGCALL_PRE(arg)
+ plugin->fc_server_stopping(&handle);
+ PLUGCALL_POST(arg)
+}
+
+void plugcall_server_starting(void *arg)
+{
+ PLUGCALL_PRE(arg)
+ plugin->fc_server_starting(&handle, args->arg1);
+ PLUGCALL_POST(arg)
+}
+
+void plugcall_server_started(void *arg)
+{
+ PLUGCALL_PRE(arg)
+ plugin->fc_server_started(&handle, args->arg1);
+ PLUGCALL_POST(arg)
+}