-
Notifications
You must be signed in to change notification settings - Fork 0
/
apns_gateway.rb
executable file
·158 lines (129 loc) · 3.72 KB
/
apns_gateway.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#!/usr/bin/env ruby -wKU
$LOAD_PATH << File.dirname(__FILE__)
require 'rubygems'
# require 'main'
require 'eventmachine'
require 'memcache'
require 'logger'
require 'active_support/core_ext/hash/keys'
class Hash
include ActiveSupport::CoreExtensions::Hash::Keys
end
require 'lib/apns'
# set up logger
# ApnsGateway.logger = Logger.new(File.join(File.dirname(__FILE__), 'apns_gateway.log'))
# ApnsGateway.logger.formatter = Logger::Formatter.new
$logger = Logger.new(STDERR)
INCOMING_QUEUE = 'to_apns'
def logger
$logger
end
def config
config_path = File.join(File.dirname(__FILE__), 'config', 'apns.yml')
@@config ||= YAML.load_file(config_path).symbolize_keys
@@config
rescue
logger.fatal "Could not load config: #{$!}"
exit!
end
class EmHandler < EventMachine::Connection
def initialize(config, channel)
@config = config
@channel = channel
end
def connection_completed
start_tls(:private_key_file => File.join(File.dirname(__FILE__), 'config', @config[:key_file]),
:cert_chain_file => File.join(File.dirname(__FILE__), 'config', @config[:cert_file]),
:verify_peer => false)
end
def ssl_handshake_completed
logger.info "SSL Session Established"
# logger.debug "Got Peer Certificate:\n" + get_peer_cert
@sid = @channel.subscribe do |x|
logger.debug "Sending to APNS: #{x.inspect}"
send_data(x)
end
end
def unbind
@channel.unsubscribe @sid
end
end
def decrease_poll_speed( opts )
unless opts['failing']
opts['failing'] = true
logger.error "Could not connect to Starling, decreasing poll frequency"
opts['timer'].interval = 30
end
end
def restore_poll_speed( opts )
if opts['failing']
opts['failing'] = false
logger.error "Reconnected to Starling, restoring poll frequency"
opts['timer'].interval = 1
end
end
def start(config)
logger.debug "Entering Start method."
channel = EM::Channel.new
starling = MemCache.new(config[:starling_addr])
# Run EventMachine in loop so we can reconnect when the SMSC drops our connection.
loop do
#
# Main EM Block
#
EventMachine::run do
logger.info "Attempting to connect to APNS"
EventMachine::connect( config[:host], config[:port], EmHandler, config, channel)
# This block will be called periodically to poll the Starling queue
@sx = {'failing' => false}
@sx['timer'] = EventMachine::PeriodicTimer.new(1) do
begin
to_send = starling.get(INCOMING_QUEUE)
rescue MemCache::MemCacheError
to_send = false
decrease_poll_speed( @sx )
else
restore_poll_speed( @sx )
end
if to_send
logger.info "Received message from Starling: #{to_send.inspect}"
begin
n = Apns::Notification.new(to_send[:device_token])
n.alert = to_send[:alert]
n.badge = to_send[:badge]
n.sound = to_send[:sound]
n.app_data = to_send[:app_data]
channel << n.apn_message_for_sending
rescue Exception => ex
logger.error "Error queuing Notification: #{ex} #{ex.backtrace[0]}"
end
end
end
end
#
# End Main EM Block
#
if $exiting
logger.info "Exiting"
break
else
logger.warn "Event loop stopped. Restarting in 5 seconds.."
sleep 5
end
end
end
def shutdown
logger.warn "Shutting down on SIGINT"
$exiting = true
# $tx.send_unbind if $tx.state == :bound
# sleep 5
EventMachine::stop_event_loop
end
trap("INT") { shutdown }
# Start the Gateway
begin
logger.info "Starting APNS Gateway"
start(config)
rescue Exception => ex
logger.fatal "#{ex.class} in APNS Gateway: \"#{ex}\" at\n #{ex.backtrace.join("\n")}"
end