Class: Suj::Pusher::APNConnection
- Inherits:
-
EM::Connection
- Object
- EM::Connection
- Suj::Pusher::APNConnection
- Includes:
- Logger
- Defined in:
- lib/suj/pusher/apn_connection.rb
Constant Summary collapse
- ERRORS =
{ 0 => "No errors encountered", 1 => "Processing error", 2 => "Missing device token", 3 => "Missing topic", 4 => "Missing payload", 5 => "Invalid token size", 6 => "Invalid topic size", 7 => "Invalid payload size", 8 => "Invalid token", 10 => "Shutdown", 255 => "Unknown error" }
- @@last_id =
0
Instance Method Summary collapse
- #connection_completed ⇒ Object
- #deliver(data) ⇒ Object
- #disconnected? ⇒ Boolean
-
#initialize(pool, options = {}) ⇒ APNConnection
constructor
A new instance of APNConnection.
- #options ⇒ Object
- #post_init ⇒ Object
-
#receive_data(data) ⇒ Object
Receives error data from APN servers.
- #unbind ⇒ Object
Constructor Details
#initialize(pool, options = {}) ⇒ APNConnection
Returns a new instance of APNConnection.
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/suj/pusher/apn_connection.rb', line 27 def initialize(pool, = {}) super @disconnected = true @pool = pool @options = @processing_ids = Vash.new @cert_key = Digest::SHA1.hexdigest(@options[:cert]) @cert_file = File.join(Suj::Pusher.config.certs_path, @cert_key) @buffer = IO::Buffer.new self.comm_inactivity_timeout = 60 # Close after 60 sec of inactivity File.open(@cert_file, "w") do |f| f.write @options[:cert] end @ssl_options = { private_key_file: @cert_file, cert_chain_file: @cert_file, verify_peer: false } end |
Instance Method Details
#connection_completed ⇒ Object
126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/suj/pusher/apn_connection.rb', line 126 def connection_completed info "APN Connection established..." @disconnected = false return if @notifications.nil? || @notifications.empty? info "EST - APN delivering data" send_data(@notifications.join) @notifications = nil info "EST - APN delivered data" end |
#deliver(data) ⇒ Object
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/suj/pusher/apn_connection.rb', line 57 def deliver(data) begin @notifications = [] data[:apn_ids].each do |apn_id| if ! @pool.valid_token?(@cert_key, apn_id) warn "Skipping invalid #{apn_id} APN id" next end notification = Suj::Pusher::ApnNotification.new(data.merge({token: apn_id, id: @@last_id})) @processing_ids[@@last_id.to_s] = apn_id @@last_id += 1 @notifications << notification end @processing_ids.cleanup! info "Processing list size #{@processing_ids.size}" if @notifications.empty? warn "No valid tokens, skip message" return end if disconnected? warn "Connection not ready yet, queue notifications for later" return end info "APN delivering data" send_data(@notifications.join) @notifications = nil info "APN delivered data" rescue Suj::Pusher::ApnNotification::PayloadTooLarge => e error "APN notification payload too large." debug @notifications.join.inspect rescue => ex error "APN notification error : #{ex}" error ex.backtrace end end |
#disconnected? ⇒ Boolean
53 54 55 |
# File 'lib/suj/pusher/apn_connection.rb', line 53 def disconnected? @disconnected end |
#options ⇒ Object
49 50 51 |
# File 'lib/suj/pusher/apn_connection.rb', line 49 def @options end |
#post_init ⇒ Object
97 98 99 100 |
# File 'lib/suj/pusher/apn_connection.rb', line 97 def post_init info "APN Connection init " start_tls(@ssl_options) end |
#receive_data(data) ⇒ Object
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
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/suj/pusher/apn_connection.rb', line 109 def receive_data(data) @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 == 8 token = @processing_ids[id.to_s] @pool.invalidate_token(@cert_key, token) warn "APN invalid (id: #{id}) token #{token}" elsif status != 0 error "APN push error received: #{ERRORS[status]} for id #{id}" end end end |
#unbind ⇒ Object
138 139 140 141 142 |
# File 'lib/suj/pusher/apn_connection.rb', line 138 def unbind info "APN Connection closed..." @disconnected = true @pool.remove_connection(@cert_key) end |