我在 linux 机器上使用源代码中的 ejabberd-17.03。
我使用用户 A 的 jid 从服务器以编程方式创建了一个临时聊天室,并向用户 B 发送直接邀请,他接受并加入聊天室。
我的用例是两个用户 A 和 B 在聊天室交换消息。如果在 30 秒内没有用户向其他用户发送任何消息,则房间会向这两个用户发送随机选择的消息。
我已经实现了如下:
start(_Host, _Opts) ->
ejabberd_hooks:add(user_send_packet, _Host, ?MODULE, myMessage, 95).
stop(_Host) ->
ejabberd_hooks:delete(user_send_packet, _Host, ?MODULE, myMessage,95).
depends(_Host, _Opts)->[{?MODULE,soft}].
mod_opt_type(_Option)->
ok.
myMessage({#message{from = From, to = To, body= Body} =Packet, C2SState}) ->
{UserA,UserB}=select_user(Packet),
PacketType=returnPacketType(Packet),
if
(PacketType==normal) ->
dosomething(),
{Timer_Result,Ref_or_Reason} = timer:apply_interval(30000, ?MODULE, func(), [Arguments]),
if
(Timer_Result == ok)->
ets:insert(ref_table, {Key, Ref_or_Reason});
(Timer_Result == error)->
io:format(" Could not delete user after timeout, Reason is ~p~n",[Ref_or_Reason])
end;
(PacketType==groupchat)->
do_something_else(),
{Timer_Result,Ref_or_Reason} = timer:apply_interval(30000, ?MODULE, func(), [Arguments]),
if
(Timer_Result == ok)->
replace_old_ref_with_new(Key, Ref_or_Reason, ref_table);
(Timer_Result == error)->
io:format(" Could not delete user after timeout, Reason is ~p~n",[Ref_or_Reason])
end
end
if
(somecondition()==true)->
delete_ref(Key, ref_table);
True->
do_nothing
end,
{Packet, C2SState}.
现在一切正常,除了以下情况:
1.Chatroom 已创建,A 和 B 之间开始交换消息,此时计时器也开始。
如果创建聊天室的用户在时间 T 下线(通过最小化应用程序并从 android 设备中杀死它)并重新上线,则计时器停止,如计划在 30 秒结束时调用的函数一样't 被调用。(此处重新联机突出显示,因为如果用户未联机,则计时器按预期工作,只有当用户再次联机时,计时器停止并且不生成日志)。
但是,如果在线用户现在在 T 点发送任何消息,那么随机选择消息并将它们发送给客户端的整个周期性操作会再次很好地开始并很好地结束。
但是如果在线用户在这个时间点 T 没有发送任何消息,那么调度的计时器永远不会被调用,用户将继续等待。
如果被邀请加入聊天室的用户在时间 T2 下线(比如 2 中的方式)并再次上线,则计时器保持活动状态并按预期工作。
因此,我将 ejabberd 的日志记录级别更改为 5,并看到离线消息未传递给离线和再次在线用户。即使在 ejabberd.yml 中启用了 mod_offline。
日志 :
#message{
id = <<>>,type = error,lang = <<"en">>,
from =
{jid,<<"fWiTvj973AB”>>,<<“example.com">>,<<"Smack">>,<<"fwitvj973ab”>>,
<<"example.com">>,<<"Smack">>},
to =
{jid,<<"ac5a6b8c-66b8-4da7-8b1a-0f3ecb1e5gfd”>>,
<<"conference.example.com">>,<<"cXWmOrqEESd”>>,
<<"ac5a6b8c-66b8-4da7-8b1a-0f3ecb1e5gfd">>,
<<"conference.example.com">>,<<"cXWmOrqEESd">>},
subject = [#text{lang = <<>>,data = <<>>}],
body = [#text{lang = <<>>,data = <<"\"cXWmOrqEESd\"">>}],
thread = undefined,
sub_els =
[{xmlel,<<"q">>,[{<<"xmlns">>,<<"ns:custom”>>}],[]},
#stanza_error{
type = cancel,code = 503,by = <<>>,
reason = 'service-unavailable',
text =
#text{lang = <<"en">>,data = <<"User session terminated">>},
sub_els = []}],
meta = #{}}
ejabberd.yml
###. ============
###' SHAPER RULES
shaper_rules:
## Maximum number of offline messages that users can have:
max_user_offline_messages:
- 5000: admin
- 100
###. =======
###' MODULES
##
## Modules enabled in all ejabberd virtual hosts.
##
modules:
mod_offline:
db_type: sql
access_max_user_messages: max_user_offline_messages
store_empty_body: unless_chat_state
虽然我不需要完美地传递这些离线消息,但我倾向于认为这是否可能是停止我的计时器的原因(但我不明白为什么它只在创建的用户时停止房间下线然后又回来了,当其他用户这样做时为什么不呢?)。
为什么这个计时器会停止,我怎样才能让它定期运行?