Я написал следующий модуль для 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"])}, [], []).
Я смог успешно реализовать модуль после того, как следовал совету Эрша (см. Ниже). Ниже приведен код, который я использовал. Надеюсь, это поможет кому-то еще 🙂
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
запускается каждый раз, когда сервер получает раздел от клиента. Это может объяснить, почему обработчик не запускается, хотя это зависит от того, как вы тестируете. Там в статья с одним разделом, описывающая некоторые хуки в MongooseIM доступно на официальной вики.
Что касается проблем с получением атрибутов пакета, либо регистрация входящего пакета для проверки или использования dbg
в оболочке сервера Erlang для отслеживания реальных вызовов, выполняемых вашим модулем, может быть способ узнать, что происходит.
Пример сеанса с 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. Я попробовал то, что вы поделились выше, и я думаю, что вы пропустили 4-ю команду, которая может служить примером того, как запустить модуль.
Это необработанный дамп моей консоли без каких-либо правок — я не пропустил ни одной части.
Вы не «запускаете модуль в 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
Других решений пока нет …