aboutsummaryrefslogtreecommitdiff
path: root/user_data.c
blob: 125a6b4d9c6295fcae5f9bc405a300a5d4d99b88 (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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <string.h>
#include <assert.h>
#include "user_data.h"
#include "util.h"
#include "hashtable.h"


struct user_data{
	i64 userid;

	int *fds;
	i64 *last_active;
	i64 cap,len;
};

static struct hashtable *user_hash=NULL;

__attribute__((constructor))
static void userdata_constructor() {
	user_hash = ht_alloc();
}

void userdata_register(i64 userid,int fd){
	struct user_data *data=ht_find(user_hash, userid);
	if(data){
		for(i64 i=0;i<data->len;i++){
			if(data->fds[i]==fd){
				die("userdata_register(%" PRIi64 ", %d) while pair already existed",userid,fd);
			}
		}
		if(data->len==data->cap){
			data->cap*=2;
			data->fds=realloc(data->fds,data->cap,int);
			data->last_active=realloc(data->last_active,data->cap,i64);
		}
		data->fds[data->len]=fd;
		data->last_active[data->len]=make_timestamp();
		data->len++;
	} else {
		data=malloc(1, struct user_data);
		data->userid=userid;
		data->cap=2;
		data->len=1;
		data->fds=malloc(data->cap,int);
		data->fds[0]=fd;
		data->last_active=malloc(data->cap,i64);
		data->last_active[0]=make_timestamp();
		ht_insert(user_hash,userid,data);
	}
}

void userdata_unregister(i64 userid,int fd){
	struct user_data *data=ht_find(user_hash,userid);
	if(!data){
		die("userdata_unregister(%" PRIi64 ", %d) while nonexistent",userid,fd);
	}
	i64 i;
	for(i=0;i<data->len;i++){
		if(data->fds[i]==fd)break;
	}
	if(i==data->len){
		die("userdata_unregister(%" PRIi64 ", %d) while nonexistent",userid,fd);
	}
	if(i<data->len-1){
		data->fds[i]=data->fds[data->len-1];
		data->last_active[i]=data->last_active[data->len-1];
	}
	data->len--;
	if(data->len==0){
		ht_delete(user_hash,userid);
	}
}

void userdata_mark_active(i64 userid,int fd,bool active){
	struct user_data *data=ht_find(user_hash,userid);
	if(!data){
		die("userdata_mark_active(%" PRIi64 ", %d, %d) with nonexistent userid",userid,fd,active);
	}
	i64 i;
	for(i=0;i<data->len;i++){
		if(data->fds[i]==fd)break;
	}
	if(i==data->len){
		die("userdata_mark_active(%" PRIi64 ", %d, %d) while nonexistent",userid,fd,active);
	}

	data->last_active[i]=active?make_timestamp():-1;
}

bool userdata_is_active(i64 userid){
	const struct user_data *data=ht_find(user_hash,userid);
	if(!data)return false;
	i64 last=0;
	for(i64 i=0;i<data->len;i++){
		if(data->last_active[i]>last)last=data->last_active[i];
	}
	return make_timestamp()-last<2*60*1000*1000;
}

const int* userdata_online(i64 userid,i64 *nfds){
	const struct user_data *data=ht_find(user_hash,userid);
	if(!data){
		if(nfds)*nfds=0;
		return NULL;
	}
	assert(data->len!=0);
	if(nfds)*nfds=data->len;
	return data->fds;
}