#include #include #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;idata.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;idata.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;idata.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;idata.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; }