From a7a0ce278e661bf5d3f2b47556d8c30469d2bd6c Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Mon, 8 May 2017 22:06:47 +0200 Subject: server: Add event system --- broadcast.c | 4 +++ command.c | 5 ++++ event.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ event.h | 31 +++++++++++++++++++ main.c | 20 +++++++++++++ 5 files changed, 159 insertions(+) create mode 100644 event.c create mode 100644 event.h diff --git a/broadcast.c b/broadcast.c index 0517dc3..2970b54 100644 --- a/broadcast.c +++ b/broadcast.c @@ -1,8 +1,10 @@ #include #include "broadcast.h" #include "db.h" +#include "event.h" #include "net.h" #include "user_data.h" +#include "util.h" // Returns whether value was new and therefore inserted into the list. @@ -72,6 +74,8 @@ void broadcast_online_change(i64 userid){ i64 numonline; (void)userdata_online(userid,&numonline); + event_emit_online(make_timestamp(),name,numonline); + char *buf; i64 len=asprintf(&buf,"_push online %" PRIi64 " %s\n",numonline,name); free(name); diff --git a/command.c b/command.c index b0b9a26..0ae7fa3 100644 --- a/command.c +++ b/command.c @@ -7,6 +7,7 @@ #include "broadcast.h" #include "command.h" #include "db.h" +#include "event.h" #include "net.h" #include "user_data.h" #include "util.h" @@ -160,6 +161,8 @@ static bool cmd_invite(struct conn_data *data,const char *tag,const char **args) char *invitebuf=NULL; i64 invitebuflen=asprintf(&invitebuf,"_push invite %s\n",roomname); + event_emit_join(make_timestamp(),username,roomname); + struct db_user_list members=db_list_members(roomid); for(i64 i=0;iuserid); i64 pushbuflen=asprintf(&pushbuf,"_push message %s %s %" PRIi64 " %s\n", roomname,username,timestamp,message); + + event_emit_message(timestamp,message,username,roomname); free(username); struct db_user_list members=db_list_members(roomid); diff --git a/event.c b/event.c new file mode 100644 index 0000000..40eaff8 --- /dev/null +++ b/event.c @@ -0,0 +1,99 @@ +#include +#include "event.h" + + +struct cbs_chain{ + event_callback_t *cb; + struct cbs_chain *prev,*next; +}; + +struct cbs_chain *callbacks=NULL,*callbacks_last=NULL; + + +static struct cbs_chain* find_chain_item(event_callback_t *cb){ + struct cbs_chain *item=callbacks; + while(item&&item->cb!=cb)item=item->next; + return item; +} + + +void event_register(event_callback_t *cb){ + struct cbs_chain *item=find_chain_item(cb); + if(item!=NULL){ + debug("event_register: callback %p already registered!",cb); + return; + } + item=malloc(1,struct cbs_chain); + item->cb=cb; + item->prev=item->next=NULL; + if(callbacks){ + item->prev=callbacks_last; + callbacks_last->next=item; + callbacks_last=item; + } else { + callbacks=callbacks_last=item; + } +} + +void event_unregister(event_callback_t *cb){ + struct cbs_chain *item=find_chain_item(cb); + if(item==NULL){ + debug("event_unregister: callback %p was not registered!",cb); + return; + } + if(item->prev)item->prev->next=item->next; + if(item->next)item->next->prev=item->prev; + if(callbacks==item)callbacks=item->next; + if(callbacks_last==item)callbacks_last=item->prev; + free(item); +} + +struct event_item* event_item_alloc(void){ + struct event_item *event=malloc(1,struct event_item); + memset(event,0,sizeof(struct event_item)); + return event; +} + +void event_item_free(struct event_item *event){ + if(event->message)free(event->message); + if(event->user)free(event->user); + if(event->room)free(event->room); + free(event); +} + +void event_emit(const struct event_item *event){ + for(struct cbs_chain *item=callbacks;item!=NULL;item=item->next){ + item->cb(event); + } +} + +void event_emit_message(i64 timestamp,const char *message,const char *user,const char *room){ + struct event_item *event=event_item_alloc(); + event->type=EVENT_MESSAGE; + event->timestamp=timestamp; + event->message=strdup(message); + event->user=strdup(user); + event->room=strdup(room); + event_emit(event); + event_item_free(event); +} + +void event_emit_online(i64 timestamp,const char *user,i64 numonline){ + struct event_item *event=event_item_alloc(); + event->type=EVENT_ONLINE; + event->timestamp=timestamp; + event->user=strdup(user); + event->num=numonline; + event_emit(event); + event_item_free(event); +} + +void event_emit_join(i64 timestamp,const char *user,const char *room){ + struct event_item *event=event_item_alloc(); + event->type=EVENT_JOIN; + event->timestamp=timestamp; + event->user=strdup(user); + event->room=strdup(room); + event_emit(event); + event_item_free(event); +} diff --git a/event.h b/event.h new file mode 100644 index 0000000..638cd20 --- /dev/null +++ b/event.h @@ -0,0 +1,31 @@ +#pragma once + +#include "global.h" + + +enum event_type{ + EVENT_MESSAGE, // message, user, room + EVENT_ONLINE, // user, num + EVENT_JOIN, // user, room +}; + +struct event_item{ + enum event_type type; + i64 timestamp; // always set + char *message,*user,*room; + i64 num; +}; + +typedef void event_callback_t(const struct event_item *event); + + +void event_register(event_callback_t *cb); +void event_unregister(event_callback_t *cb); + +struct event_item* event_item_alloc(void); +void event_item_free(struct event_item *event); + +void event_emit(const struct event_item *event); +void event_emit_message(i64 timestamp,const char *message,const char *user,const char *room); +void event_emit_online(i64 timestamp,const char *user,i64 numonline); +void event_emit_join(i64 timestamp,const char *user,const char *room); diff --git a/main.c b/main.c index 5afece8..a754f02 100644 --- a/main.c +++ b/main.c @@ -11,6 +11,7 @@ #include "command.h" #include "conn_data.h" #include "db.h" +#include "event.h" #include "net.h" #include "runloop.h" #include "user_data.h" @@ -145,15 +146,34 @@ 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; + + case EVENT_JOIN: + debug("event: <%s> joins %s",event->user,event->room); + break; + } +} + int main(void){ srandomdev(); 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(); } -- cgit v1.2.3-70-g09d2