diff options
-rw-r--r-- | Makefile | 10 | ||||
-rw-r--r-- | main.c | 26 | ||||
-rw-r--r-- | plugin.c | 79 | ||||
-rw-r--r-- | plugin.h | 7 | ||||
-rw-r--r-- | plugin_client_header.h | 26 | ||||
-rw-r--r-- | plugins/Makefile | 34 | ||||
-rw-r--r-- | plugins/log/main.c | 11 |
7 files changed, 172 insertions, 21 deletions
@@ -1,9 +1,13 @@ CC = gcc -CFLAGS = -Wall -Wextra -std=c11 -g -fwrapv -LDFLAGS = -lsqlite3 +CFLAGS = -Wall -Wextra -std=c11 -g -fwrapv -D_BSD_SOURCE +LDFLAGS = -lsqlite3 -ldl TARGETS = tomsg_server +PLUGINDIR = plugins + +PLUGINS = $(patsubst $(PLUGINDIR)/%,%,$(shell find $(PLUGINDIR)/ -maxdepth 1 -type d)) + .PHONY: all clean remake # Clear all implicit suffix rules @@ -13,9 +17,11 @@ TARGETS = tomsg_server .SECONDARY: all: $(TARGETS) + for pl in $(PLUGINS); do make --no-print-directory -C $(PLUGINDIR) $@ PLUGINNAME=$$pl; done clean: rm -f $(TARGETS) *.o *.sql.h + for pl in $(PLUGINS); do make --no-print-directory -C $(PLUGINDIR) $@ PLUGINNAME=$$pl; done remake: clean $(MAKE) all @@ -13,6 +13,7 @@ #include "db.h" #include "event.h" #include "net.h" +#include "plugin.h" #include "runloop.h" #include "user_data.h" @@ -146,34 +147,21 @@ void srandomdev(void){ } #endif -__attribute__((unused)) -static void dummy_event_handler(const struct event_item *event){ - switch(event->type){ - case EVENT_MESSAGE: - debug("event: <%s>@%s: %s",event->user,event->room,event->message); - break; - - case EVENT_ONLINE: - debug("event: <%s> online=%" PRIi64,event->user,event->num); - break; +int main(int argc,char **argv){ + srandomdev(); - case EVENT_JOIN: - debug("event: <%s> joins %s",event->user,event->room); - break; + plugin_init(); + for(int i=1;i<argc;i++){ + plugin_register(argv[i]); } -} - -int main(void){ - srandomdev(); + if(argc<=1)printf("Loaded no plugins\n"); db_init(); int sock=create_server_socket(); printf("Listening on port %d\n",PORT); - // event_register(dummy_event_handler); runloop_set_timeout(60*1000000,timeout_callback); runloop_add_fd(sock,server_socket_callback,false); runloop_run(); printf("Runloop empty, shutting down\n"); - // event_unregister(dummy_event_handler); db_close(); } diff --git a/plugin.c b/plugin.c new file mode 100644 index 0000000..14dce01 --- /dev/null +++ b/plugin.c @@ -0,0 +1,79 @@ +#include <stdio.h> +#include <string.h> +#include <dlfcn.h> +#include "event.h" +#include "global.h" +#include "plugin.h" +#include "plugin_client_header.h" + + +struct plugin_data{ + void *handle; + plugin_event_func_t *callback; +}; + +static i64 num_plugins=0; +static i64 plugins_cap=8; +static struct plugin_data *plugins_list=NULL; + + +static void consume_event(const struct event_item *event){ + struct plugin_event pe; + switch(event->type){ + case EVENT_MESSAGE: pe.type=PLUGIN_EVENT_MESSAGE; break; + case EVENT_ONLINE: pe.type=PLUGIN_EVENT_ONLINE; break; + case EVENT_JOIN: pe.type=PLUGIN_EVENT_JOIN; break; + default: + die("Unknown event type %d in plugin.c:consume_event",event->type); + } + pe.timestamp=event->timestamp; + pe.message=event->message; + pe.user=event->user; + pe.room=event->room; + pe.num=event->num; + + for(i64 i=0;i<num_plugins;i++){ + plugins_list[i].callback(&pe); + } +} + + +void plugin_init(void){ + if(plugins_list!=NULL)return; + plugins_list=malloc(plugins_cap,struct plugin_data); + memset(plugins_list,0,num_plugins*sizeof(struct plugin_data)); + + event_register(consume_event); +} + +void plugin_register(const char *fname){ + if(num_plugins==plugins_cap){ + plugins_cap*=2; + plugins_list=realloc(plugins_list,plugins_cap,struct plugin_data); + } + + struct plugin_data *data=plugins_list+num_plugins; + num_plugins++; + data->handle=dlopen(fname,RTLD_NOW|RTLD_LOCAL); + if(data->handle==NULL){ + die("Error loading plugin '%s': %s",fname,dlerror()); + } + + plugin_event_func_t* (*init_func)(void)=NULL; + dlerror(); + *(void**)&init_func=dlsym(data->handle,"plugin_init_func"); + char *err=dlerror(); + if(err!=NULL){ + die("Error reading symbol 'plugin_init_func' from plugin '%s'",fname); + } + if(init_func==NULL){ + die("Plugin '%s' exports NULL init function",fname); + } + + data->callback=init_func(); + if(data->callback==NULL){ + die("Init function of plugin '%s' returned NULL",fname); + } + + printf("Loaded plugin '%s'\n",fname); +} diff --git a/plugin.h b/plugin.h new file mode 100644 index 0000000..de235c9 --- /dev/null +++ b/plugin.h @@ -0,0 +1,7 @@ +#pragma once + + +void plugin_init(void); + +// Pass path to a shared object file / dynamic library +void plugin_register(const char *fname); diff --git a/plugin_client_header.h b/plugin_client_header.h new file mode 100644 index 0000000..4428b3c --- /dev/null +++ b/plugin_client_header.h @@ -0,0 +1,26 @@ +#pragma once + +#include <stdint.h> + + +enum plugin_event_type{ + PLUGIN_EVENT_MESSAGE, // message, user, room + PLUGIN_EVENT_ONLINE, // user, num + PLUGIN_EVENT_JOIN, // user, room +}; + +struct plugin_event{ + enum plugin_event_type type; + int64_t timestamp; // always set + char *message,*user,*room; + int64_t num; +}; + + +typedef void plugin_event_func_t(const struct plugin_event *event); + + +// All plugins should export a function of type plugin_init_func_t with +// name "plugin_init_func" that returns a pointer to a function that +// receives all events. +plugin_event_func_t* plugin_init_func(void); diff --git a/plugins/Makefile b/plugins/Makefile new file mode 100644 index 0000000..0824f2e --- /dev/null +++ b/plugins/Makefile @@ -0,0 +1,34 @@ +CC = gcc +CFLAGS = -Wall -Wextra -std=c11 -g -fwrapv -I.. -fPIC + +ifeq ($(shell uname),Darwin) + SO_EXT = dylib + SO_FLAGS = -dynamiclib +else + SO_EXT = so + SO_FLAGS = -shared +endif +SO_FLAGS += -fPIC + +TARGET = $(PLUGINNAME)/$(PLUGINNAME).$(SO_EXT) + + +.PHONY: all clean remake warning + +all: warning $(TARGET) + +clean: warning + rm -rf $(TARGET) $(PLUGINNAME)/*.{o,dSYM} + +remake: clean all + +warning: +ifndef PLUGINNAME + $(error "PLUGINNAME not set! Please run root Makefile instead.") +endif + + +.SECONDARY: + +$(PLUGINNAME)/%.$(SO_EXT): $(patsubst %.c,%.o,$(wildcard $(PLUGINNAME)/*.c)) $(wildcard ../*.h) + $(CC) $(SO_FLAGS) -o $@ $(filter %.o,$^) diff --git a/plugins/log/main.c b/plugins/log/main.c new file mode 100644 index 0000000..b931d12 --- /dev/null +++ b/plugins/log/main.c @@ -0,0 +1,11 @@ +#include <stdio.h> +#include "plugin_client_header.h" + + +static void eventfunc(const struct plugin_event *event){ + printf("type = %d\n",event->type); +} + +plugin_event_func_t* plugin_init_func(void){ + return eventfunc; +} |