offline_message_hook
仅当服务器将消息路由给不在线的用户时才调用。user_send_packet
每次服务器从客户端接收到节时运行。这可以解释为什么处理程序没有运行,尽管它取决于您如何测试。官方 wiki 上有一篇文章,其中一节描述了 MongooseIM 中的一些钩子。
至于检索数据包属性的问题,要么记录传入的数据包以供检查,要么dbg
在服务器 Erlang shell 中使用来跟踪模块完成的实际调用,这可能是判断发生了什么的方法。
调试问题的示例会话dbg
可能如下所示:
(mongooseim@localhost)1> dbg:tracer().
{ok,<0.570.0>}
(mongooseim@localhost)2> dbg:p(all, call).
{ok,[{matched,mongooseim@localhost,279}]}
(mongooseim@localhost)3> dbg:tpl(mod_test, x).
{ok,[{matched,mongooseim@localhost,5},{saved,x}]}
(mongooseim@localhost)4> (<0.576.0>) call mod_test:fetchPacketData({jid,<<"alice">>,<<"localhost">>,<<"escalus-default-resource">>,<<"alice">>,
<<"localhost">>,<<"escalus-default-resource">>},{jid,<<"alice">>,<<"localhost">>,<<>>,<<"alice">>,<<"localhost">>,<<>>},{xmlel,<<"presence">>,[{<<"xml:lang">>,<<"en">>}],[]})
(<0.576.0>) exception_from {mod_test,fetchPacketData,3} {error,function_clause}
2015-03-15 11:46:03.028 [error] <0.576.0>@ejabberd_hooks:run1:240 {function_clause,[{lists,thing_to_list,[<<>>],[{file,"lists.erl"},{line,601}]},{lists,flatmap,2,[{file,"lists.erl"},{line,1248}]},{lists,flatmap,2,[{file,"lists.erl"},{line,1248}]},{mod_test,fetchPacketData,3,[{file,"src/mod_test.erl"},{line,15}]},{safely,apply,3,[{file,"src/safely.erl"},{line,19}]},{ejabberd_hooks,run1,3,[{file,"src/ejabberd_hooks.erl"},{line,236}]},{ejabberd_c2s,session_established2,2,[{file,"src/ejabberd_c2s.erl"},{line,1063}]},{p1_fsm_old,handle_msg,10,[{file,"src/p1_fsm_old.erl"},{line,542}]}]}
Running hook: {user_send_packet,[{jid,<<"alice">>,<<"localhost">>,<<"escalus-default-resource">>,<<"alice">>,<<"localhost">>,<<"escalus-default-resource">>},{jid,<<"alice">>,<<"localhost">>,<<>>,<<"alice">>,<<"localhost">>,<<>>},{xmlel,<<"presence">>,[{<<"xml:lang">>,<<"en">>}],[]}]}
Callback: mod_test:fetchPacketData
我们看到处理程序function_clause
在调用lists:thing_to_list(<<>>)
. 空二进制文件是xml:get_tag_attr_s/2
未找到所要求的属性的结果。lists:thing_to_list/1
调用将每个参数转换lists:concat/1
为列表,但不可能将空二进制转换<<>>
为列表,因此崩溃。
匹配结果xml:get_tag_attr_s/2
并针对每种情况制定适当的逻辑:何时找到属性,何时不存在。
我不知道如何在 dbg 中启动模块。我尝试了您在上面分享的内容,我认为您错过了第四个命令,这可能是如何启动模块的示例。
这是我的控制台的原始转储,没有任何编辑 - 我没有错过任何部分。您不会“在 dbg 中启动模块”。您只需以通常的方式启动一个模块,然后dbg
从服务器外壳中使用。
我所做的是将您的示例代码放入apps/ejabberd/src/mod_test.erl
文件中并构建了一个版本。之后,您可以在ejabberd.cfg
发行版中启用模块(查找该modules
部分并按照此处显示的示例进行类似操作),或者您可以在实时模式下启动服务器mongooseimctl live
并手动启动模块gen_mod:start_module(<<"localhost">>, mod_test, [])
(其中<<"localhost">>
只是一个示例 XMPP 域- 在那里替换您自己合适的域)。
当模块运行时(可以用 进行检查gen_mod:is_loaded(<<"your-xmpp-domain">>, mod_name_goes_here)
),您必须启用dbg
. 这显示在我之前添加的清单中。我不会深入描述如何使用dbg
,因为StackOverflow 上已经有很好的介绍。
如何测试属性是否存在的示例
case xml:get_tag_attr_s(<<"some-attribute">>, Packet) of
<<>> ->
%% attribute does not exist, as get_tag_attr_s returned the default value
ok;
<<"some-value">> ->
%% do something sensible with <<"some-value">>
ok
end
或者,您可以使用exml
它也是 MongooseIM 的一部分(但不是原始 ejabberd),并且更明确地指出找不到您要求的属性:
case exml_query:attr(Packet, <<"some-attribute">>) of
undefined ->
%% not found
ok;
<<"some-value">> ->
%% do something
...
end