Push0r 0.4.4 → 0.5.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 +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'
|