У меня была одна и та же проблема, и я решил две вещи:
- Поместите некоторую логику автоматического переподключения: я стараюсь поддерживать соединение как можно дольше, но Apple время от времени отключает вас. Будьте готовы справиться с этим.
- Переход к расширенному интерфейсу: при использовании простого интерфейса (это то, что используют гем APNS и многие другие) ошибки приводят к отключению без какой-либо обратной связи. Если вы переключитесь на расширенный формат , вы будете получать целое число каждый раз, когда что-то происходит. Плохие токены приведут к возвращению 8, и я использую это для удаления устройства из моей базы данных.
Вот мой текущий код подключения, используя EventMachine:
module Apns
module SocketHandler
def initialize(wrapper)
@wrapper = wrapper
end
def post_init
start_tls(:cert_chain_file => @wrapper.pem_path,
:private_key_file => @wrapper.rsa_path,
:verify_peer => false)
end
def receive_data(data)
@wrapper.read_data!(data)
end
def unbind
@wrapper.connection_closed!
end
def write(data)
begin
send_data(data)
rescue => exc
@wrapper.connection_error!(exc)
end
end
def close!
close_connection
end
end
class Connection
attr_reader :pem_path, :rsa_path
def initialize(host, port, credentials_path, monitoring, read_data_handler)
setup_credentials(credentials_path)
@monitoring = monitoring
@host = host
@port = port
@read_data_handler = read_data_handler
open_connection!
end
def write(data)
@connection.write(data)
end
def open?
@status == :open
end
def connection_closed!
@status = :closed
end
def connection_error!(exception)
@monitoring.inform_exception!(exception, self)
@status = :error
end
def close!
@connection.close!
end
def read_data!(data)
@read_data_handler.call(data)
end
private
def setup_credentials(credentials_path)
@pem_path = "#{credentials_path}.pem"
@rsa_path = "#{credentials_path}.rsa"
raise ArgumentError.new("#{credentials_path}.pem and #{credentials_path}.rsa must exist!") unless (File.exists?(@pem_path) and File.exists?(@rsa_path))
end
def open_connection!
@connection = EventMachine.connect(@host, @port, SocketHandler, self)
@status = :open
end
end
end
конец
конец
Он разделяет записи и чтения в соединении, используя поле идентификатора в уведомлении, для коррелированных уведомлений, которые я отправляю с полученной обратной связью.