aboutsummaryrefslogtreecommitdiff
path: root/broadcast.c
blob: 2970b544ca111ee6b0db436213134c15096c8660 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <string.h>
#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.
// 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);

	event_emit_online(make_timestamp(),name,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);
}