suj-pusher 0.2.0 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +6 -18
- data/bin/pusher +1 -0
- data/lib/suj/pusher.rb +0 -2
- data/lib/suj/pusher/apn_connection.rb +31 -13
- data/lib/suj/pusher/apn_feedback_connection.rb +21 -4
- data/lib/suj/pusher/apn_notification.rb +29 -6
- data/lib/suj/pusher/connection_pool.rb +31 -14
- data/lib/suj/pusher/daemon.rb +63 -51
- data/lib/suj/pusher/version.rb +1 -1
- metadata +21 -10
data/README.md
CHANGED
@@ -4,11 +4,11 @@ This is a simple but enterprise level pusher server that can push notifications
|
|
4
4
|
|
5
5
|
## Features
|
6
6
|
|
7
|
-
-
|
8
|
-
-
|
9
|
-
-
|
7
|
+
- EventMachine based for efficient use of resources.
|
8
|
+
- Support both APN, GCM, WNS, and WPNS push services with a simple unified json API interface.
|
9
|
+
- Keep persistent connections to APN following Apple's recommendations.
|
10
|
+
- Uses the APN protocol version 2 for batched notifications.
|
10
11
|
- No need to set APN certificates or GCM api keys in configuration files or pusher startup. These are sent in a per request basis. This allows support for multiple APN certs and GCM api keys in a single Pusher instance.
|
11
|
-
- EventMachine based to handle in the order of thousands of push requests per second.
|
12
12
|
|
13
13
|
## Installation
|
14
14
|
|
@@ -113,15 +113,8 @@ When sending push notifications to iOS devices you must provide an aps hash insi
|
|
113
113
|
|
114
114
|
Read the [official documentation](http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html#//apple_ref/doc/uid/TP40008194-CH100-SW1) for details on the *aps* hash format. Note that this hash must not exceed the 256 bytes or it will be rejected by the APN service.
|
115
115
|
|
116
|
-
#### Sending one message to both APN and GCM
|
117
|
-
|
118
|
-
Normally you would send messages to either Android or iOS indenpendently. But the pusher daemon can send the same message to devices on both networks as long as you follow the Apple restrictions. This is because Apple push messages are more limited than GCM.
|
119
|
-
|
120
|
-
If your data hash is compatible with the APN standard as described above and you specify a APN cert, a GCM api_key, a list of apn_ids and a list of gcm_ids then the message will be delivered via push notification to all the devices in those lists. Apple will display the notifications using their own mechanisms and for Android you will receive the data hash in a Bundle object as usual. Is your responsibility to extract the data from that bundle and display/use it as you please.
|
121
|
-
|
122
|
-
|
123
|
-
|
124
116
|
#### Sending one message to WNS
|
117
|
+
|
125
118
|
message hash: {
|
126
119
|
wnstype: "type" ,
|
127
120
|
wnsrequeststatus: true,
|
@@ -136,7 +129,6 @@ secret and sid: App identification credentials provided by microsoft when regist
|
|
136
129
|
wnsrequeststatus: boolean, if true, the response from wns server will have aditional information
|
137
130
|
wnsids: jsonArray of target devices.
|
138
131
|
|
139
|
-
|
140
132
|
#### Sending one message to WPNS
|
141
133
|
message hash: { wptype: "type",
|
142
134
|
wpids: ["xxx"],
|
@@ -150,8 +142,6 @@ secret: a unic hash to identify a conection, internal use, each notification sen
|
|
150
142
|
wpids: jsonArray of ids for target devices
|
151
143
|
data: notification data to send, please use de xsml template provided by Microsoft(http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh202945(v=vs.105).aspx) for each wptype listed above
|
152
144
|
|
153
|
-
|
154
|
-
|
155
145
|
## Examples
|
156
146
|
|
157
147
|
A simple example using ruby code to send a push notification to iOS devices.
|
@@ -181,11 +171,9 @@ redis = Redis.new({ host: "localhost", port: 6379})
|
|
181
171
|
# Push the message to the *suj_pusher_queue* in the redis server:
|
182
172
|
redis.lpush "pusher:suj_pusher_msgs", msg_json
|
183
173
|
|
184
|
-
# Notify workers there is a new message
|
185
|
-
redis.publish "pusher:suj_pusher_queue", "PUSH_MSG"
|
186
174
|
```
|
187
175
|
|
188
|
-
|
176
|
+
Once you push the JSON message to the *suj_pusher_msgs* queue the pusher workers will retrieve and process it.
|
189
177
|
|
190
178
|
## Issues
|
191
179
|
|
data/bin/pusher
CHANGED
data/lib/suj/pusher.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "eventmachine"
|
2
|
+
require "iobuffer"
|
2
3
|
|
3
4
|
require "base64"
|
4
5
|
module Suj
|
@@ -16,6 +17,7 @@ module Suj
|
|
16
17
|
6 => "Invalid topic size",
|
17
18
|
7 => "Invalid payload size",
|
18
19
|
8 => "Invalid token",
|
20
|
+
10 => "Shutdown",
|
19
21
|
255 => "Unknown error"
|
20
22
|
}
|
21
23
|
|
@@ -26,6 +28,7 @@ module Suj
|
|
26
28
|
@options = options
|
27
29
|
@cert_key = Digest::SHA1.hexdigest(@options[:cert])
|
28
30
|
@cert_file = File.join(Suj::Pusher.config.certs_path, @cert_key)
|
31
|
+
@buffer = IO::Buffer.new
|
29
32
|
File.open(@cert_file, "w") do |f|
|
30
33
|
f.write @options[:cert]
|
31
34
|
end
|
@@ -42,18 +45,22 @@ module Suj
|
|
42
45
|
|
43
46
|
def deliver(data)
|
44
47
|
begin
|
45
|
-
@
|
48
|
+
@notifications = []
|
49
|
+
data[:apn_ids].each do |apn_id|
|
50
|
+
@notifications << Suj::Pusher::ApnNotification.new(data.merge({token: apn_id}))
|
51
|
+
end
|
46
52
|
if ! disconnected?
|
47
53
|
info "APN delivering data"
|
48
|
-
send_data(@
|
49
|
-
|
54
|
+
send_data(@notifications.join)
|
55
|
+
info "APN push notification sent"
|
56
|
+
@notifications = nil
|
50
57
|
info "APN delivered data"
|
51
58
|
else
|
52
59
|
info "APN connection unavailable"
|
53
60
|
end
|
54
61
|
rescue Suj::Pusher::ApnNotification::PayloadTooLarge => e
|
55
62
|
error "APN notification payload too large."
|
56
|
-
debug @
|
63
|
+
debug @notifications.join.inspect
|
57
64
|
rescue => ex
|
58
65
|
error "APN notification error : #{ex}"
|
59
66
|
end
|
@@ -64,22 +71,34 @@ module Suj
|
|
64
71
|
start_tls(@ssl_options)
|
65
72
|
end
|
66
73
|
|
74
|
+
# Receives error data from APN servers. Each error is 6 bytes long
|
75
|
+
# and contains:
|
76
|
+
#
|
77
|
+
# cmd -> 1 byte unsigned integer that is always 8
|
78
|
+
# status -> 1 byte unsigned integer that indicates the error
|
79
|
+
# See ERRORS array for a list
|
80
|
+
# id -> 4 byte message ID set when the message was sent
|
67
81
|
def receive_data(data)
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
82
|
+
@buffer << data
|
83
|
+
while @buffer.size >= 6
|
84
|
+
res = @buffer.read(6)
|
85
|
+
cmd, status, id = data.unpack("CCN")
|
86
|
+
if cmd != 8
|
87
|
+
error "APN push response command differs from 8"
|
88
|
+
elsif status != 0
|
89
|
+
error "APN push error received: #{ERRORS[status]} for id #{id}"
|
90
|
+
end
|
73
91
|
end
|
74
92
|
end
|
75
93
|
|
76
94
|
def connection_completed
|
77
95
|
info "APN Connection established..."
|
78
96
|
@disconnected = false
|
79
|
-
if ! @
|
97
|
+
if ! @notifications.nil?
|
80
98
|
info "EST - APN delivering data"
|
81
|
-
send_data(@
|
82
|
-
|
99
|
+
send_data(@notifications.join)
|
100
|
+
info "APN push notification sent"
|
101
|
+
@notifications = nil
|
83
102
|
info "EST - APN delivered data"
|
84
103
|
end
|
85
104
|
end
|
@@ -87,7 +106,6 @@ module Suj
|
|
87
106
|
def unbind
|
88
107
|
info "APN Connection closed..."
|
89
108
|
@disconnected = true
|
90
|
-
FileUtils.rm_f(@cert_file)
|
91
109
|
@pool.remove_connection(@cert_key)
|
92
110
|
end
|
93
111
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "eventmachine"
|
2
|
+
require "iobuffer"
|
2
3
|
|
3
4
|
require "base64"
|
4
5
|
module Suj
|
@@ -6,12 +7,15 @@ module Suj
|
|
6
7
|
class APNFeedbackConnection < EM::Connection
|
7
8
|
include Suj::Pusher::Logger
|
8
9
|
|
9
|
-
def initialize(options = {})
|
10
|
+
def initialize(pool, options = {})
|
10
11
|
super
|
11
12
|
@disconnected = true
|
12
13
|
@options = options
|
13
|
-
@
|
14
|
+
@pool = pool
|
15
|
+
@cert_key = Digest::SHA1.hexdigest("FEEDBACK" + @options[:cert])
|
14
16
|
@cert_file = File.join(Suj::Pusher.config.certs_path, @cert_key)
|
17
|
+
@buffer = IO::Buffer.new
|
18
|
+
self.comm_inactivity_timeout = 10 # Close after 10 sec of inactivity
|
15
19
|
File.open(@cert_file, "w") do |f|
|
16
20
|
f.write @options[:cert]
|
17
21
|
end
|
@@ -31,9 +35,21 @@ module Suj
|
|
31
35
|
start_tls(@ssl_options)
|
32
36
|
end
|
33
37
|
|
38
|
+
# Receive feedback data from APN servers.
|
39
|
+
#
|
40
|
+
# The format is:
|
41
|
+
#
|
42
|
+
# timestamp -> 4 byte bigendian
|
43
|
+
# len -> 2 byte token length
|
44
|
+
# token -> 32 bytes token
|
34
45
|
def receive_data(data)
|
35
|
-
|
36
|
-
|
46
|
+
@buffer << data
|
47
|
+
|
48
|
+
while @buffer.size >= 38
|
49
|
+
timestamp, size = @buffer.read(6).unpack("Nn")
|
50
|
+
token = @buffer.read(size)
|
51
|
+
puts " FEEDBACK TIMESTAMP: #{timestamp} SIZE: #{size} TOKEN: #{token}"
|
52
|
+
end
|
37
53
|
end
|
38
54
|
|
39
55
|
def connection_completed
|
@@ -44,6 +60,7 @@ module Suj
|
|
44
60
|
def unbind
|
45
61
|
info "APN Feedback Connection closed..."
|
46
62
|
@disconnected = true
|
63
|
+
@pool.remove_connection(@cert_key)
|
47
64
|
end
|
48
65
|
end
|
49
66
|
end
|
@@ -23,6 +23,10 @@ module Suj
|
|
23
23
|
@data ||= encode_data
|
24
24
|
end
|
25
25
|
|
26
|
+
def to_s
|
27
|
+
data
|
28
|
+
end
|
29
|
+
|
26
30
|
private
|
27
31
|
|
28
32
|
def get_expiry
|
@@ -34,12 +38,31 @@ module Suj
|
|
34
38
|
end
|
35
39
|
|
36
40
|
def encode_data
|
37
|
-
identifier = 0
|
38
|
-
expiry = get_expiry
|
39
|
-
size = [payload].pack("a*").size
|
40
|
-
data_array = [1, identifier, expiry, 32, @token, size, payload]
|
41
|
-
info("PAYLOAD: #{data_array}")
|
42
|
-
data_array.pack("cNNnH*na*")
|
41
|
+
# identifier = 0
|
42
|
+
# expiry = get_expiry
|
43
|
+
# size = [payload].pack("a*").size
|
44
|
+
# data_array = [1, identifier, expiry, 32, @token, size, payload]
|
45
|
+
# info("PAYLOAD: #{data_array}")
|
46
|
+
# data_array.pack("cNNnH*na*")
|
47
|
+
|
48
|
+
items = [
|
49
|
+
[1, 32, @token ], # token
|
50
|
+
[2, payload.bytesize, payload ], # payload
|
51
|
+
[3, 4, OpenSSL::Random::random_bytes(4) ], # random identifier
|
52
|
+
[4, 4, get_expiry ], # expiration date
|
53
|
+
[5, 1, 10 ] # high priority
|
54
|
+
]
|
55
|
+
|
56
|
+
info("PAYLOAD: #{items}")
|
57
|
+
|
58
|
+
frame_data =
|
59
|
+
items[0].pack("CnH*") +
|
60
|
+
items[1].pack("CnA*") +
|
61
|
+
items[2].pack("CnA*") +
|
62
|
+
items[3].pack("CnN") +
|
63
|
+
items[4].pack("CnC")
|
64
|
+
|
65
|
+
[2,frame_data.bytesize,frame_data].pack("CNA*")
|
43
66
|
end
|
44
67
|
end
|
45
68
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "base64"
|
2
|
+
require "thread"
|
2
3
|
require File.join File.dirname(File.expand_path(__FILE__)), "apn_connection.rb"
|
3
4
|
require File.join File.dirname(File.expand_path(__FILE__)), "gcm_connection.rb"
|
4
5
|
|
@@ -17,61 +18,77 @@ module Suj
|
|
17
18
|
def initialize(daemon)
|
18
19
|
@pool = {}
|
19
20
|
@daemon = daemon
|
21
|
+
@mutex = Mutex.new
|
20
22
|
end
|
21
23
|
|
22
24
|
def apn_connection(options = {})
|
23
25
|
cert = Digest::SHA1.hexdigest options[:cert]
|
24
26
|
info "APN connection #{cert}"
|
25
|
-
@
|
27
|
+
@mutex.synchronize do
|
28
|
+
@pool[cert] ||= EM.connect(APN_GATEWAY, APN_PORT, APNConnection, self, options)
|
29
|
+
end
|
26
30
|
end
|
27
31
|
|
28
32
|
def apn_sandbox_connection(options = {})
|
29
33
|
cert = Digest::SHA1.hexdigest options[:cert]
|
30
34
|
info "APN connection #{cert}"
|
31
|
-
@
|
35
|
+
@mutex.synchronize do
|
36
|
+
@pool[cert] ||= EM.connect(APN_SANDBOX, APN_PORT, APNConnection, self, options)
|
37
|
+
end
|
32
38
|
end
|
33
39
|
|
34
40
|
def feedback_connection(options = {})
|
35
|
-
|
36
|
-
|
41
|
+
cert = Digest::SHA1.hexdigest("FEEDBACK" + options[:cert])
|
42
|
+
info "APN Feedback connection #{cert}"
|
43
|
+
@mutex.synchronize do
|
44
|
+
@pool[cert] ||= EM.connect(FEEDBACK_GATEWAY, FEEDBACK_PORT, APNFeedbackConnection, self, options)
|
45
|
+
end
|
37
46
|
end
|
38
47
|
|
39
48
|
def feedback_sandbox_connection(options = {})
|
40
|
-
info "Feedback
|
41
|
-
|
49
|
+
info "Feedback connection"
|
50
|
+
cert = Digest::SHA1.hexdigest("FEEDBACK" + options[:cert])
|
51
|
+
info "APN Sandbox Feedback connection #{cert}"
|
52
|
+
@mutex.synchronize do
|
53
|
+
@pool[cert] ||= EM.connect(FEEDBACK_SANDBOX, FEEDBACK_PORT, APNFeedbackConnection, self, options)
|
54
|
+
end
|
42
55
|
end
|
43
56
|
|
44
57
|
def gcm_connection(options = {})
|
45
58
|
# All GCM connections are unique, even if they are to the same app.
|
46
59
|
api_key = "#{options[:api_key]}#{rand * 100}"
|
47
60
|
info "GCM connection #{api_key}"
|
48
|
-
@
|
61
|
+
@mutex.synchronize do
|
62
|
+
@pool[api_key] ||= Suj::Pusher::GCMConnection.new(self, api_key, options)
|
63
|
+
end
|
49
64
|
end
|
50
65
|
|
51
66
|
def apn_connection(options = {})
|
52
67
|
cert = Digest::SHA1.hexdigest options[:cert]
|
53
68
|
info "APN connection #{cert}"
|
54
|
-
@
|
69
|
+
@mutex.synchronize do
|
70
|
+
@pool[cert] ||= EM.connect(APN_GATEWAY, APN_PORT, APNConnection, self, options)
|
71
|
+
end
|
55
72
|
end
|
56
73
|
|
57
74
|
def wns_connection(options = {})
|
58
75
|
cert = Digest::SHA1.hexdigest options[:secret]
|
59
76
|
info "WNS connection #{cert}"
|
60
77
|
info "WNS Options #{options}"
|
61
|
-
@
|
78
|
+
@mutex.synchronize do
|
79
|
+
@pool[cert] ||= Suj::Pusher::WNSConnection.new(self,options)
|
80
|
+
end
|
62
81
|
end
|
63
82
|
|
64
83
|
def wpns_connection(options = {})
|
65
84
|
cert = Digest::SHA1.hexdigest options[:secret]
|
66
85
|
info "WPNS connection #{cert}"
|
67
86
|
info "WPNS Options #{options}"
|
68
|
-
@
|
69
|
-
|
87
|
+
@mutex.synchronize do
|
88
|
+
@pool[cert] ||= Suj::Pusher::WPNSConnection.new(self,options)
|
89
|
+
end
|
70
90
|
end
|
71
91
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
92
|
def remove_connection(key)
|
76
93
|
info "Removing connection #{key}"
|
77
94
|
info "Connection not found" unless @pool.delete(key)
|
data/lib/suj/pusher/daemon.rb
CHANGED
@@ -16,22 +16,10 @@ module Suj
|
|
16
16
|
def start
|
17
17
|
info "Starting pusher daemon"
|
18
18
|
info " subsribe to push messages from #{redis_url} namespace #{redis_namespace}"
|
19
|
+
@last_feedback = Time.now
|
20
|
+
@last_sandbox_feedback = Time.now
|
19
21
|
EM.run do
|
20
|
-
wait_msg
|
21
|
-
begin
|
22
|
-
info "RECEIVED MESSAGE"
|
23
|
-
data = Hash.symbolize_keys(MultiJson.load(msg))
|
24
|
-
send_notification(data)
|
25
|
-
info "SENT MESSAGE"
|
26
|
-
retrieve_feedback(data)
|
27
|
-
info "FINISHED FEEDBACK RETRIEVAL"
|
28
|
-
rescue MultiJson::LoadError
|
29
|
-
warn("Received invalid json data, discarding msg")
|
30
|
-
rescue => e
|
31
|
-
error("Error sending notification : #{e}")
|
32
|
-
error e.backtrace
|
33
|
-
end
|
34
|
-
end
|
22
|
+
wait_msg
|
35
23
|
end
|
36
24
|
end
|
37
25
|
|
@@ -47,28 +35,25 @@ module Suj
|
|
47
35
|
private
|
48
36
|
|
49
37
|
def wait_msg
|
50
|
-
redis.
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
if message
|
64
|
-
yield message
|
65
|
-
else
|
66
|
-
info "REDIS - PUSH_MSG Queue was empty"
|
67
|
-
end
|
68
|
-
end
|
69
|
-
else
|
70
|
-
yield msg
|
38
|
+
defer = redis.brpop "#{redis_namespace}:#{MSG_QUEUE}", 0
|
39
|
+
defer.callback do |_, msg|
|
40
|
+
begin
|
41
|
+
info "RECEIVED MESSAGE"
|
42
|
+
data = Hash.symbolize_keys(MultiJson.load(msg))
|
43
|
+
send_notification(data)
|
44
|
+
info "SENT MESSAGE"
|
45
|
+
retrieve_feedback(data)
|
46
|
+
rescue MultiJson::LoadError
|
47
|
+
warn("Received invalid json data, discarding msg")
|
48
|
+
rescue => e
|
49
|
+
error("Error sending notification : #{e}")
|
50
|
+
error e.backtrace
|
71
51
|
end
|
52
|
+
EM.next_tick { wait_msg }
|
53
|
+
end
|
54
|
+
defer.errback do |e|
|
55
|
+
error e
|
56
|
+
EM.next_tick { wait_msg }
|
72
57
|
end
|
73
58
|
end
|
74
59
|
|
@@ -105,28 +90,30 @@ module Suj
|
|
105
90
|
def send_apn_notification(msg)
|
106
91
|
info "Sending APN notification via connection #{Digest::SHA1.hexdigest(msg[:cert])}"
|
107
92
|
conn = pool.apn_connection(msg)
|
108
|
-
msg
|
109
|
-
|
110
|
-
|
93
|
+
conn.deliver(msg)
|
94
|
+
# msg[:apn_ids].each do |apn_id|
|
95
|
+
# conn.deliver(msg.merge({token: apn_id}))
|
96
|
+
# end
|
111
97
|
end
|
112
98
|
|
113
99
|
def send_apn_sandbox_notification(msg)
|
114
100
|
info "Sending APN sandbox notification via connection #{Digest::SHA1.hexdigest(msg[:cert])}"
|
115
101
|
conn = pool.apn_sandbox_connection(msg)
|
116
|
-
msg
|
117
|
-
|
118
|
-
|
102
|
+
conn.deliver(msg)
|
103
|
+
# msg[:apn_ids].each do |apn_id|
|
104
|
+
# conn.deliver(msg.merge({token: apn_id}))
|
105
|
+
# end
|
119
106
|
end
|
120
107
|
|
121
108
|
def feedback_connection(msg)
|
122
|
-
return
|
109
|
+
return Time.now - @last_feedback < FEEDBACK_TIME
|
123
110
|
info "Get feedback information"
|
124
111
|
conn = pool.feedback_connection(msg)
|
125
112
|
@last_feedback = Time.now
|
126
113
|
end
|
127
114
|
|
128
115
|
def feedback_sandbox_connection(msg)
|
129
|
-
return if
|
116
|
+
return if Time.now - @last_sandbox_feedback < FEEDBACK_TIME
|
130
117
|
info "Get feedback sandbox information"
|
131
118
|
conn = pool.feedback_sandbox_connection(msg)
|
132
119
|
@last_sandbox_feedback = Time.now
|
@@ -150,8 +137,6 @@ module Suj
|
|
150
137
|
conn.deliver(msg)
|
151
138
|
end
|
152
139
|
|
153
|
-
|
154
|
-
|
155
140
|
def redis_url
|
156
141
|
@redis_url ||= "redis://#{Suj::Pusher.config.redis_host}:#{Suj::Pusher.config.redis_port}/#{Suj::Pusher.config.redis_db}"
|
157
142
|
end
|
@@ -161,14 +146,41 @@ module Suj
|
|
161
146
|
end
|
162
147
|
|
163
148
|
def redis
|
164
|
-
@redis
|
165
|
-
end
|
149
|
+
return @redis if ! @redis.nil?
|
166
150
|
|
167
|
-
|
168
|
-
|
169
|
-
@
|
151
|
+
@redis = EM::Hiredis.connect(redis_url)
|
152
|
+
|
153
|
+
@redis.on(:connected) { info "REDIS - Connected to Redis server #{redis_url}" }
|
154
|
+
|
155
|
+
@redis.on(:closed) do
|
156
|
+
info "REDIS - Closed connection to Redis server"
|
157
|
+
@redis = nil
|
158
|
+
end
|
159
|
+
|
160
|
+
@redis.on(:failed) do
|
161
|
+
info "REDIS - redis connection FAILED"
|
162
|
+
@redis = nil
|
163
|
+
end
|
164
|
+
|
165
|
+
@redis.on(:reconnected) { info "REDIS - Reconnected to Redis server" }
|
166
|
+
|
167
|
+
@redis.on(:disconnected) do
|
168
|
+
info "REDIS - Disconnected from Redis server"
|
169
|
+
@redis = nil
|
170
|
+
end
|
171
|
+
|
172
|
+
@redis.on(:reconnect_failed) do
|
173
|
+
info "REDIS - Reconnection attempt to Redis server FAILED"
|
174
|
+
@redis = nil
|
175
|
+
end
|
176
|
+
|
177
|
+
return @redis
|
170
178
|
end
|
171
179
|
|
180
|
+
# def get_message
|
181
|
+
# @redis_connection ||= EM::Hiredis.connect(redis_url)
|
182
|
+
# end
|
183
|
+
|
172
184
|
def pool
|
173
185
|
@pool ||= Suj::Pusher::ConnectionPool.new(self)
|
174
186
|
end
|
data/lib/suj/pusher/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: suj-pusher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-12-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: em-http-request
|
16
|
-
requirement: &
|
16
|
+
requirement: &10281040 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *10281040
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: em-hiredis
|
27
|
-
requirement: &
|
27
|
+
requirement: &10280620 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *10280620
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: multi_json
|
38
|
-
requirement: &
|
38
|
+
requirement: &10280020 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *10280020
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: daemon-spawn
|
49
|
-
requirement: &
|
49
|
+
requirement: &10279380 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,7 +54,18 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *10279380
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: iobuffer
|
60
|
+
requirement: &10295080 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *10295080
|
58
69
|
description: Stand alone push notification server for APN, GCM, WNS and MPNS.
|
59
70
|
email:
|
60
71
|
- rd@skillupjapan.co.jp, n.bersano@skillupchile.cl
|