diff options
-rw-r--r-- | broadcast.c | 89 | ||||
-rw-r--r-- | broadcast.h | 6 | ||||
-rw-r--r-- | command.c | 3 | ||||
-rw-r--r-- | main.c | 11 |
4 files changed, 107 insertions, 2 deletions
diff --git a/broadcast.c b/broadcast.c new file mode 100644 index 0000000..0517dc3 --- /dev/null +++ b/broadcast.c @@ -0,0 +1,89 @@ +#include <string.h> +#include "broadcast.h" +#include "db.h" +#include "net.h" +#include "user_data.h" + + +// Returns whether value was new and therefore inserted into the list. +// If already present, does nothing and returns false. +// Assumes enough space for the possible new item. +static bool sorted_insert(i64 *buf,i64 len,i64 value){ + if(len==0){ + buf[0]=value; + return true; + } + i64 L=0,H=len-1; + if(buf[L]==value||buf[H]==value)return false; + if(value<buf[L]){ + memmove(buf+1,buf,len*sizeof(i64)); + buf[0]=value; + return true; + } + if(value>buf[H]){ + buf[len]=value; + return true; + } + while(L<H){ + i64 M=L+(H-L)/2; + if(buf[M]==value)return false; + if(buf[M]<value){ + L=M+1; + if(buf[L]>value)break; + } else if(buf[M]>value){ + H=M-1; + if(buf[H]<value){ + L=M; + break; + } + } + } + if(buf[L]==value)return false; + // We insert left of L + memmove(buf+L+1,buf+L,len-L); + buf[L]=value; + return true; +} + +void broadcast_online_change(i64 userid){ + i64 seencap=16,seenlen=0; + i64 *seen=malloc(seencap,i64); + + struct db_room_list rooms=db_list_rooms(userid); + for(i64 i=0;i<rooms.count;i++){ + struct db_user_list members=db_list_members(rooms.list[i].id); + for(i64 j=0;j<members.count;j++){ + if(members.list[j].id==userid)continue; + i64 nfds; + (void)userdata_online(members.list[j].id,&nfds); + if(nfds==0)continue; + if(seenlen==seencap){ + seencap*=2; + seen=realloc(seen,seencap,i64); + } + bool inserted=sorted_insert(seen,seenlen,members.list[j].id); + seenlen+=inserted; + } + db_nullify_user_list(members); + } + db_nullify_room_list(rooms); + + char *name=db_get_username(userid); + i64 numonline; + (void)userdata_online(userid,&numonline); + + char *buf; + i64 len=asprintf(&buf,"_push online %" PRIi64 " %s\n",numonline,name); + free(name); + + for(i64 i=0;i<seenlen;i++){ + i64 nfds; + const int *fds=userdata_online(seen[i],&nfds); + for(i64 j=0;j<nfds;j++){ + net_send_raw_text(fds[j],buf,len); + } + } + + free(buf); + free(seen); +} diff --git a/broadcast.h b/broadcast.h new file mode 100644 index 0000000..6ad5aad --- /dev/null +++ b/broadcast.h @@ -0,0 +1,6 @@ +#pragma once + +#include "global.h" + + +void broadcast_online_change(i64 userid); @@ -4,6 +4,7 @@ #include <errno.h> #include <sys/time.h> #include <sys/socket.h> +#include "broadcast.h" #include "command.h" #include "db.h" #include "net.h" @@ -38,11 +39,13 @@ static bool cmd_login(struct conn_data *data,const char *tag,const char **args){ free(pass); if(data->userid!=-1){ userdata_unregister(data->userid,data->fd); + broadcast_online_change(data->userid); } if(success){ data->userid=userid; userdata_register(userid,data->fd); net_send_ok(data->fd,tag); + broadcast_online_change(userid); } else { data->userid=-1; net_send_error(data->fd,tag,"Incorrect password"); @@ -7,6 +7,7 @@ #include <netinet/in.h> #include <errno.h> #include <assert.h> +#include "broadcast.h" #include "command.h" #include "conn_data.h" #include "db.h" @@ -53,7 +54,10 @@ static void delete_conn_data(int fd){ struct hash_item *item=conn_hash[fd%CONN_HASH_SIZE]; assert(item); if(item->cd.fd==fd){ - if(item->cd.userid!=-1)userdata_unregister(item->cd.userid,fd); + if(item->cd.userid!=-1){ + userdata_unregister(item->cd.userid,fd); + broadcast_online_change(item->cd.userid); + } conn_hash[fd%CONN_HASH_SIZE]=item->next; conn_data_nullify(&item->cd); free(item); @@ -66,7 +70,10 @@ static void delete_conn_data(int fd){ } assert(parent); assert(item); - if(item->cd.userid!=-1)userdata_unregister(item->cd.userid,fd); + if(item->cd.userid!=-1){ + userdata_unregister(item->cd.userid,fd); + broadcast_online_change(item->cd.userid); + } conn_data_nullify(&item->cd); parent->next=item->next; free(item); |