Ejabberd 自定义模块

问题描述 投票:0回答:1

我正在尝试为我的 Ejabberd 服务器创建一个自定义模块。 我使用的是相对较新的版本,因此 ejabberd.hrl 不可用。 该模块应该做两件事:

  1. 当用户 A 向用户 B 发送消息时,一条消息会发回给 A,表示该消息已到达服务器(有点像 Whatsapp 的复选标记) 该消息具有独特的节结构,这正是我的 Java 客户端代码在节侦听器中所期望的。
  2. 如果用户 B 离线,则会向我的应用程序服务器发送一条消息,以便生成推送通知。

该模块可以工作,但实际上并非如此。我发现只有当 B 离线时才会生成确认消息,但无论如何我都需要生成它。第一部分工作得很好。 我认为问题出在消息挂钩上。这是代码:

-module(mod_http_offline).
-author("Allen Turing").

-behaviour(gen_mod).

-export([start/2, stop/1, create_message/1, depends/2, mod_doc/0, mod_options/1]).

%% Record definitions
-record(jid, {user = <<"">>, server = <<"">>, resource = <<"">>,
              luser = <<"">>, lserver = <<"">>, lresource = <<>>}).

-record(xmlel, {name, attrs = [], children = []}).
-record(xmlcdata, {content}).

%% Start function
start(Host, _Opts) ->
    inets:start(),
    ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, create_message, 50),
    ok.

%% Stop function
stop(Host) ->
    ejabberd_hooks:delete(offline_message_hook, Host, ?MODULE, create_message, 50),
    ok.

%% Create message function
create_message({archived, {message, StanzaId, Type, _, FromJID, ToJID, _, _, _, _, _}}) ->
    handle_message(Type, FromJID, ToJID, StanzaId);
create_message({_, {message, StanzaId, Type, _, FromJID, ToJID, _, _, _, _, _}}) ->
    handle_message(Type, FromJID, ToJID, StanzaId);
create_message(_Msg) ->
    ok.

%% Handle message function
handle_message(Type, FromJID, ToJID, StanzaId) ->
    case Type of
        chat ->
            ToLUser = ToJID#jid.luser,
            ToLServer = ToJID#jid.lserver,
            %% send HTTP notification
            post_offline_message(ToLUser, ToLServer),
            %% send acknowledgment
            send_acknowledgment(FromJID, ToJID, StanzaId),
            ok;
        _ ->
            ok
    end.

%% Function to send acknowledgment
send_acknowledgment(FromJID, ToJID, StanzaId) ->
    %% Build the 'arrived' extension element
    ArrivedExtension = #xmlel{
        name = <<"arrived">>,
        attrs = [{<<"xmlns">>, <<"urn:xmpp:ack">>}],
        children = []
    },
    %% Build the message packet
    AckPacket = #xmlel{
        name = <<"message">>,
        attrs = [{<<"to">>, jid_to_binary(FromJID)},
                 {<<"from">>, jid_to_binary(ToJID)},
                 {<<"type">>, <<"chat">>}],
        children = [
            %% Include the stanza ID in the message body
            #xmlel{
                name = <<"body">>,
                attrs = [],
                children = [#xmlcdata{content = StanzaId}]
            },
            %% Add the 'arrived' extension
            ArrivedExtension
        ]
    },
    %% Send acknowledgment
    ejabberd_router:route(ToJID, FromJID, AckPacket),
    ok.

%% Helper function to convert JID to binary
jid_to_binary(#jid{user = User, server = Server, resource = Resource}) ->
    case Resource of
        <<>> -> <<User/binary, "@", Server/binary>>;
        _ -> <<User/binary, "@", Server/binary, "/", Resource/binary>>
    end.

%% function to post offline message via HTTP
post_offline_message(ToLUser, ToLServer) ->
    JID = <<ToLUser/binary, "@", ToLServer/binary>>,
    Data = lists:flatten(io_lib:format("jid=~s", [JID])),
    Headers = [
        {"API-Key", generate_api_key()}
    ],
    case httpc:request(post, {"https://www.myappserver.com/notify", Headers, "application/x-www-form-urlencoded", Data}, [], []) of
        {ok, {{_Version, StatusCode, _ReasonPhrase}, _Headers, _Body}} ->
            ok;
        {error, Reason} ->
            ok
    end.

%% API key generation
generate_api_key() ->
    %% Return a fixed, placeholder API key
    <<"DUMMY_API_KEY_1234567890">>.

%% Optional callbacks for gen_mod behaviour
depends(_Host, _Opts) -> [].

mod_doc() ->
    "mod_http_offline: This module sends HTTP requests for offline messages and sends acknowledgments.".

mod_options(_Host) -> [].

我正在考虑将任务分成两个单独的模块,一个模块检查 B 是否离线,然后与应用程序服务器通信,另一个模块将确认消息发送回 A,但我宁愿将其全部保留在一个模块中。

erlang ejabberd
1个回答
0
投票

offline_message_hook,顾名思义,只有当离线用户收到消息时才会被调用。您需要一个不同的钩子来处理“所有”传入消息。候选人是:

user_send_packet - 如果您想尽快发送确认。它适用于您的情况,但如果您上面有一些东西可以过滤不需要的消息,它可能会过早发送确认。
  • filter_packet - 稍后调用它,并再次让您删除不需要的消息。此时,mod_mam 已存档该消息(如果已启用)。
  • user_receive_packet - 当消息路由到接收者时,在调用任何离线逻辑之前,将调用此函数。可能是一个好地方,因为您肯定知道消息已通过发送方的所有内容。
  • store_mam_message - 当消息被存档时,来自 mod_mam 的钩子。虽然我不确定这是否合适,但可以在这里发表致谢。
  • 您可以在 ejabberd 存储库 (
https://github.com/processone/ejabberd

) 或模块 contrib 存储库 (https://github.com/processone/ejabberd-contrib) 中找到挂钩示例

© www.soinside.com 2019 - 2024. All rights reserved.