【问题标题】:Parsing ejabberd packet with erlang用erlang解析ejabberd数据包
【发布时间】:2019-04-10 00:44:16
【问题描述】:

我正在使用 ejabberd18.09 进行 IM 应用程序。该应用程序几乎没有需要向 ejabberd(xmpp) 消息添加扩展的功能。

我在 offline_message_hook 上创建了一个自定义模块来捕获离线消息并将它们发送到我自己的 url 以进行进一步处理。

发送到 ejabberd 的消息根据消息的类型有不同的情况,如下所示

如果我发送照片,消息将如下所示

<message xmlns="jabber:client" xml:lang="en" to="someuserjid2" from="{someuserjid}" type="chat" id="mP8tO-8">
   <mtype xmlns="urn:xmpp:mtype" value="media" />
   <url xmlns="urn:xmpp:url" id="myId" mediaType="photo" link="myphotourl.com" />
   <body>thumbnail string</body>
</message>

发送短信时

<message xmlns="jabber:client" xml:lang="en" to="someuserjid2" from="{someuserjid}" type="chat" id="mP8tO-8">
   <mtype xmlns="urn:xmpp:mtype" value="text" />
   <body>Hi John</body>
</message>

发送位置时

<message xmlns="jabber:client" xml:lang="en" to="someuserjid2" from="{someuserjid}" type="chat" id="mP8tO-8">
   <mtype xmlns="urn:xmpp:mtype" value="location" />
   <location xmlns="urn:xmpp:geo" lat="1.2" lng="2.2 " />
   <body>location thumbnailstring</body>
</message>

我使用 .erl 代码读取正文和消息 ID,如下所示

create_message(_From, _To, Packet) when (Packet#message.type == chat) and (Packet#message.body /= []) ->
  Body = fxml:get_path_s(Packet, [{elem, list_to_binary("body")}, cdata]),
  MessageId = fxml:get_tag_attr_s(list_to_binary("id"), Packet),
  post_offline_message(_From, _To, Body, MessageId),
  ok.

我想要的是如何(在 erlang 中)读取 mtype 标记的 value 属性并在(媒体、位置、 test ) 值,以便我可以分别处理每条消息?

【问题讨论】:

    标签: erlang ejabberd erl ejabberd-module ejabberd-hooks


    【解决方案1】:

    您可以将参数列表中的attr 传递给fxml:get_path_s 以挑选出某个元素的某个属性的值:

    case fxml:get_path_s(Packet, [{elem, <<"mtype">>}, {attr, <<"value">>}]) of
        <<"media">> ->
            %% handle media...
        <<"location">> ->
            %% handle location...
        <<"">> ->
            %% no mtype element, or missing value attribute!
            %% let's handle that case as well
    end
    

    另一个想法:你真的需要&lt;mtype&gt; 元素吗?看起来您可以只检查是否存在 &lt;location&gt;&lt;url&gt; 元素。你可以这样做:

    case fxml:get_subtag(Packet, <<"location">>) of
        false ->
            %% No location. Try url
            case fxml:get_subtag(Packet, <<"url">>) of
                false ->
                    %% Neither location nor url
                    %% Handle this case somehow...
                Url ->
                    %% Do something with Url...
            end
        Location ->
            %% Do something with Location...
    end
    

    代码有点乱,因为我们需要嵌套case 表达式,不像以前的版本我们只检查单个表达式的值。您可以做的一件事是编写一个帮助函数,依次尝试每个元素:

    find_one_of(Packet, []) ->
        not_found;
    find_one_of(Packet, [ElementName | Rest]) ->
        case fxml:get_subtag(Packet, ElementName) of
            false ->
                find_one_of(Packet, Rest);
            Element ->
                {ElementName, Element}
        end.
    

    然后这样称呼它:

    case find_one_of(Packet, [<<"location">>, <<"url">>]) of
        {<<"location">>, Location} ->
            %% Do something with Location...
        {<<"url">>, Url} ->
            %% Do something with Url...
        not_found ->
            %% Neither location nor url
    end
    

    【讨论】:

    • 谢谢@legoscia。我是 erlang 的新手,我准确地添加了 mtype 来检查我收到的元素类型,我同意你的观点,即检查是否存在会更好。你能建议我们在我的情况下这样做的方式吗?
    • 使用 fxml:get_path_s(Packet, [{elem, >}, {attr, >}]) 将成功编译但是当我运行它时,它崩溃:Hook offline_message_hook 在运行 mod_offline_http_post:create_message/1 时崩溃:{error,function_clause,[{fxml,get_subtag,[{file,"src/fxml.erl"},{line,175}]
    • 以防万一有人遇到这个问题,我可以使用以下方法解决它:fxml:get_path_s(xmpp:encode(Packet), [{elem,list_to_binary("mtype")} , {attr, list_to_binary("value")}]),
    猜你喜欢
    • 2015-12-17
    • 2020-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-01
    • 2013-09-08
    • 1970-01-01
    相关资源
    最近更新 更多