MongooseIM 模块没有从数据包中获取变量

MongooseIM module not getting variables from Packet

我为 MongooseIM 编写了以下模块,但没有任何内容发布到 PHP 文件。

start(_Host, _Opt) -> 
    inets:start(),
    ejabberd_hooks:add(user_send_packet, _Host, ?MODULE, fetchPacketData, 50).
stop (_Host) -> 
    ejabberd_hooks:delete(user_send_packet, _Host, ?MODULE, fetchPacketData, 50).
fetchPacketData(_From, _To, Packet) ->
    To = xml:get_tag_attr_s(<<"to">>, Packet),
    httpc:request(post, {"http://example.com/receiver.php",[],
            "application/x-www-form-urlencoded",
            lists:concat(["To=",To,"&Type=1","&Body=ABC"])}, [], []).

按照 erszcz 的建议,我能够成功实现该模块(请参见下文)。下面是我使用的代码。希望它对其他人也有帮助:)

start(Host, _Opts)->
  inets:start(),
  ejabberd_hooks:add(user_send_packet, Host, ?MODULE, sendMessage, 50),
  ok.
stop(Host)->
  ejabberd_hooks:delete(user_send_packet, Host, ?MODULE, sendMessage, 50),
  ok.
sendMessage(_From, _To, Packet) ->
  case xml:get_tag_attr_s(<<"type">>, Packet) of
    <<"chat">> ->
      To = lists:flatten(io_lib:format("~s", [xml:get_tag_attr_s(<<"to">>, Packet)])),
      ** post variables to PHP file using httpc:request **
      ok;
    _ ->
      ok
    end.

offline_message_hook 仅在服务器将消息路由到不在线的用户时调用。每当服务器从客户端接收到一个节时,user_send_packet 就是 运行。这或许可以解释为什么处理程序不是 运行,尽管这取决于您的测试方式。官方 wiki 上有 an article with one section describing some hooks in MongooseIM

至于检索数据包属性的问题,要么记录传入的数据包进行检查,要么在服务器 Erlang shell 中使用 dbg 来跟踪您的模块完成的实际调用可能是解决问题的方法告诉发生了什么事。


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

我们看到处理程序在调用 lists:thing_to_list(<<>>) 时出错 function_clause。当找不到要求的属性时,空二进制文件是 xml:get_tag_attr_s/2 的结果。 lists:thing_to_list/1 被调用以将 lists:concat/1 的每个参数转换为列表,但是无法将空二进制文件 <<>> 转换为列表,因此崩溃。

匹配 xml:get_tag_attr_s/2 的结果,并针对每种情况适当地制定逻辑:何时找到属性以及何时不存在。


I don't know how to start a module in dbg. I tried what you had shared above and I think you missed the 4th command which could be an example of how to initiate a module.

这是我的控制台的原始转储,没有任何编辑 - 我没有遗漏任何部分。 你不需要 "start a module in dbg." 你只需以通常的方式启动一个模块,然后从服务器 shell.

使用 dbg

我所做的是将您的示例代码放入 apps/ejabberd/src/mod_test.erl 文件并构建了一个版本。之后,您可以在发布的 ejabberd.cfg 中启用该模块(查找 modules 部分并按照此处显示的示例进行类似操作)或者您可以使用 [=28= 以实时模式启动服务器] 并使用 gen_mod:start_module(<<"localhost">>, mod_test, []) 手动启动模块(其中 <<"localhost">> 只是一个示例 XMPP 域 - 在那里替换您自己的合适域)。

当模块 运行ning(可以用 gen_mod:is_loaded(<<"your-xmpp-domain">>, mod_name_goes_here) 检查)时,您必须启用 dbg。这显示在我之前添加的列表中。我不会深入描述如何将 dbg 用作 a very good introduction is already available on Whosebug


an example of how to test if an attribute exists or not

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