Push0r 0.4.4 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/push0r/APNS/ApnsPushMessage.rb +38 -34
- data/lib/push0r/APNS/ApnsService.rb +231 -228
- data/lib/push0r/FlushResult.rb +46 -46
- data/lib/push0r/GCM/GcmPushMessage.rb +24 -24
- data/lib/push0r/GCM/GcmService.rb +126 -124
- data/lib/push0r/PushMessage.rb +27 -27
- data/lib/push0r/Queue.rb +74 -74
- data/lib/push0r/Service.rb +42 -42
- metadata +3 -2
data/lib/push0r/FlushResult.rb
CHANGED
@@ -1,48 +1,48 @@
|
|
1
1
|
module Push0r
|
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
|
-
|
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
48
|
end
|
@@ -1,27 +1,27 @@
|
|
1
1
|
module Push0r
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
2
|
+
# GcmPushMessage is a {PushMessage} implementation that encapsulates a single push notification to be sent to a single or multiple users.
|
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.
|
9
|
+
def initialize(receiver_token, identifier = nil, time_to_live = nil)
|
10
|
+
if identifier.nil? ## make sure the message has an identifier
|
11
|
+
identifier = Random.rand(2**32)
|
12
|
+
end
|
13
|
+
|
14
|
+
# for GCM the receiver_token is an array, so make sure we convert a single string to an array containing that string :-)
|
15
|
+
if receiver_token.is_a?(String)
|
16
|
+
receiver_token = [receiver_token]
|
17
|
+
end
|
18
|
+
|
19
|
+
super(receiver_token, identifier, time_to_live)
|
20
|
+
|
21
|
+
if time_to_live && time_to_live.to_i >= 0
|
22
|
+
self.attach({'time_to_live' => time_to_live.to_i})
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
26
|
end
|
27
27
|
|
@@ -2,128 +2,130 @@ require 'net/http'
|
|
2
2
|
|
3
3
|
module Push0r
|
4
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
|
-
|
5
|
+
# A module that contains constants for Google Cloud Messaging error codes
|
6
|
+
module GcmErrorCodes
|
7
|
+
UNKNOWN_ERROR = 1
|
8
|
+
INVALID_REGISTRATION = 2
|
9
|
+
UNAVAILABLE = 3
|
10
|
+
NOT_REGISTERED = 4
|
11
|
+
MISMATCH_SENDER_ID = 5
|
12
|
+
MISSING_REGISTRATION = 6
|
13
|
+
MESSAGE_TOO_BIG = 7
|
14
|
+
INVALID_DATA_KEY = 8
|
15
|
+
INVALID_TTL = 9
|
16
|
+
INVALID_PACKAGE_NAME = 10
|
17
|
+
CONNECTION_ERROR = 11
|
18
|
+
UNABLE_TO_PARSE_JSON = 400
|
19
|
+
NOT_AUTHENTICATED = 401
|
20
|
+
INTERNAL_ERROR = 500
|
21
|
+
end
|
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)
|
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
|
33
|
+
def initialize(api_key)
|
34
|
+
@api_key = api_key
|
35
|
+
@messages = []
|
36
|
+
end
|
37
|
+
|
38
|
+
# @see Service#can_send?
|
39
|
+
def can_send?(message)
|
40
|
+
return message.is_a?(GcmPushMessage)
|
41
|
+
end
|
42
|
+
|
43
|
+
# @see Service#send
|
44
|
+
def send(message)
|
45
|
+
@messages << message
|
46
|
+
end
|
47
|
+
|
48
|
+
# @see Service#init_push
|
49
|
+
def init_push
|
50
|
+
## not used for gcm
|
51
|
+
end
|
52
|
+
|
53
|
+
# @see Service#end_push
|
54
|
+
def end_push
|
55
|
+
failed_messages = []
|
56
|
+
new_registration_messages = []
|
57
|
+
|
58
|
+
uri = URI.parse('https://android.googleapis.com/gcm/send')
|
59
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
60
|
+
http.use_ssl = true
|
61
|
+
|
62
|
+
@messages.each do |message|
|
63
|
+
begin
|
64
|
+
request = Net::HTTP::Post.new(uri.path, {'Content-Type' => 'application/json', 'Authorization' => "key=#{@api_key}"})
|
65
|
+
request.body = message.attach({'registration_ids' => message.receiver_token}).payload.to_json
|
66
|
+
response = http.request(request)
|
67
|
+
rescue SocketError
|
68
|
+
## connection error
|
69
|
+
failed_messages << FailedMessage.new(Push0r::GcmErrorCodes::CONNECTION_ERROR, message.receiver_token, message)
|
70
|
+
next
|
71
|
+
end
|
72
|
+
|
73
|
+
if response.code.to_i == 200
|
74
|
+
json = JSON.parse(response.body)
|
75
|
+
|
76
|
+
if json['failure'].to_i > 0 || json['canonical_ids'].to_i > 0
|
77
|
+
error_receivers = {}
|
78
|
+
|
79
|
+
json['results'].each_with_index do |result, i|
|
80
|
+
receiver_token = message.receiver_token[i]
|
81
|
+
error = result['error']
|
82
|
+
message_id = result['message_id']
|
83
|
+
registration_id = result['registration_id']
|
84
|
+
|
85
|
+
if message_id && registration_id
|
86
|
+
new_registration_messages << NewTokenMessage.new(receiver_token, registration_id, message)
|
87
|
+
elsif error
|
88
|
+
error_code = Push0r::GcmErrorCodes::UNKNOWN_ERROR
|
89
|
+
if error == 'InvalidRegistration'
|
90
|
+
error_code = Push0r::GcmErrorCodes::INVALID_REGISTRATION
|
91
|
+
elsif error == 'Unavailable'
|
92
|
+
error_code = Push0r::GcmErrorCodes::UNAVAILABLE
|
93
|
+
elsif error == 'NotRegistered'
|
94
|
+
error_code = Push0r::GcmErrorCodes::NOT_REGISTERED
|
95
|
+
elsif error == 'MismatchSenderId'
|
96
|
+
error_code = Push0r::GcmErrorCodes::MISMATCH_SENDER_ID
|
97
|
+
elsif error == 'MissingRegistration'
|
98
|
+
error_code = Push0r::GcmErrorCodes::MISSING_REGISTRATION
|
99
|
+
elsif error == 'MessageTooBig'
|
100
|
+
error_code = Push0r::GcmErrorCodes::MESSAGE_TOO_BIG
|
101
|
+
elsif error == 'InvalidDataKey'
|
102
|
+
error_code = Push0r::GcmErrorCodes::INVALID_DATA_KEY
|
103
|
+
elsif error == 'InvalidTtl'
|
104
|
+
error_code = Push0r::GcmErrorCodes::INVALID_TTL
|
105
|
+
elsif error == 'InvalidPackageName'
|
106
|
+
error_code = Push0r::GcmErrorCodes::INVALID_PACKAGE_NAME
|
107
|
+
end
|
108
|
+
if error_receivers[error_code].nil? then
|
109
|
+
error_receivers[error_code] = []
|
110
|
+
end
|
111
|
+
error_receivers[error_code] << receiver_token
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
## if there are any receivers with errors: add a hash for every distinct error code and the related receivers to the failed_messages array
|
116
|
+
error_receivers.each do |error_code, receivers|
|
117
|
+
failed_messages << FailedMessage.new(error_code, receivers, message)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
elsif response.code.to_i >= 500 && response.code.to_i <= 599
|
121
|
+
failed_messages << FailedMessage.new(Push0r::GcmErrorCodes::INTERNAL_ERROR, message.receiver_token, message)
|
122
|
+
else
|
123
|
+
failed_messages << FailedMessage.new(response.code.to_i, message.receiver_token, message)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
@messages = [] ## reset
|
128
|
+
return [failed_messages, new_registration_messages]
|
129
|
+
end
|
130
|
+
end
|
129
131
|
end
|
data/lib/push0r/PushMessage.rb
CHANGED
@@ -1,33 +1,33 @@
|
|
1
1
|
module Push0r
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
8
|
+
class PushMessage
|
9
|
+
attr_reader :payload, :identifier, :receiver_token, :time_to_live
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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.
|
15
|
+
def initialize(receiver_token, identifier = nil, time_to_live = nil)
|
16
|
+
@receiver_token = receiver_token
|
17
|
+
@identifier = identifier
|
18
|
+
@time_to_live = time_to_live
|
19
|
+
@payload = {}
|
20
|
+
end
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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
|
26
|
+
def attach(payload = {})
|
27
|
+
@payload.merge!(payload)
|
28
|
+
return self
|
29
|
+
end
|
30
|
+
end
|
31
31
|
end
|
32
32
|
|
33
33
|
require_relative 'APNS/ApnsPushMessage'
|