lib/suj/pusher/apn_connection.rb in suj-pusher-0.2.0 vs lib/suj/pusher/apn_connection.rb in suj-pusher-0.2.3

- old
+ new

@@ -1,6 +1,7 @@ require "eventmachine" +require "iobuffer" require "base64" module Suj module Pusher class APNConnection < EM::Connection @@ -14,20 +15,22 @@ 4 => "Missing payload", 5 => "Invalid token size", 6 => "Invalid topic size", 7 => "Invalid payload size", 8 => "Invalid token", + 10 => "Shutdown", 255 => "Unknown error" } def initialize(pool, options = {}) super @disconnected = true @pool = pool @options = options @cert_key = Digest::SHA1.hexdigest(@options[:cert]) @cert_file = File.join(Suj::Pusher.config.certs_path, @cert_key) + @buffer = IO::Buffer.new File.open(@cert_file, "w") do |f| f.write @options[:cert] end @ssl_options = { private_key_file: @cert_file, @@ -40,55 +43,70 @@ @disconnected end def deliver(data) begin - @notification = Suj::Pusher::ApnNotification.new(data) + @notifications = [] + data[:apn_ids].each do |apn_id| + @notifications << Suj::Pusher::ApnNotification.new(data.merge({token: apn_id})) + end if ! disconnected? info "APN delivering data" - send_data(@notification.data) - @notification = nil + send_data(@notifications.join) + info "APN push notification sent" + @notifications = nil info "APN delivered data" else info "APN connection unavailable" end rescue Suj::Pusher::ApnNotification::PayloadTooLarge => e error "APN notification payload too large." - debug @notification.data.inspect + debug @notifications.join.inspect rescue => ex error "APN notification error : #{ex}" end end def post_init info "APN Connection init " start_tls(@ssl_options) end + # Receives error data from APN servers. Each error is 6 bytes long + # and contains: + # + # cmd -> 1 byte unsigned integer that is always 8 + # status -> 1 byte unsigned integer that indicates the error + # See ERRORS array for a list + # id -> 4 byte message ID set when the message was sent def receive_data(data) - cmd, status, id = data.unpack("ccN") - if status != 0 - error "APN push error received: #{ERRORS[status]}" - else - info "APN push notification sent" + @buffer << data + while @buffer.size >= 6 + res = @buffer.read(6) + cmd, status, id = data.unpack("CCN") + if cmd != 8 + error "APN push response command differs from 8" + elsif status != 0 + error "APN push error received: #{ERRORS[status]} for id #{id}" + end end end def connection_completed info "APN Connection established..." @disconnected = false - if ! @notification.nil? + if ! @notifications.nil? info "EST - APN delivering data" - send_data(@notification.data) - @notification = nil + send_data(@notifications.join) + info "APN push notification sent" + @notifications = nil info "EST - APN delivered data" end end def unbind info "APN Connection closed..." @disconnected = true - FileUtils.rm_f(@cert_file) @pool.remove_connection(@cert_key) end end end end