Push0r 0.2.7 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/push0r/APNS/ApnsPushMessage.rb +10 -0
- data/lib/push0r/APNS/ApnsService.rb +49 -34
- data/lib/push0r/FlushResult.rb +48 -0
- data/lib/push0r/GCM/GcmPushMessage.rb +6 -0
- data/lib/push0r/GCM/GcmService.rb +38 -25
- data/lib/push0r/PushMessage.rb +17 -3
- data/lib/push0r/Queue.rb +36 -4
- data/lib/push0r/Service.rb +33 -4
- data/lib/push0r.rb +2 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ec063440562ff9633e4856679f911e047c69afb6
|
4
|
+
data.tar.gz: 1ecef9c128f4ac66a5a86af7d1301e51a6f709a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e30bef2183bf8c659cb0489701de5a2175996de3599ebb91715d28bf8b9319ab02add199b4ea26dfb2463060b09990f4c8fc4e6c0a35d4ff6546c5609b460bc3
|
7
|
+
data.tar.gz: cbd6ae1c91f25ba19584107939dca1a1126ab57e815c366e9505992a93e4527fbef0e18c25ad14f8af6c18be0f1733e7c1c87dac44ffd92d2d588739e374d116
|
@@ -1,5 +1,11 @@
|
|
1
1
|
module Push0r
|
2
|
+
# ApnsPushMessage is a {PushMessage} implementation that encapsulates a single push notification to be sent to a single user.
|
2
3
|
class ApnsPushMessage < PushMessage
|
4
|
+
|
5
|
+
# Returns a new ApnsPushMessage instance that encapsulates a single push notification to be sent to a single user.
|
6
|
+
# @param receiver_token [String] the apns push token (aka device token) to push the notification to
|
7
|
+
# @param identifier [Fixnum] a unique identifier to identify this push message during error handling. If nil, a random identifier is automatically generated.
|
8
|
+
# @param time_to_live [Fixnum] The time to live in seconds for this push messages. If nil, the time to live is set to zero seconds.
|
3
9
|
def initialize(receiver_token, identifier = nil, time_to_live = nil)
|
4
10
|
if identifier.nil? ## make sure the message has an identifier (required for apns error handling)
|
5
11
|
identifier = Random.rand(2**32)
|
@@ -7,6 +13,10 @@ module Push0r
|
|
7
13
|
super(receiver_token, identifier, time_to_live)
|
8
14
|
end
|
9
15
|
|
16
|
+
# Convenience method to attach common data (that is an alert, a sound or a badge value) to this message's payload.
|
17
|
+
# @param alert_text [String] the alert text to be displayed
|
18
|
+
# @param sound [String] the sound to be played
|
19
|
+
# @param badge [Fixnum] the badge value to be displayed
|
10
20
|
def simple(alert_text = nil, sound = nil, badge = nil)
|
11
21
|
new_payload = {aps: {}}
|
12
22
|
if alert_text
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Push0r
|
2
|
+
|
3
|
+
# A module that contains Apple Push Notification Service error codes
|
2
4
|
module ApnsErrorCodes
|
3
|
-
NO_ERROR = 0
|
4
5
|
PROCESSING_ERROR = 1
|
5
6
|
MISSING_DEVICE_TOKEN = 2
|
6
7
|
MISSING_TOPIC = 3
|
@@ -12,8 +13,18 @@ module Push0r
|
|
12
13
|
SHUTDOWN = 10
|
13
14
|
NONE = 255
|
14
15
|
end
|
15
|
-
|
16
|
+
|
17
|
+
# ApnsService is a {Service} implementation to push notifications to iOS and OSX users using the Apple Push Notification Service.
|
18
|
+
# @example
|
19
|
+
# queue = Push0r::Queue.new
|
20
|
+
#
|
21
|
+
# apns_service = Push0r::ApnsService.new(File.read("aps.pem"), true)
|
22
|
+
# queue.register_service(apns_service)
|
16
23
|
class ApnsService < Service
|
24
|
+
|
25
|
+
# Returns a new ApnsService instance
|
26
|
+
# @param certificate_data [String] the Apple push certificate in PEM format
|
27
|
+
# @param sandbox_environment [Boolean] true if the sandbox push server should be used, otherwise false
|
17
28
|
def initialize(certificate_data, sandbox_environment = false)
|
18
29
|
@certificate_data = certificate_data
|
19
30
|
@sandbox_environment = sandbox_environment
|
@@ -21,57 +32,61 @@ module Push0r
|
|
21
32
|
@sock = nil
|
22
33
|
@messages = []
|
23
34
|
end
|
24
|
-
|
35
|
+
|
36
|
+
# @see Service#can_send?
|
25
37
|
def can_send?(message)
|
26
38
|
return message.is_a?(ApnsPushMessage)
|
27
39
|
end
|
28
|
-
|
40
|
+
|
41
|
+
# @see Service#send
|
29
42
|
def send(message)
|
30
43
|
@messages << message
|
31
44
|
end
|
32
|
-
|
45
|
+
|
46
|
+
# @see Service#init_push
|
33
47
|
def init_push
|
34
48
|
# not used for apns
|
35
49
|
end
|
36
|
-
|
50
|
+
|
51
|
+
# @see Service#end_push
|
37
52
|
def end_push
|
38
53
|
failed_messages = []
|
39
54
|
begin
|
40
55
|
setup_ssl
|
41
56
|
(result, error_message, error_code) = transmit_messages
|
42
|
-
if result == false
|
43
|
-
failed_messages <<
|
57
|
+
if result == false
|
58
|
+
failed_messages << FailedMessage.new(error_code, error_message.receiver_token, error_message)
|
44
59
|
reset_message(error_identifier)
|
45
60
|
if @messages.empty? then result = true end
|
46
61
|
end
|
47
62
|
end while result != true
|
48
|
-
|
63
|
+
|
49
64
|
unless @ssl.nil?
|
50
65
|
@ssl.close
|
51
66
|
end
|
52
67
|
unless @sock.nil?
|
53
68
|
@sock.close
|
54
69
|
end
|
55
|
-
|
70
|
+
|
56
71
|
@messages = [] ## reset
|
57
72
|
return [failed_messages, []]
|
58
73
|
end
|
59
|
-
|
74
|
+
|
60
75
|
private
|
61
76
|
def setup_ssl
|
62
77
|
ctx = OpenSSL::SSL::SSLContext.new
|
63
|
-
|
78
|
+
|
64
79
|
ctx.key = OpenSSL::PKey::RSA.new(@certificate_data, '')
|
65
80
|
ctx.cert = OpenSSL::X509::Certificate.new(@certificate_data)
|
66
|
-
|
81
|
+
|
67
82
|
@sock = TCPSocket.new(@sandbox_environment ? "gateway.sandbox.push.apple.com" : "gateway.push.apple.com", 2195)
|
68
83
|
@ssl = OpenSSL::SSL::SSLSocket.new(@sock, ctx)
|
69
84
|
@ssl.connect
|
70
85
|
end
|
71
|
-
|
86
|
+
|
72
87
|
def reset_message(error_identifier)
|
73
88
|
index = @messages.find_index {|o| o.identifier == error_identifier}
|
74
|
-
|
89
|
+
|
75
90
|
if index.nil? ## this should never happen actually
|
76
91
|
@messages = []
|
77
92
|
elsif index < @messages.length - 1 # reset @messages to contain all messages after the one that has failed
|
@@ -80,61 +95,61 @@ module Push0r
|
|
80
95
|
@messages = []
|
81
96
|
end
|
82
97
|
end
|
83
|
-
|
98
|
+
|
84
99
|
def create_push_frame(message)
|
85
100
|
receiver_token = message.receiver_token
|
86
101
|
payload = message.payload
|
87
102
|
identifier = message.identifier
|
88
103
|
time_to_live = (message.time_to_live.nil? || message.time_to_live.to_i < 0) ? 0 : message.time_to_live.to_i
|
89
|
-
|
104
|
+
|
90
105
|
if receiver_token.nil? then raise(ArgumentError, "receiver_token is nil!") end
|
91
|
-
if payload.nil? then raise(ArgumentError, "payload is nil!") end
|
92
|
-
|
106
|
+
if payload.nil? then raise(ArgumentError, "payload is nil!") end
|
107
|
+
|
93
108
|
receiver_token = receiver_token.gsub(/\s+/, "")
|
94
|
-
if receiver_token.length != 64 then raise(ArgumentError, "invalid receiver_token length!") end
|
95
|
-
|
109
|
+
if receiver_token.length != 64 then raise(ArgumentError, "invalid receiver_token length!") end
|
110
|
+
|
96
111
|
devicetoken = [receiver_token].pack('H*')
|
97
112
|
devicetoken_length = [32].pack("n")
|
98
113
|
devicetoken_item = "\1#{devicetoken_length}#{devicetoken}"
|
99
|
-
|
114
|
+
|
100
115
|
identifier = [identifier.to_i].pack("N")
|
101
116
|
identifier_length = [4].pack("n")
|
102
117
|
identifier_item = "\3#{identifier_length}#{identifier}"
|
103
|
-
|
118
|
+
|
104
119
|
expiration_date = [(time_to_live > 0 ? Time.now.to_i + time_to_live : 0)].pack("N")
|
105
120
|
expiration_date_length = [4].pack("n")
|
106
121
|
expiration_item = "\4#{expiration_date_length}#{expiration_date}"
|
107
|
-
|
122
|
+
|
108
123
|
priority = "\xA" ## default: high priority
|
109
124
|
if payload[:aps] && payload[:aps]["content-available"] && payload[:aps]["content-available"].to_i != 0 && (payload[:aps][:alert].nil? && payload[:aps][:sound].nil? && payload[:aps][:badge].nil?)
|
110
125
|
priority = "\5" ## lower priority for content-available pushes without alert/sound/badge
|
111
126
|
end
|
112
|
-
|
127
|
+
|
113
128
|
priority_length = [1].pack("n")
|
114
129
|
priority_item = "\5#{priority_length}#{priority}"
|
115
|
-
|
130
|
+
|
116
131
|
payload = payload.to_json.force_encoding("BINARY")
|
117
132
|
payload_length = [payload.bytesize].pack("n")
|
118
133
|
payload_item = "\2#{payload_length}#{payload}"
|
119
|
-
|
134
|
+
|
120
135
|
frame_length = [devicetoken_item.bytesize + payload_item.bytesize + identifier_item.bytesize + expiration_item.bytesize + priority_item.bytesize].pack("N")
|
121
136
|
frame = "\2#{frame_length}#{devicetoken_item}#{payload_item}#{identifier_item}#{expiration_item}#{priority_item}"
|
122
|
-
|
137
|
+
|
123
138
|
return frame
|
124
139
|
end
|
125
|
-
|
140
|
+
|
126
141
|
def transmit_messages
|
127
142
|
if @messages.empty? || @ssl.nil?
|
128
143
|
return [true, nil, nil]
|
129
144
|
end
|
130
|
-
|
145
|
+
|
131
146
|
pushdata = ""
|
132
147
|
@messages.each do |message|
|
133
148
|
pushdata << create_push_frame(message)
|
134
149
|
end
|
135
|
-
|
150
|
+
|
136
151
|
@ssl.write(pushdata)
|
137
|
-
|
152
|
+
|
138
153
|
if IO.select([@ssl], nil, nil, 2)
|
139
154
|
begin
|
140
155
|
read_buffer = @ssl.read(6)
|
@@ -153,7 +168,7 @@ module Push0r
|
|
153
168
|
end
|
154
169
|
return [true, nil, nil]
|
155
170
|
end
|
156
|
-
|
171
|
+
|
157
172
|
def message_for_identifier(identifier)
|
158
173
|
index = @messages.find_index {|o| o.identifier == identifier}
|
159
174
|
if index.nil?
|
@@ -163,4 +178,4 @@ module Push0r
|
|
163
178
|
end
|
164
179
|
end
|
165
180
|
end
|
166
|
-
end
|
181
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Push0r
|
2
|
+
# FlushResult models the result of a single {Queue} flushing process.
|
3
|
+
class FlushResult
|
4
|
+
attr_reader :failed_messages
|
5
|
+
attr_reader :new_token_messages
|
6
|
+
|
7
|
+
def initialize(failed_message, new_token_messages)
|
8
|
+
@failed_messages = failed_message
|
9
|
+
@new_token_messages = new_token_messages
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"FlushResult - Failed: #{@failed_messages.count} NewToken: #{@new_token_messages.count}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class FailedMessage
|
18
|
+
attr_reader :error_code
|
19
|
+
attr_reader :receivers
|
20
|
+
attr_reader :message
|
21
|
+
|
22
|
+
def initialize(error_code, receivers, message)
|
23
|
+
@error_code = error_code
|
24
|
+
@receivers = receivers
|
25
|
+
@message = message
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
"FailedMessage: errorCode: #{@error_code} receivers: #{@receivers.inspect}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class NewTokenMessage
|
34
|
+
attr_reader :message
|
35
|
+
attr_reader :token
|
36
|
+
attr_reader :new_token
|
37
|
+
|
38
|
+
def initialize(token, new_token, message)
|
39
|
+
@token = token
|
40
|
+
@new_token = new_token
|
41
|
+
@message = message
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
"NewTokenMessage: oldToken: #{@token} newToken: #{@new_token}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -1,5 +1,11 @@
|
|
1
1
|
module Push0r
|
2
|
+
# GcmPushMessage is a {PushMessage} implementation that encapsulates a single push notification to be sent to a single or multiple users.
|
2
3
|
class GcmPushMessage < PushMessage
|
4
|
+
|
5
|
+
# Returns a new GcmPushMessage instance that encapsulates a single push notification to be sent to a single or multiple users.
|
6
|
+
# @param receiver_token [Array<String>] the apns push tokens (aka registration ids) to push the notification to
|
7
|
+
# @param identifier [Fixnum] a unique identifier to identify this push message during error handling. If nil, a random identifier is automatically generated.
|
8
|
+
# @param time_to_live [Fixnum] The time to live in seconds for this push messages. If nil, the time to live is set to four weeks.
|
3
9
|
def initialize(receiver_token, identifier = nil, time_to_live = nil)
|
4
10
|
if identifier.nil? ## make sure the message has an identifier
|
5
11
|
identifier = Random.rand(2**32)
|
@@ -1,12 +1,9 @@
|
|
1
1
|
require 'net/http'
|
2
2
|
|
3
3
|
module Push0r
|
4
|
-
|
4
|
+
|
5
|
+
# A module that contains constants for Google Cloud Messaging error codes
|
5
6
|
module GcmErrorCodes
|
6
|
-
NO_ERROR = 0
|
7
|
-
UNABLE_TO_PARSE_JSON = 400
|
8
|
-
NOT_AUTHENTICATED = 401
|
9
|
-
INTERNAL_ERROR = 500
|
10
7
|
UNKNOWN_ERROR = 1
|
11
8
|
INVALID_REGISTRATION = 2
|
12
9
|
UNAVAILABLE = 3
|
@@ -18,30 +15,46 @@ module Push0r
|
|
18
15
|
INVALID_TTL = 9
|
19
16
|
INVALID_PACKAGE_NAME = 10
|
20
17
|
CONNECTION_ERROR = 11
|
18
|
+
UNABLE_TO_PARSE_JSON = 400
|
19
|
+
NOT_AUTHENTICATED = 401
|
20
|
+
INTERNAL_ERROR = 500
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
|
+
# GcmService is a {Service} implementation to push notifications to Android users using the Google Cloud Messaging Service.
|
24
|
+
# @example
|
25
|
+
# queue = Push0r::Queue.new
|
26
|
+
#
|
27
|
+
# gcm_service = Push0r::GcmService.new("__gcm_api_token__")
|
28
|
+
# queue.register_service(gcm_service)
|
23
29
|
class GcmService < Service
|
30
|
+
|
31
|
+
# Returns a new ApnsService instance
|
32
|
+
# @param api_key [String] the GCM API key obtained from the Google Developers Console
|
24
33
|
def initialize(api_key)
|
25
34
|
@api_key = api_key
|
26
35
|
@messages = []
|
27
36
|
end
|
28
|
-
|
37
|
+
|
38
|
+
# @see Service#can_send?
|
29
39
|
def can_send?(message)
|
30
40
|
return message.is_a?(GcmPushMessage)
|
31
41
|
end
|
32
|
-
|
42
|
+
|
43
|
+
# @see Service#send
|
33
44
|
def send(message)
|
34
45
|
@messages << message
|
35
46
|
end
|
36
|
-
|
47
|
+
|
48
|
+
# @see Service#init_push
|
37
49
|
def init_push
|
38
50
|
## not used for gcm
|
39
51
|
end
|
40
|
-
|
52
|
+
|
53
|
+
# @see Service#end_push
|
41
54
|
def end_push
|
42
55
|
failed_messages = []
|
43
56
|
new_registration_messages = []
|
44
|
-
|
57
|
+
|
45
58
|
uri = URI.parse("https://android.googleapis.com/gcm/send")
|
46
59
|
http = Net::HTTP.new(uri.host, uri.port)
|
47
60
|
http.use_ssl = true
|
@@ -53,24 +66,24 @@ module Push0r
|
|
53
66
|
response = http.request(request)
|
54
67
|
rescue SocketError
|
55
68
|
## connection error
|
56
|
-
failed_messages <<
|
69
|
+
failed_messages << FailedMessage.new(Push0r::GcmErrorCodes::CONNECTION_ERROR, message.receiver_token, message)
|
57
70
|
next
|
58
71
|
end
|
59
|
-
|
72
|
+
|
60
73
|
if response.code.to_i == 200
|
61
74
|
json = JSON.parse(response.body)
|
62
|
-
|
75
|
+
|
63
76
|
if json["failure"].to_i > 0 || json["canonical_ids"].to_i > 0
|
64
77
|
error_receivers = {}
|
65
|
-
|
78
|
+
|
66
79
|
json["results"].each_with_index do |result,i|
|
67
80
|
receiver_token = message.receiver_token[i]
|
68
81
|
error = result["error"]
|
69
82
|
message_id = result["message_id"]
|
70
83
|
registration_id = result["registration_id"]
|
71
|
-
|
84
|
+
|
72
85
|
if message_id && registration_id
|
73
|
-
new_registration_messages <<
|
86
|
+
new_registration_messages << NewTokenMessage.new(receiver_token, registration_id, message)
|
74
87
|
elsif error
|
75
88
|
error_code = Push0r::GcmErrorCodes::UNKNOWN_ERROR
|
76
89
|
if error == "InvalidRegistration"
|
@@ -86,7 +99,7 @@ module Push0r
|
|
86
99
|
elsif error == "MessageTooBig"
|
87
100
|
error_code = Push0r::GcmErrorCodes::MESSAGE_TOO_BIG
|
88
101
|
elsif error == "InvalidDataKey"
|
89
|
-
error_code = Push0r::GcmErrorCodes::INVALID_DATA_KEY
|
102
|
+
error_code = Push0r::GcmErrorCodes::INVALID_DATA_KEY
|
90
103
|
elsif error == "InvalidTtl"
|
91
104
|
error_code = Push0r::GcmErrorCodes::INVALID_TTL
|
92
105
|
elsif error == "InvalidPackageName"
|
@@ -96,21 +109,21 @@ module Push0r
|
|
96
109
|
error_receivers[error_code] << receiver_token
|
97
110
|
end
|
98
111
|
end
|
99
|
-
|
112
|
+
|
100
113
|
## if there are any receivers with errors: add a hash for every distinct error code and the related receivers to the failed_messages array
|
101
114
|
error_receivers.each do |error_code, receivers|
|
102
|
-
failed_messages <<
|
115
|
+
failed_messages << FailedMessage.new(error_code, receivers, message)
|
103
116
|
end
|
104
117
|
end
|
105
118
|
elsif response.code.to_i >= 500 && response.code.to_i <= 599
|
106
|
-
failed_messages <<
|
119
|
+
failed_messages << FailedMessage.new(Push0r::GcmErrorCodes::INTERNAL_ERROR, message.receiver_token, message)
|
107
120
|
else
|
108
|
-
failed_messages <<
|
121
|
+
failed_messages << FailedMessage.new(response.code.to_i, message.receiver_token, message)
|
109
122
|
end
|
110
123
|
end
|
111
|
-
|
112
|
-
@messages = [] ## reset
|
124
|
+
|
125
|
+
@messages = [] ## reset
|
113
126
|
return [failed_messages, new_registration_messages]
|
114
127
|
end
|
115
128
|
end
|
116
|
-
end
|
129
|
+
end
|
data/lib/push0r/PushMessage.rb
CHANGED
@@ -1,14 +1,28 @@
|
|
1
1
|
module Push0r
|
2
|
+
# PushMessage is the base class for all implemented push message types. A PushMessage encapsulates values like the notification's payload, its receiver, etc.
|
3
|
+
# @abstract
|
4
|
+
# @attr_reader [Hash] payload the payload for this push message
|
5
|
+
# @attr_reader [Fixnum] identifier the unique identifier for this push message
|
6
|
+
# @attr_reader [String, Array] receiver_token the receiver's push token
|
7
|
+
# @attr_reader [Fixnum] time_to_live the time to live in seconds for this push message
|
2
8
|
class PushMessage
|
3
9
|
attr_reader :payload, :identifier, :receiver_token, :time_to_live
|
4
|
-
|
10
|
+
|
11
|
+
# Creates a new PushMessage instance
|
12
|
+
# @param receiver_token [String, Array] the receiver's push token. Some subclasses might also accept an Array of tokens.
|
13
|
+
# @param identifier [Fixnum] a unique identifier to identify this push message during error handling. If nil, a random identifier is automatically generated.
|
14
|
+
# @param time_to_live [Fixnum] The time to live in seconds for this push messages. If nil, the time to live depends on the service used to transmit the message.
|
5
15
|
def initialize(receiver_token, identifier = nil, time_to_live = nil)
|
6
16
|
@receiver_token = receiver_token
|
7
17
|
@identifier = identifier
|
8
18
|
@time_to_live = time_to_live
|
9
19
|
@payload = {}
|
10
20
|
end
|
11
|
-
|
21
|
+
|
22
|
+
# Attaches the given payload to the push message.
|
23
|
+
# @note attaching is done using the merge! method of the Hash class, i.e. be careful not to overwrite previously set Hash keys.
|
24
|
+
# @param payload [Hash] the payload to attach to the message.
|
25
|
+
# @return [self] self
|
12
26
|
def attach(payload = {})
|
13
27
|
@payload.merge!(payload)
|
14
28
|
return self
|
@@ -17,4 +31,4 @@ module Push0r
|
|
17
31
|
end
|
18
32
|
|
19
33
|
require_relative 'APNS/ApnsPushMessage'
|
20
|
-
require_relative 'GCM/GcmPushMessage'
|
34
|
+
require_relative 'GCM/GcmPushMessage'
|
data/lib/push0r/Queue.rb
CHANGED
@@ -1,16 +1,46 @@
|
|
1
1
|
module Push0r
|
2
|
+
|
3
|
+
# A Queue is used to register services to be used to transmit PushMessages. Single PushMessages are then put into the queue and a call to the {#flush} method transmits all enqueued messages using the registered services. In a sense, Queue is the class that ties all the other Push0r components together.
|
4
|
+
# @example
|
5
|
+
# queue = Push0r::Queue.new
|
6
|
+
#
|
7
|
+
# gcm_service = Push0r::GcmService.new("__gcm_api_token__")
|
8
|
+
# queue.register_service(gcm_service)
|
9
|
+
#
|
10
|
+
# apns_service = Push0r::ApnsService.new(File.read("aps.pem"), true)
|
11
|
+
# queue.register_service(apns_service)
|
12
|
+
#
|
13
|
+
# gcm_message = Push0r::GcmPushMessage.new("__registration_id__")
|
14
|
+
# gcm_message.attach({"data" => {"d" => "1"}})
|
15
|
+
#
|
16
|
+
# apns_message = Push0r::ApnsPushMessage.new("__device_token__")
|
17
|
+
# apns_message.attach({"data" => {"v" => "1"}}
|
18
|
+
#
|
19
|
+
# queue.add(gcm_message)
|
20
|
+
# queue.add(apns_message)
|
21
|
+
#
|
22
|
+
# queue.flush
|
2
23
|
class Queue
|
3
24
|
def initialize
|
4
25
|
@services = []
|
5
26
|
@queued_messages = {}
|
6
27
|
end
|
7
28
|
|
29
|
+
# Registers a Service with the Queue
|
30
|
+
# @note Every service can only be registered once with the same queue
|
31
|
+
# @param service [Service] the service to be registered with the queue
|
32
|
+
# @return [void]
|
33
|
+
# @see Service
|
8
34
|
def register_service(service)
|
9
35
|
unless @services.include?(service)
|
10
36
|
@services << service
|
11
37
|
end
|
12
38
|
end
|
13
39
|
|
40
|
+
# Adds a PushMessage to the queue
|
41
|
+
# @param message [PushMessage] the message to be added to the queue
|
42
|
+
# @return [Boolean] true if message was added to the queue (that is: if any of the registered services can handle the message), otherwise false
|
43
|
+
# @see PushMessage
|
14
44
|
def add(message)
|
15
45
|
@services.each do |service|
|
16
46
|
if service.can_send?(message)
|
@@ -24,21 +54,23 @@ module Push0r
|
|
24
54
|
return false
|
25
55
|
end
|
26
56
|
|
57
|
+
# Flushes the queue by transmitting the enqueued messages using the registered services
|
58
|
+
# @return [FlushResult] the result of the operation
|
27
59
|
def flush
|
28
60
|
failed_messages = []
|
29
|
-
|
61
|
+
new_token_messages = []
|
30
62
|
|
31
63
|
@queued_messages.each do |service, messages|
|
32
64
|
service.init_push
|
33
65
|
messages.each do |message|
|
34
66
|
service.send(message)
|
35
67
|
end
|
36
|
-
(failed,
|
68
|
+
(failed, new_token) = service.end_push
|
37
69
|
failed_messages += failed
|
38
|
-
|
70
|
+
new_token_messages += new_token
|
39
71
|
end
|
40
72
|
@queued_messages = {}
|
41
|
-
return
|
73
|
+
return FlushResult.new(failed_messages, new_token_messages)
|
42
74
|
end
|
43
75
|
end
|
44
76
|
end
|
data/lib/push0r/Service.rb
CHANGED
@@ -1,17 +1,46 @@
|
|
1
1
|
module Push0r
|
2
|
+
module ErrorCodes
|
3
|
+
NO_ERROR = -1
|
4
|
+
end
|
5
|
+
|
6
|
+
# Service is the base class for all implemented push services. A Service encapsulates everything that is necessary to take a batch of push notifications and transmit it to the receivers.
|
7
|
+
# @abstract
|
2
8
|
class Service
|
9
|
+
|
10
|
+
# Called on the service every time a PushMessage is added to a Queue in order to determine whether it can send the given message.
|
11
|
+
# @param message [PushMessage] the message
|
12
|
+
# @return [Boolean] true if this service can send the given message, otherwise false
|
13
|
+
# @abstract
|
14
|
+
# @see PushMessage
|
15
|
+
# @see Queue
|
3
16
|
def can_send?(message)
|
4
17
|
return false
|
5
18
|
end
|
6
|
-
|
19
|
+
|
20
|
+
# Sends a single push message. This is called during the flushing of a Queue for every enqueued PushMessage. The service may create its own internal queue in order to efficiently batch the messages.
|
21
|
+
# @param message [PushMessage] the message to be sent
|
22
|
+
# @return [void]
|
23
|
+
# @abstract
|
24
|
+
# @see PushMessage
|
25
|
+
# @see Queue
|
7
26
|
def send(message)
|
8
27
|
## empty
|
9
28
|
end
|
10
|
-
|
29
|
+
|
30
|
+
# Called on the service during the flushing of a Queue before the first PushMessage is sent.
|
31
|
+
# @return [void]
|
32
|
+
# @abstract
|
33
|
+
# @see PushMessage
|
34
|
+
# @see Queue
|
11
35
|
def init_push
|
12
36
|
## empty
|
13
37
|
end
|
14
|
-
|
38
|
+
|
39
|
+
# Called on the service during the flushing of a Queue after the last PushMessage has been sent. If the service manages its own internal queue, this is the place to actually transmit all messages.
|
40
|
+
# @return [Array(Array<String>, Array<String>)] Failed new RegId Messages
|
41
|
+
# @abstract
|
42
|
+
# @see PushMessage
|
43
|
+
# @see Queue
|
15
44
|
def end_push
|
16
45
|
## empty
|
17
46
|
return [[], []]
|
@@ -20,4 +49,4 @@ module Push0r
|
|
20
49
|
end
|
21
50
|
|
22
51
|
require_relative 'APNS/ApnsService'
|
23
|
-
require_relative 'GCM/GcmService'
|
52
|
+
require_relative 'GCM/GcmService'
|
data/lib/push0r.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: Push0r
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kai Straßmann
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-05-
|
11
|
+
date: 2014-05-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -33,6 +33,7 @@ files:
|
|
33
33
|
- lib/push0r.rb
|
34
34
|
- lib/push0r/APNS/ApnsPushMessage.rb
|
35
35
|
- lib/push0r/APNS/ApnsService.rb
|
36
|
+
- lib/push0r/FlushResult.rb
|
36
37
|
- lib/push0r/GCM/GcmPushMessage.rb
|
37
38
|
- lib/push0r/GCM/GcmService.rb
|
38
39
|
- lib/push0r/PushMessage.rb
|
@@ -63,3 +64,4 @@ signing_key:
|
|
63
64
|
specification_version: 4
|
64
65
|
summary: Push0r gem
|
65
66
|
test_files: []
|
67
|
+
has_rdoc:
|