Class: APN::Connection

Inherits:
Object
  • Object
show all
Includes:
Base
Defined in:
lib/apn/connection.rb

Constant Summary collapse

TIMES_TO_RETRY_SOCKET_ERROR =
2
IDLE_RECONNECTION_INTERVAL =
120

Constants included from Base

Base::FIFO_SIZE

Instance Attribute Summary

Attributes included from Base

#fifos, #logger, #opts

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Base

#initialize, #log, #log_and_die, #socket

Class Method Details

.current(sandbox = false, enterprise = false) ⇒ 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
# File 'lib/apn/connection.rb', line 57

def self.current(sandbox = false, enterprise = false)
  thread_id = Thread.current.object_id
  epoch = Time.now.to_i

  # Use only 1 single thread for internal enterprise cert
  if enterprise
    if @enterprise_senders[thread_id] && (epoch - @enterprise_last_accesses[thread_id]) > IDLE_RECONNECTION_INTERVAL
      @enterprise_senders[thread_id].reconnect
    end

    @enterprise_last_accesses[thread_id] = epoch
    @enterprise_senders[thread_id] ||= new(worker_count: 1, verbose: 1, enterprise: 1)
  elsif sandbox
    if @sandbox_senders[thread_id] && (epoch - @sandbox_last_accesses[thread_id]) > IDLE_RECONNECTION_INTERVAL
      @sandbox_senders[thread_id].reconnect
    end

    @sandbox_last_accesses[thread_id] = epoch
    @sandbox_senders[thread_id] ||= new(worker_count: 1, sandbox: 1, verbose: 1)
  else
    if @production_senders[thread_id] && (epoch - @production_last_accesses[thread_id]) > IDLE_RECONNECTION_INTERVAL
      @production_senders[thread_id].reconnect
    end

    @production_last_accesses[thread_id] = epoch
    @production_senders[thread_id] ||= new(worker_count: 1, verbose: 1)
  end
end

.send_apn(token, message, sandbox = false, enterprise = false, style = { format: :frame }) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/apn/connection.rb', line 86

def self.send_apn(token, message, sandbox = false, enterprise = false, style = { format: :frame })
  style.symbolize_keys!
  msg = APN::Notification.new(token, message, style.reverse_merge(identifier: token.byteslice(0, 4)))
  raise "Invalid notification message (did you provide :alert, :badge, :sound, or :'content-available'?): #{message.inspect}" unless msg.valid?

  sender = current(sandbox, enterprise)
  env = sandbox ? 'sandbox' : enterprise ? 'enterprise' : 'production'
  tag = "#{sandbox ? 'sandbox' : 'production'}#{enterprise ? ' enterprise' : ''}"
  sender.log(:info, "token: #{token} message: #{message}, style: #{style}")
  debug = style[:debug] || (style[:debug_sample] && rand(style[:debug_sample].to_i) == 0)
  sender.send_to_apple(msg, token, env, tag, debug)
  sender
end

Instance Method Details

#error_responseObject



19
20
21
22
23
24
25
26
# File 'lib/apn/connection.rb', line 19

def error_response
  if socket.flush && IO.select([socket], nil, nil, 1) && (error = socket.read(6))
    error = error.unpack("ccA*")
    log(:error, "Error response: #{error}")
  end

  error
end

#push_fifo(env, token) ⇒ Object



14
15
16
17
# File 'lib/apn/connection.rb', line 14

def push_fifo(env, token)
  @fifos[env] <<= token
  @fifos[env].shift if @fifos[env][FIFO_SIZE]
end

#reconnectObject



51
52
53
54
55
# File 'lib/apn/connection.rb', line 51

def reconnect
  teardown_connection
  sleep 1
  setup_connection
end

#send_to_apple(notification, token, env, tag, debug = false) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/apn/connection.rb', line 28

def send_to_apple(notification, token, env, tag, debug = false)
  retries = 0
  push_fifo(env, token)

  begin
    socket.write(notification.to_s)
    return false if debug && error_response

    true
  rescue => e
    log(:error, "Try #{retries}: #{e.class} to #{apn_host}: #{e.message}, recent_tokens: #{@fifos[env]}")

    # Try reestablishing the connection
    if (retries += 1) <= TIMES_TO_RETRY_SOCKET_ERROR
      reconnect
      retry
    end

    log(:error, "#{e.class} to #{apn_host}: #{e.message}, recent_tokens: #{@fifos[env]}")
    raise e
  end
end