Push notification Ejabberd:处理脱机消息的简单模块中出错

Push notification Ejabberd:处理脱机消息的简单模块中出错,push-notification,erlang,xmpp,ejabberd,Push Notification,Erlang,Xmpp,Ejabberd,我安装了Ejabberd 17.01,需要在收件人脱机时推送通知。这似乎是一项常见的任务,使用定制Ejabberd模块的解决方案随处可见。然而,我就是不能让它运行。首先,这里是我的脚本: -module(mod_offline_push). -behaviour(gen_mod). -export([start/2, stop/1]). -export([push_message/3]). -include("ejabberd.hrl"). -

我安装了Ejabberd 17.01,需要在收件人脱机时推送通知。这似乎是一项常见的任务,使用定制Ejabberd模块的解决方案随处可见。然而,我就是不能让它运行。首先,这里是我的脚本:

    -module(mod_offline_push).
    -behaviour(gen_mod).

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

    -include("ejabberd.hrl").
    -include("logger.hrl").
    -include("jlib.hrl").

    start(Host, _Opts) ->
            ?INFO_MSG("mod_offline_push loading", []),
            ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, push_message, 10),
            ok.

    stop(Host) ->
            ?INFO_MSG("mod_offline_push stopping", []),
            ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, push_message, 10),
            ok.

    push_message(From, To, Packet) ->
            ?INFO_MSG("mod_offline_push -> push_message", [To]),
            Type = fxml:get_tag_attr_s(<<"type">>, Packet), % Supposedly since 16.04
            %Type = xml:get_tag_attr_s(<<"type">>, Packet), % Supposedly since 13.XX
            %Type = xml:get_tag_attr_s("type", Packet),
            %Type = xml:get_tag_attr_s(list_to_binary("type"), Packet),
            ?INFO_MSG("mod_offline_push -> push_message", []),
            ok.
我是新来的Ejabberd和Erlang,所以我不能真正解释错误,但是
{mod_offline\u push,push_message,3,[{file,“mod_offline\u push.erl”},{Line,33}]}
中提到的第33行肯定是调用
get_tag\u attr\u s
的行

2017/01/27更新:因为这让我很头疼——我还是不太开心——我在这里发布了我当前的工作模块,希望它能帮助其他人。我的安装程序是Ejabberd17.01,运行在Ubuntu 16.04上。我尝试过但失败的大多数东西似乎都适用于Ejabberd的旧版本:

-module(mod_fcm_fork).
-behaviour(gen_mod).

%% public methods for this module
-export([start/2, stop/1]).
-export([push_notification/3]).

%% included for writing to ejabberd log file
-include("ejabberd.hrl").
-include("logger.hrl").
-include("xmpp_codec.hrl").

%% Copied this record definition from jlib.hrl
%% Including "xmpp_codec.hrl" and "jlib.hrl" resulted in errors ("XYZ already defined")
-record(jid, {user = <<"">> :: binary(),
              server = <<"">> :: binary(),
              resource = <<"">> :: binary(),
              luser = <<"">> :: binary(),
              lserver = <<"">> :: binary(),
              lresource = <<"">> :: binary()}).


start(Host, _Opts) ->
    ?INFO_MSG("mod_fcm_fork loading", []),
    % Providing the most basic API to the clients and servers that are part of the Inets application
    inets:start(),
    % Add hook to handle message to user who are offline
    ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, push_notification, 10),
    ok.


stop(Host) ->
    ?INFO_MSG("mod_fcm_fork stopping", []),
    ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, push_notification, 10),
    ok.


