class RubyPushNotifications::APNS::APNSPusher

This class coordinates the process of sending notifications. It takes care of reopening closed APNSConnections and seeking back to the failed notification to keep writing.

Remember that APNS doesn't confirm successful notification, it just notifies when one went wrong and closes the connection. Therefore, this APNSPusher reconnects and rewinds the array until the notification that Apple rejected.

@author Carlos Alonso

Public Class Methods

new(certificate, sandbox, password = nil, options = {}) click to toggle source

@param certificate [String]. The PEM encoded APNS certificate. @param sandbox [Boolean]. Whether the certificate is an APNS sandbox or not. @param options [Hash] optional. Options for APNSPusher. Currently supports:

* host [String]: Hostname of the APNS environment. Defaults to the official APNS hostname.
* connect_timeout [Integer]: Number of seconds to wait for the connection to open. Defaults to 30.
# File lib/ruby-push-notifications/apns/apns_pusher.rb, line 21
def initialize(certificate, sandbox, password = nil, options = {})
  @certificate = certificate
  @pass = password
  @sandbox = sandbox
  @options = options
end

Public Instance Methods

push(notifications) click to toggle source

Pushes the notifications. Builds an array with all the binaries (one for each notification and receiver) and pushes them sequentially to APNS monitoring the response. If an error is received, the connection is reopened and the process continues at the next notification after the failed one (pointed by the response error)

For each notification assigns an array with the results of each submission.

@param notifications [Array]. All the APNSNotifications to be sent.

# File lib/ruby-push-notifications/apns/apns_pusher.rb, line 37
def push(notifications)
  conn = APNSConnection.open @certificate, @sandbox, @pass, @options

  binaries = notifications.each_with_object([]) do |notif, binaries|
    notif.each_message(binaries.count) do |msg|
      binaries << msg
    end
  end

  results = []
  i = 0
  while i < binaries.count
    conn.write binaries[i]

    if i == binaries.count-1
      conn.flush
      rs, = IO.select([conn], nil, nil, 2)
    else
      rs, = IO.select([conn], [conn])
    end
    if rs && rs.any?
      packed = rs[0].read 6
      if packed.nil? && i == 0
        # The connection wasn't properly open
        # Probably because of wrong certificate/sandbox? combination
        results << UNKNOWN_ERROR_STATUS_CODE
      else
        err = packed.unpack 'ccN'
        results.slice! err[2]..-1
        results << err[1]
        i = err[2]
        conn = APNSConnection.open @certificate, @sandbox, @pass, @options
      end
    else
      results << NO_ERROR_STATUS_CODE
    end
    i += 1
  end

  conn.close

  notifications.each do |notif|
    notif.results = APNSResults.new(results.slice! 0, notif.count)
  end
end