用户发送数据包挂钩返回`badmatch`错误

时间:2015-12-15 13:52:51

标签: erlang xmpp ejabberd ejabberd-hooks

我在自定义模块中使用用户发送数据包挂钩,我不明白为什么收到的每个数据包都会出现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}]}]}

2 个答案:

答案 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}}),