我正在尝试为我的 Ejabberd 服务器创建一个自定义模块。 我使用的是相对较新的版本,因此 ejabberd.hrl 不可用。 该模块应该做两件事:
该模块可以工作,但实际上并非如此。我发现只有当 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,但我宁愿将其全部保留在一个模块中。
offline_message_hook,顾名思义,只有当离线用户收到消息时才会被调用。您需要一个不同的钩子来处理“所有”传入消息。候选人是:
user_send_packet - 如果您想尽快发送确认。它适用于您的情况,但如果您上面有一些东西可以过滤不需要的消息,它可能会过早发送确认。) 或模块 contrib 存储库 (https://github.com/processone/ejabberd-contrib) 中找到挂钩示例