我在自定义模块中使用用户发送数据包挂钩,我不明白为什么收到的每个数据包都会出现badmatch
错误。我也在这里添加了声明部分。
**Code**
-module(mod_post_log).
-behaviour(gen_mod).
-export([start/2,stop/1,log_user_send/4,post_result/1,send_message/3]).
**strong text**
-include("ejabberd.hrl").
-include("jlib.hrl").
-include("logger.hrl").
start(Host, _Opts) ->
ok = case inets:start() of
{error, {already_started, inets}} ->
ok;
ok ->
ok
end,
ejabberd_hooks:add(user_send_packet, Host,
?MODULE, log_user_send, 50),
ok.
stop(Host) ->
ejabberd_hooks:delete(user_send_packet, Host,
?MODULE, log_user_send, 50),
ok.
log_user_send(Packet, _C2SState, From, To) ->
ok = log_packet(From, To, Packet),
Packet.
log_packet(From, To, #xmlel{name = <<"message">>} = Packet) ->
MessageId = xml:get_tag_attr_s(<<"id">>, Packet),
Type = xml:get_tag_attr_s(list_to_binary("type"), Packet),
send_message(From, To, MessageId, Type),
%% send_message(From, To, xml:get_tag_attr_s(list_to_binary("id"), Packet),xml:get_tag_attr_s(list_to_binary("type"), Packet)),
%% ?INFO_MSG("mod_ack_receipt - MsgID: ~p To: ~p From: ~p", [MessageId, To, From]),
ok = log_message(From, To, Packet);
log_packet(_From, _To, _Packet) ->
ok.
log_message(From, To, #xmlel{attrs = Attrs} = Packet) ->
Type = lists:keyfind(<<"type">>, 1, Attrs),
log_message_filter(Type, From, To, Packet).
log_message_filter({<<"type">>, Type}, From, To, Packet)
when Type =:= <<"chat">>;
Type =:= <<"groupchat">> ->
log_chat(From, To, Packet);
log_message_filter(_Other, _From, _To, _Packet) ->
ok.
log_chat(From, To, #xmlel{children = Els} = Packet) ->
case get_body(Els) of
no_body ->
ok;
{ok, _Body} ->
log_chat_with_body(From, To, Packet)
end.
log_chat_with_body(From, To, Packet) ->
case should_acknowledge(Packet) of
S when (S==true) ->
post_xml(From, To, Packet);
false ->
ok
end,
Packet.
should_acknowledge(#xmlel{name = <<"message">>} = Packet) ->
case {xml:get_attr_s(<<"type">>, Packet#xmlel.attrs),
xml:get_subtag_cdata(Packet, <<"body">>)} of
{<<"error">>, _} ->
false;
{_, <<>>} ->
%% Empty body
false;
_ ->
true
end;
should_acknowledge(#xmlel{}) ->
false.
post_xml(From, To, Packet) ->
Ts = to_iso_8601_date(os:timestamp()),
MessageId = xml:get_tag_attr_s(list_to_binary("id"), Packet),
Type = xml:get_tag_attr_s(list_to_binary("type"), Packet),
Chat_sent = xml:get_tag_attr_s(list_to_binary("chat_sent"), Packet),
Subject = xml:get_path_s(Packet, [{elem, list_to_binary("subject")},cdata]),
Body = xml:get_path_s(Packet,[{elem, list_to_binary("body")}, cdata]),
Sep = "&",
Post = [
"from=", From#jid.luser, Sep,
"to=", To#jid.luser, Sep,
"body=", binary_to_list(Body), Sep,
"type=", binary_to_list(Type),Sep,
"chat_sent=", binary_to_list(Chat_sent),Sep,
"subject=",binary_to_list(Subject),Sep,
"message_id=", binary_to_list(MessageId),Sep,
"xml=",xml:element_to_binary(Packet),Sep,
"done=11"
],
Url = get_opt(url),
TsHeader = get_opt(ts_header, "X-Message-Timestamp"),
FromHeader = get_opt(from_header, "X-Message-From"),
ToHeader = get_opt(to_header, "X-Message-To"),
HttpOptions = get_opt(http_options, []),
ReqOptions = get_opt(req_options, []),
{ok, _ReqId} = httpc:request(post,
{Url, [], "application/x-www-form-urlencoded", list_to_binary(Post)},
HttpOptions,
[ {sync, false},
{receiver, {?MODULE, post_result, []}}
| ReqOptions ]),
?INFO_MSG("post http - MsgID: xml: ~p", [post]),
ok.
post_result({_ReqId, {error, Reason}}) ->
report_error([ {error, Reason } ]);
post_result({_ReqId, Result}) ->
{StatusLine, Headers, Body} = Result,
{_HttpVersion, StatusCode, ReasonPhrase} = StatusLine,
if StatusCode < 200;
StatusCode > 299 ->
ok = report_error([ {status_code, StatusCode},
{reason_phrase, ReasonPhrase},
{headers, Headers},
{body, Body} ]),
ok;
true ->
ok
end.
send_message(From, To, MessageId,Type) ->
Packet = #xmlel{name = <<"iq">>,
attrs = [{<<"to">>, From},{<<"ack">>, MessageId}, {<<"type">>, <<"result">>},{<<"chattype">>, Type}],
children =
[#xmlel{name = <<"ack">>,
attrs = [{<<"xmlns">>,<<"xmpp:ack">> }],
children = []}]},
ejabberd_router:route(From, From, Packet).
get_body(Els) ->
XmlEls = [ El || El <- Els, is_record(El, xmlel) ],
case lists:keyfind(<<"body">>, #xmlel.name, XmlEls) of
false ->
no_body;
#xmlel{children = InnerEls} ->
case lists:keyfind(xmlcdata, 1, InnerEls) of
false ->
no_body;
{xmlcdata, Body} ->
{ok, Body}
end
end.
get_opt(Opt) ->
get_opt(Opt, undefined).
get_opt(Opt, Default) ->
F = fun(Val) when is_binary(Val) -> binary_to_list(Val);
(Val) -> Val
end,
gen_mod:get_module_opt(global, ?MODULE, Opt, F, Default).
report_error(ReportArgs) ->
ok = error_logger:error_report([ mod_post_log_cannot_post | ReportArgs ]).
**Error Log**
{{badmatch,{xmlel,<<"message">>,
[{<<"xml:lang">>,<<"en">>},
{<<"to">>,<<"123456789@xyz.myapp.com">>},
{<<"id">>,<<"AF1xJ-149">>},
{<<"chat_sent">>,<<"2015-12-15T06:45:29.399Z">>},
{<<"type">>,<<"chat">>}],
[{xmlel,<<"size">>,[],[{xmlcdata,<<"0">>}]},
{xmlel,<<"subject">>,[],[{xmlcdata,<<"poke">>}]},
{xmlel,<<"body">>,[],[{xmlcdata,<<"95">>}]},
{xmlel,<<"request">>,
[{<<"xmlns">>,<<"urn:xmpp:receipts">>}],
[]}]}},
[{mod_post_log,log_packet,3,
[{file,"src/mod_post_log.erl"},{line,44}]},
{mod_post_log,log_user_send,4,
[{file,"src/mod_post_log.erl"},{line,33}]},
{ejabberd_hooks,safe_apply,3,
[{file,"src/ejabberd_hooks.erl"},{line,382}]},
{ejabberd_hooks,run_fold1,4,
[{file,"src/ejabberd_hooks.erl"},{line,365}]},
{ejabberd_c2s,session_established2,2,
[{file,"src/ejabberd_c2s.erl"},{line,1296}]},
{p1_fsm,handle_msg,10,[{file,"src/p1_fsm.erl"},{line,582}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,237}]}]}
答案 0 :(得分:2)
在函数src/mod_post_log.erl
第44行的文件mod_post_log:log_packet/3
中有一些匹配运算符,它不希望获得
{xmlel,<<"message">>,
[{<<"xml:lang">>,<<"en">>},
{<<"to">>,<<"123456789@xyz.myapp.com">>},
{<<"id">>,<<"AF1xJ-149">>},
{<<"chat_sent">>,<<"2015-12-15T06:45:29.399Z">>},
{<<"type">>,<<"chat">>}],
[{xmlel,<<"size">>,[],[{xmlcdata,<<"0">>}]},
{xmlel,<<"subject">>,[],[{xmlcdata,<<"poke">>}]},
{xmlel,<<"body">>,[],[{xmlcdata,<<"95">>}]},
{xmlel,<<"request">>,
[{<<"xmlns">>,<<"urn:xmpp:receipts">>}],
[]}]}
答案 1 :(得分:1)
按原样查看完整模块“mod_post_log.erl”会好得多。 但我认为问题在于:
MessageId = xml:get_tag_attr_s(<<"id">>, Packet),
Packet是一个记录,函数等待iolist,所以它应该是
MessageId = xml:get_tag_attr_s(<<"id">>, Packet#xmlel.{{see record declaration}}),