From 964cb84864729e669b6276bb76d55aadaa943b4b Mon Sep 17 00:00:00 2001 From: Alexey Shchepin Date: Fri, 28 Nov 2008 16:06:39 +0000 Subject: [PATCH] * src/mod_muc/mod_muc_room.erl: Clean user activity after timeout (EJAB-804) SVN Revision: 1688 --- ChangeLog | 5 ++ src/mod_muc/mod_muc_room.erl | 153 ++++++++++++++++++++++++----------- 2 files changed, 111 insertions(+), 47 deletions(-) diff --git a/ChangeLog b/ChangeLog index 538b29dc5..41c44f958 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2008-11-28 Alexey Shchepin + + * src/mod_muc/mod_muc_room.erl: Clean user activity after timeout + (EJAB-804) + 2008-11-26 Badlop * src/ejabberdctl.template: Fix detection of ejabberdctl.cfg path diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index edd5912ea..0e13b21fc 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -103,7 +103,7 @@ subject = "", subject_author = "", just_created = false, - activity = ?DICT:new(), + activity = treap:empty(), room_shaper, room_queue = queue:new()}). @@ -243,13 +243,12 @@ normal_state({route, From, "", message_time = Now, message_shaper = MessageShaper}, StateData1 = - StateData#state{ - activity = ?DICT:store( - jlib:jid_tolower(From), - NewActivity, - StateData#state.activity), + store_user_activity( + From, NewActivity, StateData), + StateData2 = + StateData1#state{ room_shaper = RoomShaper}, - process_groupchat_message(From, Packet, StateData1); + process_groupchat_message(From, Packet, StateData2); true -> StateData1 = if @@ -270,13 +269,12 @@ normal_state({route, From, "", {message, From}, StateData#state.room_queue), StateData2 = - StateData1#state{ - activity = ?DICT:store( - jlib:jid_tolower(From), - NewActivity, - StateData#state.activity), + store_user_activity( + From, NewActivity, StateData1), + StateData3 = + StateData2#state{ room_queue = RoomQueue}, - {next_state, normal_state, StateData2} + {next_state, normal_state, StateData3} end; true -> MessageInterval = @@ -290,11 +288,8 @@ normal_state({route, From, "", message = Packet, message_shaper = MessageShaper}, StateData1 = - StateData#state{ - activity = ?DICT:store( - jlib:jid_tolower(From), - NewActivity, - StateData#state.activity)}, + store_user_activity( + From, NewActivity, StateData), {next_state, normal_state, StateData1} end; "error" -> @@ -436,12 +431,7 @@ normal_state({route, From, Nick, (Now >= Activity#activity.presence_time + MinPresenceInterval) and (Activity#activity.presence == undefined) -> NewActivity = Activity#activity{presence_time = Now}, - StateData1 = - StateData#state{ - activity = ?DICT:store( - jlib:jid_tolower(From), - NewActivity, - StateData#state.activity)}, + StateData1 = store_user_activity(From, NewActivity, StateData), process_presence(From, Nick, Packet, StateData1); true -> if @@ -454,12 +444,7 @@ normal_state({route, From, Nick, ok end, NewActivity = Activity#activity{presence = {Nick, Packet}}, - StateData1 = - StateData#state{ - activity = ?DICT:store( - jlib:jid_tolower(From), - NewActivity, - StateData#state.activity)}, + StateData1 = store_user_activity(From, NewActivity, StateData), {next_state, normal_state, StateData1} end; @@ -737,27 +722,25 @@ handle_info(process_room_queue, normal_state = StateName, StateData) -> Packet = Activity#activity.message, NewActivity = Activity#activity{message = undefined}, StateData1 = - StateData#state{ - activity = ?DICT:store( - jlib:jid_tolower(From), - NewActivity, - StateData#state.activity), + store_user_activity( + From, NewActivity, StateData), + StateData2 = + StateData1#state{ room_queue = RoomQueue}, - StateData2 = prepare_room_queue(StateData1), - process_groupchat_message(From, Packet, StateData2); + StateData3 = prepare_room_queue(StateData2), + process_groupchat_message(From, Packet, StateData3); {{value, {presence, From}}, RoomQueue} -> Activity = get_user_activity(From, StateData), {Nick, Packet} = Activity#activity.presence, NewActivity = Activity#activity{presence = undefined}, StateData1 = - StateData#state{ - activity = ?DICT:store( - jlib:jid_tolower(From), - NewActivity, - StateData#state.activity), + store_user_activity( + From, NewActivity, StateData), + StateData2 = + StateData1#state{ room_queue = RoomQueue}, - StateData2 = prepare_room_queue(StateData1), - process_presence(From, Nick, Packet, StateData2); + StateData3 = prepare_room_queue(StateData2), + process_presence(From, Nick, Packet, StateData3); {empty, _} -> {next_state, StateName, StateData} end; @@ -1284,9 +1267,9 @@ get_max_users_admin_threshold(StateData) -> mod_muc, max_users_admin_threshold, 5). get_user_activity(JID, StateData) -> - case ?DICT:find(jlib:jid_tolower(JID), - StateData#state.activity) of - {ok, A} -> A; + case treap:lookup(jlib:jid_tolower(JID), + StateData#state.activity) of + {ok, _P, A} -> A; error -> MessageShaper = shaper:new(gen_mod:get_module_opt( @@ -1300,6 +1283,82 @@ get_user_activity(JID, StateData) -> presence_shaper = PresenceShaper} end. +store_user_activity(JID, UserActivity, StateData) -> + MinMessageInterval = + gen_mod:get_module_opt( + StateData#state.server_host, + mod_muc, min_message_interval, 0), + MinPresenceInterval = + gen_mod:get_module_opt( + StateData#state.server_host, + mod_muc, min_presence_interval, 0), + Key = jlib:jid_tolower(JID), + Now = now_to_usec(now()), + Activity1 = clean_treap(StateData#state.activity, {1, -Now}), + Activity = + case treap:lookup(Key, Activity1) of + {ok, _P, _A} -> + treap:delete(Key, Activity1); + error -> + Activity1 + end, + StateData1 = + case (MinMessageInterval == 0) andalso + (MinPresenceInterval == 0) andalso + (UserActivity#activity.message_shaper == none) andalso + (UserActivity#activity.presence_shaper == none) andalso + (UserActivity#activity.message == undefined) andalso + (UserActivity#activity.presence == undefined) of + true -> + StateData#state{activity = Activity}; + false -> + case (UserActivity#activity.message == undefined) andalso + (UserActivity#activity.presence == undefined) of + true -> + {_, MessageShaperInterval} = + shaper:update(UserActivity#activity.message_shaper, + 100000), + {_, PresenceShaperInterval} = + shaper:update(UserActivity#activity.presence_shaper, + 100000), + Delay = lists:max([MessageShaperInterval, + PresenceShaperInterval, + MinMessageInterval * 1000, + MinPresenceInterval * 1000]) * 1000, + Priority = {1, -(Now + Delay)}, + StateData#state{ + activity = treap:insert( + Key, + Priority, + UserActivity, + Activity)}; + false -> + Priority = {0, 0}, + StateData#state{ + activity = treap:insert( + Key, + Priority, + UserActivity, + Activity)} + end + end, + StateData1. + +clean_treap(Treap, CleanPriority) -> + case treap:is_empty(Treap) of + true -> + Treap; + false -> + {_Key, Priority, _Value} = treap:get_root(Treap), + if + Priority > CleanPriority -> + clean_treap(treap:delete_root(Treap), CleanPriority); + true -> + Treap + end + end. + + prepare_room_queue(StateData) -> case queue:out(StateData#state.room_queue) of {{value, {message, From}}, _RoomQueue} ->