push_notification(From, To, Packet) ->
    % Generate JID of sender and receiver
    FromJid = lists:concat([binary_to_list(From#jid.user), "@", binary_to_list(From#jid.server), "/", binary_to_list(From#jid.resource)]),
    ToJid = lists:concat([binary_to_list(To#jid.user), "@", binary_to_list(To#jid.server), "/", binary_to_list(To#jid.resource)]),
    % Get message body
    MessageBody = Packet#message.body,
    % Check of MessageBody is not empty
    case MessageBody/=[] of
        true ->
            % Get first element (no idea when this list can have more elements)
            [First | _ ] = MessageBody,
            % Get message data and convert to string
            MessageBodyText = binary_to_list(First#text.data),
            send_post_request(FromJid, ToJid, MessageBodyText);
        false ->
            ?INFO_MSG("mod_fcm_fork -> push_notification: MessageBody is empty",[])
    end,    
    ok.


send_post_request(FromJid, ToJid, MessageBodyText) ->
    %?INFO_MSG("mod_fcm_fork -> send_post_request -> MessageBodyText = ~p", [Demo]),    
    Method = post,
    PostURL = gen_mod:get_module_opt(global, ?MODULE, post_url,fun(X) -> X end, all),
    % Add data as query string. Not nice, query body would be preferable
    % Problem: message body itself can be in a JSON string, and I couldn't figure out the correct encoding.
    URL = lists:concat([binary_to_list(PostURL), "?", "fromjid=", FromJid,"&tojid=", ToJid,"&body=", edoc_lib:escape_uri(MessageBodyText)]),   
    Header = [],
    ContentType = "application/json",
    Body = [],
    ?INFO_MSG("mod_fcm_fork -> send_post_request -> URL = ~p", [URL]),    
    % ADD SSL CONFIG BELOW!
    %HTTPOptions = [{ssl,[{versions, ['tlsv1.2']}]}],
    HTTPOptions = [], 
    Options = [],
    httpc:request(Method, {URL, Header, ContentType, Body}, HTTPOptions, Options),
    ok.
-模块(mod_fcm_fork)。
-行为(gen_mod)。
%%此模块的公共方法
-导出([开始/2,停止/1])。
-导出([推送通知/3])。
%%包括用于写入ejabberd日志文件
-包括(“ejabberd.hrl”)。
-包括(“logger.hrl”)。
-包括(“xmpp_codec.hrl”)。
%%从jlib.hrl复制了此记录定义
%%包括“xmpp_codec.hrl”和“jlib.hrl”会导致错误(“XYZ已定义”)
-记录(jid,{user=::binary(),
服务器=::二进制(),
资源=::二进制(),
luser=::binary(),
lserver=::binary(),
lresource=::binary()})。
开始(主机,选择)->
?信息信息(“模块fcm货叉装载”,[]),
%为作为iNet应用程序一部分的客户端和服务器提供最基本的API
inets:start(),
%添加钩子以处理脱机用户的消息
ejabberd挂钩:添加(离线消息挂钩、主机、模块、推送通知、10),
好啊
停止(主机)->
?信息信息(“模块fcm叉停止”,[]),
ejabberd挂钩:添加(离线消息挂钩、主机、模块、推送通知、10),
好啊
推送通知(从、到、数据包)->
%生成发送方和接收方的JID
FromJid=list:concat([二进制到二进制列表(从#jid.user)、“@”、二进制到二进制列表(从#jid.server)、“/”、二进制到二进制列表(从#jid.resource)],
ToJid=list:concat([binary-to-list(to-jid.user),“@”,binary-to-list(to-jid.server),“/”,binary-to-list(to-jid.resource)],
%获取消息正文
MessageBody=数据包#message.body,
%MessageBody的检查不为空
案例MessageBody/=[]共
正确->
%获取第一个元素(不知道此列表何时可以包含更多元素)
[First | |]=MessageBody,
%获取消息数据并转换为字符串
MessageBodyText=binary_to_列表(第一个#text.data),
发送post请求(FromJid、ToJid、MessageBodyText);
错误->
信息消息(“mod\u fcm\u fork->push\u通知:消息体为空”,[])
完,,
好啊
发送发布请求(FromJid、ToJid、MessageBodyText)->
%信息消息(“mod\u fcm\u fork->send\u post\u request->MessageBodyText=~p”,[Demo]),
方法=员额,
postrl=gen_mod:get_module_opt(全局、模块、post_url、fun(X)->X end,all),
%将数据添加为查询字符串。不太好,最好是查询主体
%问题:消息体本身可能是JSON字符串,我无法找出正确的编码。
URL=lists:concat([binary_to_list(postrl),“?”,“fromjid=”,fromjid,&tojid=”,tojid,&body=”,edoc_lib:escape_uri(MessageBodyText)],
页眉=[],
ContentType=“application/json”,
正文=[],
信息消息(“mod\u fcm\u fork->send\u post\u request->URL=~p”,[URL]),
%在下面添加SSL配置!
%HTTPOptions=[{ssl,[{versions,['tlsv1.2']}]}],
HTTPOptions=[],
选项=[],
httpc:request(方法,{URL,Header,ContentType,Body},HTTPOptions,Options),
好啊

最新的方法似乎是使用
xmpp:get\u type/1

Type = xmpp:get_type(Packet),

它返回一个atom,在本例中,它是
normal

实际上,它失败了,因为第二个arg
数据包
传递给fxml:get\u tag\u attr\s in push\u message函数

{message,<<>>,normal,<<>>,
         {jid,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>,
              <<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>},
         {jid,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>,<<"carl">>,
              <<"xxx.xxx.xxx.xxx">>,<<>>},
         [],
         [{text,<<>>,<<"sfsdfsdf">>}],
         undefined,[],#{}}
包括此文件并仅使用

Type =  Packet#message.type
或者,如果需要二进制值

 Type =  erlang:atom_to_binary(Packet#message.type, utf8)

太好了,谢谢!作为一个新手,我太不了解错误信息了。我想这些变化是伴随着最新的Ejabberd版本而来的?因为即使是去年年底的搜索结果也使用了我尝试过的方法。我不知道,也许是最新版本,我使用的是14.07除了
数据包
,我如何处理
?像
到#jid.luser
这样的东西会抛出错误。这仅在我还包括
jlib.hrl
,但它似乎与cose的
xmpp\u codec.hrl
冲突时才有效,您需要包括jlib.hrl,这是一个很好的解决方案
code
ToJid=Packet#message.to,ToLUser=ToJid#jid.luser
code
我已经尝试过了,但正如我所写的,这些to包括(
xmpp\u codec.hrl
jlib.hrel
)与一些记录已经定义的错误冲突。我最后做的是只包含
xmpp\u codec.hrl
,并将jid记录的定义
-record(jid,{user=::binary(),…
)添加到我自己的文件中。它似乎有点“脏”但它是这样工作的。一旦我解决了所有其他小问题,我会更新我的问题。作为一个附加问题:我现在如何获得
正文
。它不适用于
xmpp:get_body(Packet)
,我认为应该根据
body=Packet\message.body
或者,如果需要文本:
xmpp:get_text(Packet#message.body)
您能帮我回答以下问题吗:
Type =  Packet#message.type
 Type =  erlang:atom_to_binary(Packet#message.type, utf8)