Erlang 未处理MongooseIM简单模块事件

Erlang 未处理MongooseIM简单模块事件,erlang,mongoose-im,Erlang,Mongoose Im,我是新来的爱尔兰人和埃贾伯德/蒙古塞姆人。我试图编写一个非常简单的mongoose模块,在发送数据包之前向数据包添加一个额外的子元素。下面是我的代码: -module(mod_test). -behavior(gen_mod). -export([start/2, stop/1]). -export([add_child/1]). -include("ejabberd.hrl"). start(Host, Opts) -> ejabberd_hooks:add(filte

我是新来的爱尔兰人和埃贾伯德/蒙古塞姆人。我试图编写一个非常简单的mongoose模块,在发送数据包之前向数据包添加一个额外的子元素。下面是我的代码:

-module(mod_test).

-behavior(gen_mod).


-export([start/2, stop/1]).
-export([add_child/1]).

-include("ejabberd.hrl").

start(Host, Opts) ->
    ejabberd_hooks:add(filter_packet, Host, ?MODULE, add_child, 0),
    ?DEBUG(" MOD_TEST Started",[]),
    ok.

stop(Host) ->
    ejabberd_hooks:delete(filter_packet, Host, ?MODULE, add_child, 0),
    ok.

add_child({From, To, XML} = Packet) ->
    Tag = {"a","b"},
    NewPacket = xml:append_subtags(Packet, [Tag]),
    ?INFO_MSG("  To party: ~p~n",[To]),
    NewPacket.
我可以编译代码,很少有警告

mod_test.erl:3: Warning: behaviour gen_mod undefined
mod_test.erl:11: Warning: variable 'Opts' is unused
mod_test.erl:20: Warning: variable 'From' is unused
mod_test.erl:20: Warning: variable 'XML' is unused
然后,当我添加模块并运行它时,它会启动,但它不会对数据包进行任何更改,也不会生成任何日志

另一个问题是,如果在start函数中添加日志,它会被编译,但在启动模块时会看到错误

2015-03-03 16:36:34.772 [critical] <0.200.0>@gen_mod:start_module:94 Problem starting the module mod_test for host <<"localhost">>
 options: []
 error: undef
[{lager,info,["  mod_test starting ...",[[]]],[]},
 {mod_test,start,2,[{file,"mod_test.erl"},{line,13}]},
 {gen_mod,start_module,3,[{file,"src/gen_mod.erl"},{line,83}]},
 {lists,foreach,2,[{file,"lists.erl"},{line,1336}]},
 {ejabberd_app,start,2,[{file,"src/ejabberd_app.erl"},{line,69}]},
 {application_master,start_it_old,4,
                     [{file,"application_master.erl"},{line,272}]}]
2015-03-03 16:36:34.773 [critical] <0.200.0>@gen_mod:start_module:99 ejabberd initialization was aborted because a module start failed.
The trace is [{lager,info,["  mod_test starting ...",[[]]],[]},{mod_test,start,2,[{file,"mod_test.erl"},{line,13}]},{gen_mod,start_module,3,[{file,"src/gen_mod.erl"},{line,83}]},{lists,foreach,2,[{file,"lists.erl"},{line,1336}]},{ejabberd_app,start,2,[{file,"src/ejabberd_app.erl"},{line,69}]},{application_master,start_it_old,4,[{file,"application_master.erl"},{line,272}]}].

Crash dump was written to: erl_crash.dump
Problem starting the module mod_test for host <<"localhost">>
 options: []
 error: undef
[{lager,info,["  mod_xyz starting ...",[[]]],[]},
 {mod_test,start,2,[{file,"mod_timetagg
我做错了什么?

错误为未定义,这意味着调用的函数未定义/导出。stacktrace显示所讨论的函数更大:info/2

Lager处理?INFO_MSG的日志库有一个特殊的怪癖,即代码会调用不存在的函数,但代码在编译之前会通过解析转换进行转换。看来这不是为你发生的

MongooseIM树中apps/ejabberd中的rebar.config文件包含erl_opts中的{parse_transform,lager_transform},它要求编译器应用解析转换。我建议将mod_test.erl放入apps/ejabberd/src,并构建整个MongooseIM树;这将确保使用正确的选项生成文件。

错误为未定义,这意味着调用了未定义/导出的函数。stacktrace显示所讨论的函数更大:info/2

Lager处理?INFO_MSG的日志库有一个特殊的怪癖,即代码会调用不存在的函数,但代码在编译之前会通过解析转换进行转换。看来这不是为你发生的


MongooseIM树中apps/ejabberd中的rebar.config文件包含erl_opts中的{parse_transform,lager_transform},它要求编译器应用解析转换。我建议将mod_test.erl放入apps/ejabberd/src,并构建整个MongooseIM树;这将确保您的文件使用正确的选项生成。

因此您的示例实际上有点棘手,因为filter\u数据包钩子是如何工作的。你在第一次尝试时选择了最差的钩子

如果您查看ejabberd_router:do_route,您将看到filter_数据包在没有主机参数的情况下运行-它是一个全局钩子,因此当您为特定主机注册add_子函数时,它基本上会被忽略

请尝试以下操作:

-module(mod_test).
-behavior(gen_mod).

-export([start/2, stop/1]).
-export([add_child/1]).

-include_lib("ejabberd/include/ejabberd.hrl").
-include_lib("exml/include/exml.hrl").

start(Host, Opts) ->
    ejabberd_loglevel:set_custom(?MODULE, 5),
    ejabberd_hooks:add(filter_local_packet, Host, ?MODULE, add_child, 1),
    ?DEBUG(" MOD_TEST Started",[]),
    ok.

stop(Host) ->
    ejabberd_hooks:delete(filter_local_packet, Host, ?MODULE, add_child, 1),
    ok.

add_child({From, To, Element} = HookData) ->
    ?DEBUG("Filtering ~p~n", [HookData]),
    case Element#xmlel.name of
        <<"message">> ->
            Tag = #xmlel{name = <<"added-tag">>, attrs = [], children = []},
            NewElement = xml:append_subtags(Element, [Tag]),
            ?DEBUG("will return new el: ~p", [NewElement]),
            {From, To, NewElement};
        _ ->
            ?DEBUG("will pass old el: ~p", [Element]),
            HookData
    end.
在给定主机上注册filter_local_数据包现在可以工作了,所有传入的节都将传递给您的函数。重要的是要记住,在所有小节中添加虚假标记可能会破坏一些东西,因此上面的代码只会在小节中添加一个元素

使用上面的例子,从那里开始工作


祝你好运

所以您的示例实际上有点棘手,因为filter_数据包钩子是如何工作的。你在第一次尝试时选择了最差的钩子

如果您查看ejabberd_router:do_route,您将看到filter_数据包在没有主机参数的情况下运行-它是一个全局钩子,因此当您为特定主机注册add_子函数时,它基本上会被忽略

请尝试以下操作:

-module(mod_test).
-behavior(gen_mod).

-export([start/2, stop/1]).
-export([add_child/1]).

-include_lib("ejabberd/include/ejabberd.hrl").
-include_lib("exml/include/exml.hrl").

start(Host, Opts) ->
    ejabberd_loglevel:set_custom(?MODULE, 5),
    ejabberd_hooks:add(filter_local_packet, Host, ?MODULE, add_child, 1),
    ?DEBUG(" MOD_TEST Started",[]),
    ok.

stop(Host) ->
    ejabberd_hooks:delete(filter_local_packet, Host, ?MODULE, add_child, 1),
    ok.

add_child({From, To, Element} = HookData) ->
    ?DEBUG("Filtering ~p~n", [HookData]),
    case Element#xmlel.name of
        <<"message">> ->
            Tag = #xmlel{name = <<"added-tag">>, attrs = [], children = []},
            NewElement = xml:append_subtags(Element, [Tag]),
            ?DEBUG("will return new el: ~p", [NewElement]),
            {From, To, NewElement};
        _ ->
            ?DEBUG("will pass old el: ~p", [Element]),
            HookData
    end.
在给定主机上注册filter_local_数据包现在可以工作了,所有传入的节都将传递给您的函数。重要的是要记住,在所有小节中添加虚假标记可能会破坏一些东西,因此上面的代码只会在小节中添加一个元素

使用上面的例子,从那里开始工作


祝你好运

嗨,谢谢你的回复。我已经重建了整个mongoose,现在我可以看到我的模块正在正确启动,我可以看到调试日志MOD_测试已经启动。但是add_子函数仍然没有被触发,我甚至没有看到我放在add_子函数中的日志。知道为什么吗?嗨,谢谢你的回复。我已经重建了整个mongoose,现在我可以看到我的模块正在正确启动,我可以看到调试日志MOD_测试已经启动。但是add_子函数仍然没有被触发,我甚至没有看到我放在add_子函数中的日志。知道为什么吗?只是个问题。我尝试了相同的代码,将hook filter_包更改为全局。它确实调用了add_child函数并更新了数据包,但没有发送新数据包,因为我没有看到数据包中的跟踪。知道为什么吗?你能给我看一下密码吗?请记住,在Erlang中,您无法就地更新内容-可能您没有返回正确的值?这只是一个问题。我尝试了相同的代码,将hook filter_包更改为全局。它确实调用了add_child函数并更新了数据包,但没有发送新数据包,因为我没有看到数据包中的跟踪。知道为什么吗?你能给我看一下密码吗?请记住,在Erlang中,您无法就地更新内容-可能您没有返回正确的值?