From 5921f9c506f2a2c11160a7465a70a24d3cb2be5f Mon Sep 17 00:00:00 2001 From: Maxim Ignatenko Date: Thu, 28 Jul 2011 20:40:46 +0300 Subject: [PATCH] Simple rate control Visitor allowed to send new voice request only after specified amount of time (or after rejoining). --- src/mod_muc/mod_muc_room.erl | 67 ++++++++++++++++++++++++++++++------ src/mod_muc/mod_muc_room.hrl | 1 + 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index 3e61f80d8..c54af83d2 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -298,23 +298,39 @@ normal_state({route, From, "", end end; IsVoiceRequest -> - case is_visitor(From, StateData) of + NewStateData = case is_visitor(From, StateData) of true -> - send_voice_request(From, StateData); + MinInterval = 1800, + FromNick = find_nick_by_jid(From, StateData), + LastTime = last_voice_request_time(FromNick, StateData), + {MegaSecs, Secs, _} = erlang:now(), + Now = MegaSecs * 1000000 + Secs, + if + timer:now_diff(LastTime, erlang:now()) > MinInterval*1000000 -> + send_voice_request(From, StateData), + update_voice_request_time(FromNick, StateData); + true -> + ErrText = "Please, wait for a while before sending new voice request", + Err = jlib:make_error_reply( + Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), + ejabberd_router:route( + StateData#state.jid, From, Err), + StateData + end; _ -> ErrText = "Only visitors allowed to request voice", Err = jlib:make_error_reply( Packet, ?ERRT_NOT_ALLOWED(Lang, ErrText)), ejabberd_router:route( - StateData#state.jid, From, Err) + StateData#state.jid, From, Err), + StateData end, - {next_state, normal_state, StateData}; + {next_state, normal_state, NewStateData}; IsVoiceApprovement -> NewStateData = case is_moderator(From, StateData) of true -> case extract_jid_from_voice_approvement(Els) of {error, X} -> - ?ERROR_MSG("Failed to extract JID from voice approvement: ~n~p", [X]), ErrText = "Failed to extract JID from your voice request approvement", Err = jlib:make_error_reply( Packet, ?ERRT_BAD_REQUEST(Lang, ErrText)), @@ -1533,7 +1549,9 @@ remove_online_user(JID, StateData, Reason) -> error -> StateData#state.nicks end, - StateData#state{users = Users, nicks = Nicks}. + LastTimes = ?DICT:erase(Nick, StateData#state.last_voice_request_time), + StateData#state{users = Users, nicks = Nicks, + last_voice_request_time = LastTimes}. filter_presence({xmlelement, "presence", Attrs, Els}) -> @@ -1641,6 +1659,12 @@ get_priority_from_presence(PresencePacket) -> end end. +find_nick_by_jid(Jid, StateData) -> + [{_, #user{nick = Nick}}] = lists:filter( + fun({_, #user{jid = FJid}}) -> FJid == Jid end, + ?DICT:to_list(StateData#state.users)), + Nick. + is_nick_change(JID, Nick, StateData) -> LJID = jlib:jid_tolower(JID), case Nick of @@ -2169,7 +2193,18 @@ change_nick(JID, Nick, StateData) -> ?DICT:store(OldNick, OldNickUsers -- [LJID], StateData#state.nicks)) end, - NewStateData = StateData#state{users = Users, nicks = Nicks}, + LastTimes = + case ?DICT:find(OldNick, StateData#state.last_voice_request_time) of + {ok, Time} -> + ?DICT:store( + Nick, Time, + ?DICT:erase(OldNick, StateData#state.last_voice_request_time) + ); + error -> + StateData#state.last_voice_request_time + end, + NewStateData = StateData#state{users = Users, nicks = Nicks, + last_voice_request_time = LastTimes}, send_nick_changing(JID, OldNick, NewStateData, SendOldUnavailable, SendNewAvailable), add_to_log(nickchange, {OldNick, Nick}, StateData), NewStateData. @@ -3737,9 +3772,7 @@ prepare_request_form(Requester, Nick, Lang) -> send_voice_request(From, StateData) -> Moderators = search_role(moderator, StateData), - [{_, #user{nick = FromNick}}] = lists:filter( - fun({_, #user{jid = Jid}}) -> Jid == From end, - ?DICT:to_list(StateData#state.users)), + FromNick = find_nick_by_jid(From, StateData), lists:map( fun({_, User}) -> ejabberd_router:route( @@ -3826,6 +3859,20 @@ extract_jid_from_voice_approvement(Els) -> {error, X} end. +last_voice_request_time(Nick, StateData) -> + case ?DICT:find(Nick, StateData#state.last_voice_request_time) of + {ok, Value} -> + Value; + error -> + 0 + end. + +update_voice_request_time(Nick, StateData) -> + {MegaSecs, Secs, _} = erlang:now(), + Time = MegaSecs * 1000000 + Secs, + NewDict = ?DICT:store(Nick, Time, StateData#state.last_voice_request_time), + StateData#state{last_voice_request_time = NewDict}. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Invitation support diff --git a/src/mod_muc/mod_muc_room.hrl b/src/mod_muc/mod_muc_room.hrl index 10120cba6..abbc1870e 100644 --- a/src/mod_muc/mod_muc_room.hrl +++ b/src/mod_muc/mod_muc_room.hrl @@ -69,6 +69,7 @@ jid, config = #config{}, users = ?DICT:new(), + last_voice_request_time = ?DICT:new(), robots = ?DICT:new(), nicks = ?DICT:new(), affiliations = ?DICT:new(),