Как отправить push-уведомление с помощью Erlang? - PullRequest
20 голосов
/ 18 ноября 2009

Я пытаюсь отправить push-уведомление APN, используя Erlang. Это код, который я придумал до сих пор:

-module(apnstest2).
-export([connect/0]).

connect() ->
    application:start(ssl),
    ssl:seed("someseedstring"),
    Address = "gateway.sandbox.push.apple.com",
    Port = 2195,
    Cert = "/path/to/Certificate.pem",
    Key = "/path/to/Key.unenc.pem",
    Options = [{certfile, Cert}, {keyfile, Key}, {mode, binary}],
    Timeout = 1000,
    {ok, Socket} = ssl:connect(Address, Port, Options, Timeout),

    Token = "195ec05a962b24954693c0b638b6216579a0d1d74b3e1c6f534c6f8fd0d50d03",
    Payload = "{\"aps\":{\"alert\":\"Just testing.\",\"sound\":\"chime\", \"badge\":10}}",
    TokenLength = length(Token),
    PayloadLength = length(Payload),

    Packet = [<<0:8, TokenLength, Token, PayloadLength, Payload>>],

    ssl:send(Socket, list_to_binary(Packet)),
    ssl:close(Socket).

Код не использует преимущества параллелизма Эрланга, а является всего лишь прототипом. Я только хочу проверить, могу ли я отправить пуш самым простым способом.

Я думаю, проблема в том, что пакет отправляется в APN. Это двоичный формат push-уведомления:

альтернативный текст http://developer.apple.com/IPhone/library/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Art/aps_provider_binary.jpg

Как мне создать такой пакет в Erlang? Может кто-нибудь взглянуть на мой код и сказать, где проблема?
Также я использовал приложение SSL Erlang для создания соединения и отправки данных, и я не знаю, является ли это проблемой или пакетом.
Спасибо!

Ответы [ 2 ]

21 голосов
/ 18 ноября 2009

Начнем с того, что нет необходимости создавать список из одного двоичного файла и затем вызывать list_to_binary/1 для него. Вы можете просто отправить двоичный файл сам.

Кроме того, убедитесь, что длина поля и значения соответствуют протоколу:

TokenLength = 32 = length(Token),
Packet = <<0:8, TokenLength:16/big, Token, PayloadLength:16/big, Payload>>,
ssl:send(Socket, Packet),

Теперь, когда мы зашли так далеко, мы увидим, что длина (Token) на самом деле 64, а не 32: Вы забыли преобразовать шестнадцатеричную строку для токена в двоичный файл, поэтому вместо 32 двоичных байтов вы отправляете шестнадцатеричную символьную строку.

Итак ... сделав Payload двоичным с самого начала и сделав Token числовой константой, вы можете сделать что-то вроде следующего:

Payload = <<"{\"aps\":{\"alert\":\"Just testing.\",\"sound\":\"chime\", \"badge\":10}}">>,
PayloadLength = size(Payload),
Packet = <<0:8, 32:16/big,
          16#195ec05a962b24954693c0b638b6216579a0d1d74b3e1c6f534c6f8fd0d50d03:256/big,
          PayloadLength:16/big, Payload/binary>>,
ssl:send(Socket, Packet),

Спасибо Кристиану за указание на ряд ошибок в предыдущих редакциях этого ответа.

3 голосов
/ 18 ноября 2009

Я вижу две ошибки:

  • Маркер должен передаваться в двоичном, а не в шестнадцатеричном формате.
  • Нельзя использовать двоичный синтаксис для преобразования списков в двоичные файлы.

Для разбора шестнадцатеричного числа на целое, а затем на двоичное, используйте что-то вроде этого:

Token = "dead",
TokenNum = erlang:list_to_integer(Token, 16),
TokenBin = <<TokenNum:32/integer-unit:8>>,

Создайте пакет протокола примерно так:

TokenBin = ...,
Payload = <<"Payload">>,
PayloadSize = byte_size(Payload),
Packet = <<0:8, 32:16, TokenBin/binary, PayloadSize:16, Payload/binary>>,
...