我正在编写一个ejabberd挂钩,以与Apple Push Notification Server创建外发SSL连接。我已经在ejabberd之外(在erlang解释器中)测试了send方法,并可以验证它是否有效。我不确定为什么该模块:

-module(mod_http_offline).

-author("Joseph Martin").

%% Every ejabberd module implements the gen_mod behavior
%% The gen_mod behavior requires two functions: start/2 and stop/1
-behaviour(gen_mod).

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

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

%% ejabberd functions for JID manipulation called jlib.
-include("jlib.hrl").

start(_Host, _Opt) ->
        ?INFO_MSG("mod_http_offline loading", []),
        %send("Test Push"),
        ejabberd_hooks:add(offline_message_hook, _Host, ?MODULE, create_message, 50).


stop (_Host) ->
        ?INFO_MSG("stopping mod_http_offline", []),
        ejabberd_hooks:delete(offline_message_hook, _Host, ?MODULE, create_message, 50).


create_message(_From, _To, Packet) ->
        Type = xml:get_tag_attr_s("type", Packet),
        FromS = xml:get_tag_attr_s("from", Packet),
        ToS = xml:get_tag_attr_s("to", Packet),
        Body = xml:get_path_s(Packet, [{elem, "body"}, cdata]),
        if (Type == "chat") ->
            send("You did it!","10","Chime")
        end.

% All argument fields expect a string
send(Msg) ->
  send_pn([{alert, Msg}]).
% send a string and and a bagde number
send(Msg, Badge) ->
  send_pn([{alert, Msg}, {badge, Badge}]).
% send a string, a badge number and play a sound
send(Msg, Badge, Sound) ->
  send_pn([{alert, Msg}, {badge, Badge}, {sound, Sound}]).

send_pn(Msg) ->

  % start ssl
    ssl:start(),
  % application:start(ssl),

  % socket configuration, may need to increase the timeout if concurrency becomes an issue
  Address = "gateway.sandbox.push.apple.com",
  % Address = "gateway.push.apple.com",
  Port = 2195,
  Cert = "/Users/joemartin/Desktop/PushNotificationCertificates/PushChatCert.pem",
  Key  = "/Users/joemartin/Desktop/PushNotificationCertificates/PushChatKey.pem",
  Options = [{certfile, Cert}, {keyfile, Key}, {password, "mypassword"}, {mode, binary}, {verify, verify_none}],
  Timeout = 5000,

  case ssl:connect(Address, Port, Options, Timeout) of
    {ok, Socket} ->

      % Convert the device token from hex to int to binary
      Token = "3eca19d7...mydevicetokenstring",
      TokenNum = erlang:list_to_integer(Token, 16),
      TokenBin = <<TokenNum:32/integer-unit:8>>,

      % Construct the protocol packet
      PayloadString = create_json(Msg),
      Payload = list_to_binary(PayloadString),
      PayloadLength = byte_size(Payload),
      Packet = <<0:8, 32:16, TokenBin/binary, PayloadLength:16, Payload/binary>>,

      % Send the packet then close the socket
      ssl:send(Socket, Packet),
      ssl:close(Socket),

      % Return the PayloadString (for debugging purposes)
      PayloadString;
    {error, Reason} ->
        ?INFO_MSG("THE SSL CONNECTION FAILED", []),
      Reason
  end.

% helper for creating json
create_json(List) ->
  lists:append(["{\"aps\":{", create_keyvalue(List), "}}"]).

create_keyvalue([Head]) ->
  create_pair(Head);

create_keyvalue([Head|Tail]) ->
  lists:append([create_pair(Head), ",", create_keyvalue(Tail)]).

create_pair({Key, Value}) ->
  lists:append([add_quotes(atom_to_list(Key)), ":", add_quotes(Value)]).

add_quotes(String) ->
  lists:append(["\"", String, "\""]).


在我的错误日志中创建此stacktrace:

=ERROR REPORT==== 2013-12-31 16:23:57 ===
E(<0.1558.0>:ejabberd_hooks:294) : {undef,
                                    [{tls,connect,
                                      ["gateway.sandbox.push.apple.com",2195,
                                       [{certfile,
                                         "/Users/joemartin/Desktop/PushNotificationCertificates/PushChatCert.pem"},
                                        {keyfile,
                                         "/Users/joemartin/Desktop/PushNotificationCertificates/PushChatKey.pem"},
                                        {password,"mypassword"},
                                        {mode,binary},
                                        {verify,verify_none}],
                                       5000],
                                      []},
                                     {mod_http_offline,send_pn,1,
                                      [{file,"mod_http_offline.erl"},
                                       {line,69}]},
                                     {ejabberd_hooks,run1,3,
                                      [{file,"ejabberd_hooks.erl"},
                                       {line,290}]},
                                     {ejabberd_sm,route,3,
                                      [{file,"ejabberd_sm.erl"},{line,87}]},
                                     {ejabberd_local,route,3,
                                      [{file,"ejabberd_local.erl"},
                                       {line,120}]},
                                     {ejabberd_router,route,3,
                                      [{file,"ejabberd_router.erl"},
                                       {line,68}]},
                                     {ejabberd_c2s,session_established2,2,
                                      [{file,"ejabberd_c2s.erl"},{line,1122}]},
                                     {p1_fsm,handle_msg,10,
                                      [{file,"p1_fsm.erl"},{line,544}]}]}


我读过ejabberd 2默认情况下禁用了旧式SSL,但认为这仅用于传入的客户端连接。我也没有找到一个建立出站SSL连接的钩子的好例子。我也意识到名称mod_http_offline是一个错误的名称。有任何想法吗?

谢谢,
   乔

最佳答案

我看到它在ejabberd buglist on github上报告了。

只是为了让它降级一个或另一个。
要解决生产问题,请根据您的需求定制依赖项。

重新命名模块名称,确保其唯一且与开始/停止回调一致。遵守约定并具有mod前缀可能会很好。新名称也将进入ejabberd.cfg(在“模块”部分中)。

关于ssl - 使用ejabberd Hook 建立传出SSL连接,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20863528/

10-13 02:06