【发布时间】:2019-01-27 07:33:01
【问题描述】:
我在 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 和 A 之间开始交换消息 B 和计时器也在此时开始。
-
如果创建聊天室的用户在时间 T 下线(通过最小化应用程序并从 android 设备中杀死它)然后重新上线,则计时器停止,如预定的功能在 30 秒结束时调用不会被调用。(此处重新联机突出显示,因为如果用户未联机,则计时器按预期工作,只有当用户再次联机时,计时器才会停止并且不生成日志)。
但是如果在线用户现在在 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
虽然我不需要完美地传递这些离线消息,但我倾向于认为这是否可能是停止我的计时器的原因(但我不明白为什么它只在创建房间的用户下线后又回来了,当其他用户这样做时为什么不呢?)。
为什么这个计时器会停止,我怎样才能让它定期运行?
【问题讨论】:
-
你有多少在线用户?
-
我只处于开发阶段,所以只有 2 或 4 个用户,即当有 2 个用户时有一个聊天室,当有 4 个用户时有两个聊天室。但问题在 1 个聊天室或 2 个单独的聊天室中仍然存在。
标签: android erlang ejabberd smack ejabberd-hooks