aboutsummaryrefslogtreecommitdiff
path: root/user_data.c
blob: f92d4d4749024b07675b712feb3f759910b4f017 (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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include <string.h>
#include <assert.h>
#include "user_data.h"
#include "util.h"


struct user_data{
	i64 userid;

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

struct hash_item{
	struct user_data data;
	struct hash_item *next;
};

#define USER_HASH_SIZE (16)
static struct hash_item *user_hash[USER_HASH_SIZE];


static struct hash_item* find_userdata(i64 userid){
	struct hash_item *item=user_hash[userid%USER_HASH_SIZE];
	while(item&&item->data.userid!=userid)item=item->next;
	return item;
}

static void remove_userdata(i64 userid){
	struct hash_item *item=user_hash[userid%USER_HASH_SIZE];
	assert(item);
	if(item->data.userid==userid){
		user_hash[userid%USER_HASH_SIZE]=item->next;
		free(item->data.fds);
		free(item);
		return;
	}
	struct hash_item *parent=NULL;
	while(item->data.userid!=userid){
		parent=item;
		item=item->next;
		assert(item);
	}
	parent->next=item->next;
	free(item->data.fds);
	free(item);
}

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

void userdata_unregister(i64 userid,int fd){
	struct hash_item *item=find_userdata(userid);
	if(!item){
		die("userdata_unregister(%" PRIi64 ", %d) while nonexistent",userid,fd);
	}
	i64 i;
	for(i=0;i<item->data.len;i++){
		if(item->data.fds[i]==fd)break;
	}
	if(i==item->data.len){
		die("userdata_unregister(%" PRIi64 ", %d) while nonexistent",userid,fd);
	}
	memmove(item->data.fds+i,item->data.fds+i+1,item->data.len-i-1);
	memmove(item->data.last_active+i,item->data.last_active+i+1,item->data.len-i-1);
	item->data.len--;
	if(item->data.len==0){
		remove_userdata(userid);
	}
}

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

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

bool userdata_is_active(i64 userid){
	struct hash_item *item=find_userdata(userid);
	if(!item)return false;
	i64 last=0;
	for(i64 i=0;i<item->data.len;i++){
		if(item->data.last_active[i]>last)last=item->data.last_active[i];
	}
	return make_timestamp()-last<2*60*1000*1000;
}

const int* userdata_online(i64 userid,i64 *nfds){
	struct hash_item *item=find_userdata(userid);
	if(!item){
		if(nfds)*nfds=0;
		return NULL;
	}
	assert(item->data.len!=0);
	if(nfds)*nfds=item->data.len;
	return item->data.fds;
}