diff options
| author | tomsmeding <tom.smeding@gmail.com> | 2017-04-15 18:09:48 +0200 | 
|---|---|---|
| committer | tomsmeding <tom.smeding@gmail.com> | 2017-04-15 18:58:34 +0200 | 
| commit | 8e1a1c1f01aef52ba8b2af47503461320a0abc20 (patch) | |
| tree | 58a10a92ae3ad8b26db8efb72ded1169d50537e9 | |
| parent | 393b27c556008d1ae4eaa7438fa8a376202b1c88 (diff) | |
server: Send _push online messages on online change
| -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); | 
