rpush 1.0.0-java → 2.0.0-java
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/CHANGELOG.md +15 -0
- data/README.md +37 -22
- data/bin/rpush +13 -4
- data/lib/generators/rpush_generator.rb +2 -0
- data/lib/generators/templates/add_adm.rb +5 -5
- data/lib/generators/templates/add_alert_is_json_to_rapns_notifications.rb +1 -1
- data/lib/generators/templates/add_app_to_rapns.rb +2 -2
- data/lib/generators/templates/add_fail_after_to_rpush_notifications.rb +1 -1
- data/lib/generators/templates/add_gcm.rb +32 -32
- data/lib/generators/templates/add_rpush.rb +67 -67
- data/lib/generators/templates/add_wpns.rb +2 -2
- data/lib/generators/templates/create_rapns_apps.rb +5 -5
- data/lib/generators/templates/create_rapns_feedback.rb +2 -2
- data/lib/generators/templates/create_rapns_notifications.rb +15 -15
- data/lib/generators/templates/rpush.rb +28 -7
- data/lib/generators/templates/rpush_2_0_0_updates.rb +42 -0
- data/lib/rpush/client/active_model/adm/app.rb +23 -0
- data/lib/rpush/client/active_model/adm/data_validator.rb +14 -0
- data/lib/rpush/client/active_model/adm/notification.rb +28 -0
- data/lib/rpush/client/active_model/apns/app.rb +37 -0
- data/lib/rpush/client/active_model/apns/binary_notification_validator.rb +16 -0
- data/lib/rpush/client/active_model/apns/device_token_format_validator.rb +14 -0
- data/lib/rpush/client/active_model/apns/notification.rb +90 -0
- data/lib/rpush/client/active_model/gcm/app.rb +19 -0
- data/lib/rpush/client/active_model/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +14 -0
- data/lib/rpush/client/active_model/gcm/notification.rb +31 -0
- data/lib/rpush/client/active_model/notification.rb +26 -0
- data/lib/rpush/client/active_model/payload_data_size_validator.rb +13 -0
- data/lib/rpush/client/active_model/registration_ids_count_validator.rb +13 -0
- data/lib/rpush/client/active_model/wpns/app.rb +13 -0
- data/lib/rpush/client/active_model/wpns/notification.rb +17 -0
- data/lib/rpush/client/active_model.rb +21 -0
- data/lib/rpush/client/active_record/adm/app.rb +11 -0
- data/lib/rpush/client/active_record/adm/notification.rb +11 -0
- data/lib/rpush/client/active_record/apns/app.rb +11 -0
- data/lib/rpush/client/active_record/apns/feedback.rb +22 -0
- data/lib/rpush/client/active_record/apns/notification.rb +46 -0
- data/lib/rpush/client/active_record/app.rb +17 -0
- data/lib/rpush/client/active_record/gcm/app.rb +11 -0
- data/lib/rpush/client/active_record/gcm/notification.rb +11 -0
- data/lib/rpush/client/active_record/notification.rb +38 -0
- data/lib/rpush/client/active_record/wpns/app.rb +11 -0
- data/lib/rpush/client/active_record/wpns/notification.rb +11 -0
- data/lib/rpush/client/active_record.rb +19 -0
- data/lib/rpush/client/redis/adm/app.rb +14 -0
- data/lib/rpush/client/redis/adm/notification.rb +11 -0
- data/lib/rpush/client/redis/apns/app.rb +11 -0
- data/lib/rpush/client/redis/apns/feedback.rb +20 -0
- data/lib/rpush/client/redis/apns/notification.rb +11 -0
- data/lib/rpush/client/redis/app.rb +24 -0
- data/lib/rpush/client/redis/gcm/app.rb +11 -0
- data/lib/rpush/client/redis/gcm/notification.rb +11 -0
- data/lib/rpush/client/redis/notification.rb +68 -0
- data/lib/rpush/client/redis/wpns/app.rb +11 -0
- data/lib/rpush/client/redis/wpns/notification.rb +11 -0
- data/lib/rpush/client/redis.rb +35 -0
- data/lib/rpush/configuration.rb +27 -6
- data/lib/rpush/daemon/adm/delivery.rb +56 -55
- data/lib/rpush/daemon/apns/delivery.rb +20 -44
- data/lib/rpush/daemon/apns/feedback_receiver.rb +11 -8
- data/lib/rpush/daemon/apns.rb +6 -5
- data/lib/rpush/daemon/app_runner.rb +103 -99
- data/lib/rpush/daemon/batch.rb +54 -40
- data/lib/rpush/daemon/delivery.rb +13 -3
- data/lib/rpush/daemon/delivery_error.rb +10 -2
- data/lib/rpush/daemon/dispatcher/apns_tcp.rb +114 -0
- data/lib/rpush/daemon/dispatcher/http.rb +3 -3
- data/lib/rpush/daemon/dispatcher/tcp.rb +3 -3
- data/lib/rpush/daemon/dispatcher_loop.rb +37 -23
- data/lib/rpush/daemon/errors.rb +18 -0
- data/lib/rpush/daemon/feeder.rb +28 -39
- data/lib/rpush/daemon/gcm/delivery.rb +19 -20
- data/lib/rpush/daemon/interruptible_sleep.rb +26 -45
- data/lib/rpush/daemon/loggable.rb +2 -4
- data/lib/rpush/daemon/proc_title.rb +16 -0
- data/lib/rpush/daemon/queue_payload.rb +12 -0
- data/lib/rpush/daemon/reflectable.rb +3 -5
- data/lib/rpush/daemon/retry_header_parser.rb +6 -6
- data/lib/rpush/daemon/retryable_error.rb +2 -0
- data/lib/rpush/daemon/ring_buffer.rb +16 -0
- data/lib/rpush/daemon/service_config_methods.rb +23 -7
- data/lib/rpush/daemon/signal_handler.rb +56 -0
- data/lib/rpush/daemon/store/active_record/reconnectable.rb +21 -17
- data/lib/rpush/daemon/store/active_record.rb +71 -38
- data/lib/rpush/daemon/store/interface.rb +19 -0
- data/lib/rpush/daemon/store/redis.rb +149 -0
- data/lib/rpush/daemon/string_helpers.rb +15 -0
- data/lib/rpush/daemon/synchronizer.rb +60 -0
- data/lib/rpush/daemon/tcp_connection.rb +6 -11
- data/lib/rpush/daemon/wpns/delivery.rb +21 -30
- data/lib/rpush/daemon.rb +40 -60
- data/lib/rpush/deprecatable.rb +4 -3
- data/lib/rpush/deprecation.rb +7 -10
- data/lib/rpush/embed.rb +8 -3
- data/lib/rpush/logger.rb +11 -15
- data/lib/rpush/push.rb +1 -2
- data/lib/rpush/reflection.rb +8 -12
- data/lib/rpush/version.rb +1 -1
- data/lib/rpush.rb +5 -29
- data/lib/tasks/quality.rake +35 -0
- data/lib/tasks/test.rake +1 -5
- data/spec/.rubocop.yml +4 -0
- data/spec/functional/adm_spec.rb +3 -6
- data/spec/functional/apns_spec.rb +117 -24
- data/spec/functional/embed_spec.rb +20 -20
- data/spec/functional/gcm_spec.rb +4 -7
- data/spec/functional/new_app_spec.rb +59 -0
- data/spec/functional/retry_spec.rb +46 -0
- data/spec/functional/synchronization_spec.rb +68 -0
- data/spec/functional/wpns_spec.rb +3 -6
- data/spec/functional_spec_helper.rb +26 -0
- data/spec/integration/rpush_spec.rb +13 -0
- data/spec/integration/support/gcm_success_response.json +1 -0
- data/spec/spec_helper.rb +60 -0
- data/spec/support/active_record_setup.rb +48 -0
- data/{config → spec/support/config}/database.yml +0 -0
- data/spec/support/install.sh +43 -7
- data/spec/support/simplecov_helper.rb +9 -5
- data/spec/support/simplecov_quality_formatter.rb +10 -6
- data/spec/unit/apns_feedback_spec.rb +3 -3
- data/spec/unit/{adm → client/active_record/adm}/app_spec.rb +3 -3
- data/spec/unit/{adm → client/active_record/adm}/notification_spec.rb +5 -7
- data/spec/unit/client/active_record/apns/app_spec.rb +29 -0
- data/spec/unit/client/active_record/apns/feedback_spec.rb +9 -0
- data/spec/unit/client/active_record/apns/notification_spec.rb +231 -0
- data/spec/unit/client/active_record/app_spec.rb +30 -0
- data/spec/unit/client/active_record/gcm/app_spec.rb +4 -0
- data/spec/unit/{gcm → client/active_record/gcm}/notification_spec.rb +5 -7
- data/spec/unit/client/active_record/notification_spec.rb +21 -0
- data/spec/unit/client/active_record/wpns/app_spec.rb +4 -0
- data/spec/unit/client/active_record/wpns/notification_spec.rb +21 -0
- data/spec/unit/configuration_spec.rb +12 -5
- data/spec/unit/daemon/adm/delivery_spec.rb +66 -55
- data/spec/unit/daemon/apns/certificate_expired_error_spec.rb +3 -3
- data/spec/unit/daemon/apns/delivery_spec.rb +90 -83
- data/spec/unit/daemon/apns/feedback_receiver_spec.rb +22 -17
- data/spec/unit/daemon/app_runner_spec.rb +78 -186
- data/spec/unit/daemon/batch_spec.rb +52 -115
- data/spec/unit/daemon/delivery_spec.rb +15 -1
- data/spec/unit/daemon/dispatcher/http_spec.rb +3 -2
- data/spec/unit/daemon/dispatcher/tcp_spec.rb +10 -9
- data/spec/unit/daemon/dispatcher_loop_spec.rb +6 -24
- data/spec/unit/daemon/feeder_spec.rb +38 -39
- data/spec/unit/daemon/gcm/delivery_spec.rb +122 -101
- data/spec/unit/daemon/reflectable_spec.rb +2 -2
- data/spec/unit/daemon/retryable_error_spec.rb +1 -1
- data/spec/unit/daemon/service_config_methods_spec.rb +6 -3
- data/spec/unit/daemon/signal_handler_spec.rb +95 -0
- data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +48 -27
- data/spec/unit/daemon/store/active_record_spec.rb +38 -47
- data/spec/unit/daemon/tcp_connection_spec.rb +22 -34
- data/spec/unit/daemon/wpns/delivery_spec.rb +58 -50
- data/spec/unit/daemon_spec.rb +48 -82
- data/spec/unit/embed_spec.rb +6 -4
- data/spec/unit/logger_spec.rb +35 -43
- data/spec/unit/notification_shared.rb +9 -79
- data/spec/unit/push_spec.rb +6 -10
- data/spec/unit/reflection_spec.rb +25 -25
- data/spec/unit/rpush_spec.rb +1 -2
- data/spec/unit_spec_helper.rb +33 -88
- metadata +126 -76
- data/lib/rpush/TODO +0 -3
- data/lib/rpush/adm/app.rb +0 -15
- data/lib/rpush/adm/data_validator.rb +0 -11
- data/lib/rpush/adm/notification.rb +0 -29
- data/lib/rpush/apns/app.rb +0 -29
- data/lib/rpush/apns/binary_notification_validator.rb +0 -12
- data/lib/rpush/apns/device_token_format_validator.rb +0 -12
- data/lib/rpush/apns/feedback.rb +0 -16
- data/lib/rpush/apns/notification.rb +0 -84
- data/lib/rpush/app.rb +0 -18
- data/lib/rpush/daemon/apns/certificate_expired_error.rb +0 -20
- data/lib/rpush/daemon/apns/disconnection_error.rb +0 -20
- data/lib/rpush/daemon/dispatcher_loop_collection.rb +0 -33
- data/lib/rpush/daemon/too_many_requests_error.rb +0 -20
- data/lib/rpush/gcm/app.rb +0 -11
- data/lib/rpush/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +0 -11
- data/lib/rpush/gcm/notification.rb +0 -30
- data/lib/rpush/notification.rb +0 -69
- data/lib/rpush/notifier.rb +0 -52
- data/lib/rpush/payload_data_size_validator.rb +0 -10
- data/lib/rpush/railtie.rb +0 -11
- data/lib/rpush/registration_ids_count_validator.rb +0 -10
- data/lib/rpush/wpns/app.rb +0 -9
- data/lib/rpush/wpns/notification.rb +0 -26
- data/lib/tasks/cane.rake +0 -18
- data/lib/tasks/rpush.rake +0 -16
- data/spec/unit/apns/app_spec.rb +0 -29
- data/spec/unit/apns/feedback_spec.rb +0 -9
- data/spec/unit/apns/notification_spec.rb +0 -208
- data/spec/unit/app_spec.rb +0 -30
- data/spec/unit/daemon/apns/disconnection_error_spec.rb +0 -18
- data/spec/unit/daemon/dispatcher_loop_collection_spec.rb +0 -37
- data/spec/unit/daemon/interruptible_sleep_spec.rb +0 -68
- data/spec/unit/daemon/too_many_requests_error_spec.rb +0 -14
- data/spec/unit/gcm/app_spec.rb +0 -4
- data/spec/unit/notification_spec.rb +0 -15
- data/spec/unit/notifier_spec.rb +0 -49
- data/spec/unit/wpns/app_spec.rb +0 -4
- data/spec/unit/wpns/notification_spec.rb +0 -30
data/lib/rpush/daemon/batch.rb
CHANGED
@@ -3,8 +3,7 @@ module Rpush
|
|
3
3
|
class Batch
|
4
4
|
include Reflectable
|
5
5
|
|
6
|
-
attr_reader :num_processed, :notifications,
|
7
|
-
:delivered, :failed, :retryable
|
6
|
+
attr_reader :num_processed, :notifications, :delivered, :failed, :retryable
|
8
7
|
|
9
8
|
def initialize(notifications)
|
10
9
|
@notifications = notifications
|
@@ -15,61 +14,80 @@ module Rpush
|
|
15
14
|
@mutex = Mutex.new
|
16
15
|
end
|
17
16
|
|
18
|
-
def
|
19
|
-
@
|
17
|
+
def complete?
|
18
|
+
@complete == true
|
19
|
+
end
|
20
|
+
|
21
|
+
def each_notification(&blk)
|
22
|
+
@notifications.each(&blk)
|
23
|
+
end
|
24
|
+
|
25
|
+
def each_delivered(&blk)
|
26
|
+
@delivered.each(&blk)
|
20
27
|
end
|
21
28
|
|
22
29
|
def mark_retryable(notification, deliver_after)
|
23
|
-
|
24
|
-
retryable[deliver_after] ||= []
|
25
|
-
retryable[deliver_after] << notification
|
26
|
-
Rpush::Daemon.store.mark_retryable(notification, deliver_after, :persist => false)
|
27
|
-
else
|
28
|
-
Rpush::Daemon.store.mark_retryable(notification, deliver_after)
|
29
|
-
reflect(:notification_will_retry, notification)
|
30
|
+
@mutex.synchronize do
|
31
|
+
@retryable[deliver_after] ||= []
|
32
|
+
@retryable[deliver_after] << notification
|
30
33
|
end
|
34
|
+
Rpush::Daemon.store.mark_retryable(notification, deliver_after, persist: false)
|
31
35
|
end
|
32
36
|
|
33
37
|
def mark_delivered(notification)
|
34
|
-
|
35
|
-
delivered << notification
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
@mutex.synchronize do
|
39
|
+
@delivered << notification
|
40
|
+
end
|
41
|
+
Rpush::Daemon.store.mark_delivered(notification, Time.now, persist: false)
|
42
|
+
end
|
43
|
+
|
44
|
+
def mark_all_delivered
|
45
|
+
@mutex.synchronize do
|
46
|
+
@delivered = @notifications
|
47
|
+
end
|
48
|
+
each_notification do |notification|
|
49
|
+
Rpush::Daemon.store.mark_delivered(notification, Time.now, persist: false)
|
40
50
|
end
|
41
51
|
end
|
42
52
|
|
43
53
|
def mark_failed(notification, code, description)
|
44
|
-
|
45
|
-
|
46
|
-
failed[key] ||= []
|
47
|
-
failed[key] << notification
|
48
|
-
Rpush::Daemon.store.mark_failed(notification, code, description, Time.now, :persist => false)
|
49
|
-
else
|
50
|
-
Rpush::Daemon.store.mark_failed(notification, code, description, Time.now)
|
51
|
-
reflect(:notification_failed, notification)
|
54
|
+
key = [code, description]
|
55
|
+
@mutex.synchronize do
|
56
|
+
@failed[key] ||= []
|
57
|
+
@failed[key] << notification
|
52
58
|
end
|
59
|
+
Rpush::Daemon.store.mark_failed(notification, code, description, Time.now, persist: false)
|
53
60
|
end
|
54
61
|
|
55
|
-
def
|
62
|
+
def mark_all_failed(code, message)
|
63
|
+
key = [code, message]
|
56
64
|
@mutex.synchronize do
|
57
|
-
@
|
58
|
-
|
65
|
+
@failed[key] = @notifications
|
66
|
+
end
|
67
|
+
each_notification do |notification|
|
68
|
+
Rpush::Daemon.store.mark_failed(notification, code, message, Time.now, persist: false)
|
59
69
|
end
|
60
70
|
end
|
61
71
|
|
62
|
-
def
|
63
|
-
@
|
72
|
+
def notification_processed
|
73
|
+
@mutex.synchronize do
|
74
|
+
@num_processed += 1
|
75
|
+
complete if @num_processed >= @notifications.size
|
76
|
+
end
|
64
77
|
end
|
65
78
|
|
66
|
-
def
|
67
|
-
|
79
|
+
def all_processed
|
80
|
+
@mutex.synchronize do
|
81
|
+
@num_processed = @notifications.size
|
82
|
+
complete
|
83
|
+
end
|
68
84
|
end
|
69
85
|
|
70
86
|
private
|
71
87
|
|
72
88
|
def complete
|
89
|
+
return if complete?
|
90
|
+
|
73
91
|
[:complete_delivered, :complete_failed, :complete_retried].each do |method|
|
74
92
|
begin
|
75
93
|
send(method)
|
@@ -79,36 +97,32 @@ module Rpush
|
|
79
97
|
end
|
80
98
|
end
|
81
99
|
|
82
|
-
notifications.clear
|
83
100
|
@complete = true
|
84
101
|
end
|
85
102
|
|
86
103
|
def complete_delivered
|
87
|
-
Rpush::Daemon.store.mark_batch_delivered(delivered)
|
88
|
-
delivered.each do |notification|
|
104
|
+
Rpush::Daemon.store.mark_batch_delivered(@delivered)
|
105
|
+
@delivered.each do |notification|
|
89
106
|
reflect(:notification_delivered, notification)
|
90
107
|
end
|
91
|
-
delivered.clear
|
92
108
|
end
|
93
109
|
|
94
110
|
def complete_failed
|
95
|
-
failed.each do |(code, description), notifications|
|
111
|
+
@failed.each do |(code, description), notifications|
|
96
112
|
Rpush::Daemon.store.mark_batch_failed(notifications, code, description)
|
97
113
|
notifications.each do |notification|
|
98
114
|
reflect(:notification_failed, notification)
|
99
115
|
end
|
100
116
|
end
|
101
|
-
failed.clear
|
102
117
|
end
|
103
118
|
|
104
119
|
def complete_retried
|
105
|
-
retryable.each do |deliver_after, notifications|
|
120
|
+
@retryable.each do |deliver_after, notifications|
|
106
121
|
Rpush::Daemon.store.mark_batch_retryable(notifications, deliver_after)
|
107
122
|
notifications.each do |notification|
|
108
123
|
reflect(:notification_will_retry, notification)
|
109
124
|
end
|
110
125
|
end
|
111
|
-
retryable.clear
|
112
126
|
end
|
113
127
|
end
|
114
128
|
end
|
@@ -13,15 +13,25 @@ module Rpush
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def mark_retryable_exponential(notification)
|
16
|
-
mark_retryable(notification, Time.now + 2
|
16
|
+
mark_retryable(notification, Time.now + 2**(notification.retries + 1))
|
17
17
|
end
|
18
18
|
|
19
19
|
def mark_delivered
|
20
20
|
@batch.mark_delivered(@notification)
|
21
21
|
end
|
22
22
|
|
23
|
-
def
|
24
|
-
@batch.
|
23
|
+
def mark_batch_delivered
|
24
|
+
@batch.mark_all_delivered
|
25
|
+
end
|
26
|
+
|
27
|
+
def mark_failed(error)
|
28
|
+
code = error.respond_to?(:code) ? error.code : nil
|
29
|
+
@batch.mark_failed(@notification, code, error.to_s)
|
30
|
+
end
|
31
|
+
|
32
|
+
def mark_batch_failed(error)
|
33
|
+
code = error.respond_to?(:code) ? error.code : nil
|
34
|
+
@batch.mark_all_failed(code, error.to_s)
|
25
35
|
end
|
26
36
|
end
|
27
37
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Rpush
|
2
2
|
class DeliveryError < StandardError
|
3
|
-
attr_reader :code, :
|
3
|
+
attr_reader :code, :notification_id
|
4
4
|
|
5
5
|
def initialize(code, notification_id, description)
|
6
6
|
@code = code
|
@@ -13,7 +13,15 @@ module Rpush
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def message
|
16
|
-
|
16
|
+
error_str = [@code, "(#{@description})"].compact.join(' ')
|
17
|
+
"Unable to deliver notification #{@notification_id}, received error #{error_str}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def ==(other)
|
21
|
+
other.is_a?(DeliveryError) && \
|
22
|
+
other.code == code && \
|
23
|
+
other.notification_id == notification_id && \
|
24
|
+
other.to_s == to_s
|
17
25
|
end
|
18
26
|
end
|
19
27
|
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module Rpush
|
2
|
+
module Daemon
|
3
|
+
module Dispatcher
|
4
|
+
class ApnsTcp < Rpush::Daemon::Dispatcher::Tcp
|
5
|
+
include Loggable
|
6
|
+
include Reflectable
|
7
|
+
|
8
|
+
SELECT_TIMEOUT = 10
|
9
|
+
ERROR_TUPLE_BYTES = 6
|
10
|
+
APNS_ERRORS = {
|
11
|
+
1 => 'Processing error',
|
12
|
+
2 => 'Missing device token',
|
13
|
+
3 => 'Missing topic',
|
14
|
+
4 => 'Missing payload',
|
15
|
+
5 => 'Missing token size',
|
16
|
+
6 => 'Missing topic size',
|
17
|
+
7 => 'Missing payload size',
|
18
|
+
8 => 'Invalid token',
|
19
|
+
255 => 'None (unknown error)'
|
20
|
+
}
|
21
|
+
|
22
|
+
def initialize(*args)
|
23
|
+
super
|
24
|
+
@dispatch_mutex = Mutex.new
|
25
|
+
@stop_error_receiver = false
|
26
|
+
start_error_receiver
|
27
|
+
end
|
28
|
+
|
29
|
+
def dispatch(payload)
|
30
|
+
@dispatch_mutex.synchronize do
|
31
|
+
@delivery_class.new(@app, connection, payload.batch).perform
|
32
|
+
record_batch(payload.batch)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def cleanup
|
37
|
+
@stop_error_receiver = true
|
38
|
+
super
|
39
|
+
@error_receiver_thread.join if @error_receiver_thread
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def start_error_receiver
|
45
|
+
@error_receiver_thread = Thread.new do
|
46
|
+
check_for_error until @stop_error_receiver
|
47
|
+
Rpush::Daemon.store.release_connection
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def delivered_buffer
|
52
|
+
@delivered_buffer ||= RingBuffer.new(Rpush.config.batch_size * 10)
|
53
|
+
end
|
54
|
+
|
55
|
+
def record_batch(batch)
|
56
|
+
batch.each_delivered do |notification|
|
57
|
+
delivered_buffer << notification.id
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def check_for_error
|
62
|
+
begin
|
63
|
+
return unless connection.select(SELECT_TIMEOUT)
|
64
|
+
rescue Errno::EBADF
|
65
|
+
# Connection closed, daemon is shutting down.
|
66
|
+
return
|
67
|
+
end
|
68
|
+
|
69
|
+
tuple = connection.read(ERROR_TUPLE_BYTES)
|
70
|
+
@dispatch_mutex.synchronize { handle_error_response(tuple) }
|
71
|
+
end
|
72
|
+
|
73
|
+
def handle_error_response(tuple)
|
74
|
+
if tuple
|
75
|
+
_, code, notification_id = tuple.unpack('ccN')
|
76
|
+
handle_error(code, notification_id)
|
77
|
+
else
|
78
|
+
handle_disconnect
|
79
|
+
end
|
80
|
+
|
81
|
+
log_error('Error received, reconnecting...')
|
82
|
+
connection.reconnect
|
83
|
+
ensure
|
84
|
+
delivered_buffer.clear
|
85
|
+
end
|
86
|
+
|
87
|
+
def handle_disconnect
|
88
|
+
log_error('The APNs disconnected without returning an error. Marking all notifications delivered via this connection as failed.')
|
89
|
+
reason = 'The APNs disconnected without returning an error. This may indicate you are using an invalid certificate.'
|
90
|
+
Rpush::Daemon.store.mark_ids_failed(delivered_buffer, nil, reason, Time.now)
|
91
|
+
delivered_buffer.each { |id| reflect(:notification_id_failed, @app, id, nil, reason) }
|
92
|
+
end
|
93
|
+
|
94
|
+
def handle_error(code, notification_id)
|
95
|
+
failed_pos = delivered_buffer.index(notification_id)
|
96
|
+
description = APNS_ERRORS[code.to_i] || "Unknown error code #{code.inspect}. Possible Rpush bug?"
|
97
|
+
Rpush::Daemon.store.mark_ids_failed([notification_id], code, description, Time.now)
|
98
|
+
reflect(:notification_id_failed, @app, notification_id, code, description)
|
99
|
+
|
100
|
+
if failed_pos
|
101
|
+
retry_ids = delivered_buffer[(failed_pos + 1)..-1]
|
102
|
+
if retry_ids.size > 0
|
103
|
+
now = Time.now
|
104
|
+
Rpush::Daemon.store.mark_ids_retryable(retry_ids, now)
|
105
|
+
retry_ids.each { |id| reflect(:notification_id_will_retry, @app, id, now) }
|
106
|
+
end
|
107
|
+
elsif delivered_buffer.size > 0
|
108
|
+
log_error("Delivery sequence unknown for notifications following #{notification_id}.")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -2,14 +2,14 @@ module Rpush
|
|
2
2
|
module Daemon
|
3
3
|
module Dispatcher
|
4
4
|
class Http
|
5
|
-
def initialize(app, delivery_class,
|
5
|
+
def initialize(app, delivery_class, _options = {})
|
6
6
|
@app = app
|
7
7
|
@delivery_class = delivery_class
|
8
8
|
@http = Net::HTTP::Persistent.new('rpush')
|
9
9
|
end
|
10
10
|
|
11
|
-
def dispatch(
|
12
|
-
@delivery_class.new(@app, @http, notification, batch).perform
|
11
|
+
def dispatch(payload)
|
12
|
+
@delivery_class.new(@app, @http, payload.notification, payload.batch).perform
|
13
13
|
end
|
14
14
|
|
15
15
|
def cleanup
|
@@ -8,15 +8,15 @@ module Rpush
|
|
8
8
|
@host, @port = options[:host].call(@app)
|
9
9
|
end
|
10
10
|
|
11
|
-
def dispatch(
|
12
|
-
@delivery_class.new(@app, connection, notification, batch).perform
|
11
|
+
def dispatch(payload)
|
12
|
+
@delivery_class.new(@app, connection, payload.notification, payload.batch).perform
|
13
13
|
end
|
14
14
|
|
15
15
|
def cleanup
|
16
16
|
@connection.close if @connection
|
17
17
|
end
|
18
18
|
|
19
|
-
|
19
|
+
protected
|
20
20
|
|
21
21
|
def connection
|
22
22
|
return @connection if defined? @connection
|
@@ -2,19 +2,38 @@ module Rpush
|
|
2
2
|
module Daemon
|
3
3
|
class DispatcherLoop
|
4
4
|
include Reflectable
|
5
|
+
include Loggable
|
5
6
|
|
6
|
-
|
7
|
+
attr_reader :started_at, :dispatch_count
|
8
|
+
|
9
|
+
STOP = :stop
|
7
10
|
|
8
11
|
def initialize(queue, dispatcher)
|
9
12
|
@queue = queue
|
10
13
|
@dispatcher = dispatcher
|
14
|
+
@dispatch_count = 0
|
15
|
+
end
|
16
|
+
|
17
|
+
def thread_status
|
18
|
+
@thread ? @thread.status : 'not started'
|
11
19
|
end
|
12
20
|
|
13
21
|
def start
|
22
|
+
@started_at = Time.now
|
23
|
+
|
14
24
|
@thread = Thread.new do
|
15
25
|
loop do
|
16
|
-
|
17
|
-
|
26
|
+
payload = @queue.pop
|
27
|
+
if stop_payload?(payload)
|
28
|
+
break if should_stop?(payload)
|
29
|
+
|
30
|
+
# Intended for another dispatcher loop.
|
31
|
+
@queue.push(payload)
|
32
|
+
Thread.pass
|
33
|
+
sleep 0.1
|
34
|
+
else
|
35
|
+
dispatch(payload)
|
36
|
+
end
|
18
37
|
end
|
19
38
|
|
20
39
|
Rpush::Daemon.store.release_connection
|
@@ -22,32 +41,27 @@ module Rpush
|
|
22
41
|
end
|
23
42
|
|
24
43
|
def stop
|
25
|
-
@
|
26
|
-
end
|
27
|
-
|
28
|
-
def wakeup
|
29
|
-
@queue.push(WAKEUP) if @thread
|
30
|
-
end
|
31
|
-
|
32
|
-
def wait
|
44
|
+
@queue.push([STOP, object_id]) if @thread
|
33
45
|
@thread.join if @thread
|
34
46
|
@dispatcher.cleanup
|
35
47
|
end
|
36
48
|
|
37
|
-
|
49
|
+
private
|
50
|
+
|
51
|
+
def stop_payload?(payload)
|
52
|
+
payload.is_a?(Array) && payload.first == STOP
|
53
|
+
end
|
38
54
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
55
|
+
def should_stop?(payload)
|
56
|
+
payload.last == object_id
|
57
|
+
end
|
42
58
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
batch.notification_dispatched
|
50
|
-
end
|
59
|
+
def dispatch(payload)
|
60
|
+
@dispatch_count += 1
|
61
|
+
@dispatcher.dispatch(payload)
|
62
|
+
rescue StandardError => e
|
63
|
+
log_error(e)
|
64
|
+
reflect(:error, e)
|
51
65
|
end
|
52
66
|
end
|
53
67
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Rpush
|
2
|
+
class CertificateExpiredError < StandardError
|
3
|
+
attr_reader :app, :time
|
4
|
+
|
5
|
+
def initialize(app, time)
|
6
|
+
@app = app
|
7
|
+
@time = time
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
message
|
12
|
+
end
|
13
|
+
|
14
|
+
def message
|
15
|
+
"#{app.name} certificate expired at #{time}."
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/rpush/daemon/feeder.rb
CHANGED
@@ -4,63 +4,52 @@ module Rpush
|
|
4
4
|
extend Reflectable
|
5
5
|
|
6
6
|
def self.start
|
7
|
-
|
8
|
-
|
9
|
-
if Rpush.config.embedded
|
10
|
-
Thread.new { feed_forever }
|
11
|
-
elsif Rpush.config.push
|
12
|
-
enqueue_notifications
|
13
|
-
else
|
14
|
-
feed_forever
|
15
|
-
end
|
7
|
+
self.should_stop = false
|
8
|
+
Rpush.config.push ? enqueue_notifications : feed_forever
|
16
9
|
end
|
17
10
|
|
18
11
|
def self.stop
|
19
|
-
|
20
|
-
|
12
|
+
self.should_stop = true
|
13
|
+
interruptible_sleeper.stop
|
14
|
+
@thread.join if @thread
|
21
15
|
end
|
22
16
|
|
23
|
-
def self.
|
24
|
-
interruptible_sleeper.
|
17
|
+
def self.wakeup
|
18
|
+
interruptible_sleeper.wakeup
|
25
19
|
end
|
26
20
|
|
27
|
-
|
21
|
+
class << self
|
22
|
+
attr_accessor :should_stop
|
23
|
+
end
|
28
24
|
|
29
25
|
def self.feed_forever
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
26
|
+
@thread = Thread.new do
|
27
|
+
loop do
|
28
|
+
enqueue_notifications
|
29
|
+
interruptible_sleeper.sleep
|
30
|
+
break if should_stop
|
31
|
+
end
|
32
|
+
|
33
|
+
Rpush::Daemon.store.release_connection
|
34
34
|
end
|
35
35
|
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
# :nocov:
|
40
|
-
def self.stop?
|
41
|
-
@stop
|
36
|
+
@thread.join
|
42
37
|
end
|
43
38
|
|
44
39
|
def self.enqueue_notifications
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
reflect(:error, e)
|
53
|
-
end
|
40
|
+
batch_size = Rpush.config.batch_size - Rpush::Daemon::AppRunner.total_queued
|
41
|
+
return if batch_size <= 0
|
42
|
+
notifications = Rpush::Daemon.store.deliverable_notifications(batch_size)
|
43
|
+
Rpush::Daemon::AppRunner.enqueue(notifications)
|
44
|
+
rescue StandardError => e
|
45
|
+
Rpush.logger.error(e)
|
46
|
+
reflect(:error, e)
|
54
47
|
end
|
55
48
|
|
56
49
|
def self.interruptible_sleeper
|
57
50
|
return @interruptible_sleeper if @interruptible_sleeper
|
58
|
-
|
59
|
-
@interruptible_sleeper
|
60
|
-
if Rpush.config.wakeup
|
61
|
-
@interruptible_sleeper.enable_wake_on_udp Rpush.config.wakeup[:bind], Rpush.config.wakeup[:port]
|
62
|
-
end
|
63
|
-
|
51
|
+
@interruptible_sleeper = InterruptibleSleep.new(Rpush.config.push_poll)
|
52
|
+
@interruptible_sleeper.start
|
64
53
|
@interruptible_sleeper
|
65
54
|
end
|
66
55
|
end
|
@@ -1,15 +1,14 @@
|
|
1
1
|
module Rpush
|
2
2
|
module Daemon
|
3
3
|
module Gcm
|
4
|
-
|
5
4
|
# http://developer.android.com/guide/google/gcm/gcm.html#response
|
6
5
|
class Delivery < Rpush::Daemon::Delivery
|
7
6
|
include MultiJsonHelper
|
8
7
|
|
9
8
|
host = ENV["RPUSH_GCM_HOST"] || "https://android.googleapis.com"
|
10
9
|
GCM_URI = URI.parse("#{host}/gcm/send")
|
11
|
-
UNAVAILABLE_STATES =
|
12
|
-
INVALID_REGISTRATION_ID_STATES =
|
10
|
+
UNAVAILABLE_STATES = %w(Unavailable InternalServerError)
|
11
|
+
INVALID_REGISTRATION_ID_STATES = %w(InvalidRegistration MismatchSenderId NotRegistered InvalidPackageName)
|
13
12
|
|
14
13
|
def initialize(app, http, notification, batch)
|
15
14
|
@app = app
|
@@ -19,12 +18,12 @@ module Rpush
|
|
19
18
|
end
|
20
19
|
|
21
20
|
def perform
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
handle_response(do_post)
|
22
|
+
rescue StandardError => error
|
23
|
+
mark_failed(error)
|
24
|
+
raise
|
25
|
+
ensure
|
26
|
+
@batch.notification_processed
|
28
27
|
end
|
29
28
|
|
30
29
|
protected
|
@@ -42,7 +41,7 @@ module Rpush
|
|
42
41
|
when 503
|
43
42
|
service_unavailable(response)
|
44
43
|
else
|
45
|
-
|
44
|
+
fail Rpush::DeliveryError.new(response.code, @notification.id, Rpush::Daemon::HTTP_STATUS_CODES[response.code.to_i])
|
46
45
|
end
|
47
46
|
end
|
48
47
|
|
@@ -69,9 +68,8 @@ module Rpush
|
|
69
68
|
def handle_successes(successes)
|
70
69
|
successes.each do |result|
|
71
70
|
reflect(:gcm_delivered_to_recipient, @notification, result[:registration_id])
|
72
|
-
|
73
|
-
|
74
|
-
end
|
71
|
+
next unless result.key?(:canonical_id)
|
72
|
+
reflect(:gcm_canonical_id, result[:registration_id], result[:canonical_id])
|
75
73
|
end
|
76
74
|
end
|
77
75
|
|
@@ -86,7 +84,7 @@ module Rpush
|
|
86
84
|
failures.description += " #{unavailable_idxs.join(', ')} will be retried as notification #{new_notification.id}."
|
87
85
|
end
|
88
86
|
handle_errors(failures)
|
89
|
-
|
87
|
+
fail Rpush::DeliveryError.new(nil, @notification.id, failures.description)
|
90
88
|
end
|
91
89
|
end
|
92
90
|
|
@@ -103,15 +101,15 @@ module Rpush
|
|
103
101
|
attrs = @notification.attributes.slice('app_id', 'collapse_key', 'delay_while_idle')
|
104
102
|
registration_ids = @notification.registration_ids.values_at(*unavailable_idxs)
|
105
103
|
Rpush::Daemon.store.create_gcm_notification(attrs, @notification.data,
|
106
|
-
|
104
|
+
registration_ids, deliver_after_header(response), @notification.app)
|
107
105
|
end
|
108
106
|
|
109
107
|
def bad_request
|
110
|
-
|
108
|
+
fail Rpush::DeliveryError.new(400, @notification.id, 'GCM failed to parse the JSON request. Possibly an Rpush bug, please open an issue.')
|
111
109
|
end
|
112
110
|
|
113
111
|
def unauthorized
|
114
|
-
|
112
|
+
fail Rpush::DeliveryError.new(401, @notification.id, 'Unauthorized, check your App auth_key.')
|
115
113
|
end
|
116
114
|
|
117
115
|
def internal_server_error(response)
|
@@ -129,7 +127,8 @@ module Rpush
|
|
129
127
|
end
|
130
128
|
|
131
129
|
def retry_delivery(notification, response)
|
132
|
-
|
130
|
+
time = deliver_after_header(response)
|
131
|
+
if time
|
133
132
|
mark_retryable(notification, time)
|
134
133
|
else
|
135
134
|
mark_retryable_exponential(notification)
|
@@ -141,8 +140,8 @@ module Rpush
|
|
141
140
|
end
|
142
141
|
|
143
142
|
def do_post
|
144
|
-
post = Net::HTTP::Post.new(GCM_URI.path,
|
145
|
-
|
143
|
+
post = Net::HTTP::Post.new(GCM_URI.path, 'Content-Type' => 'application/json',
|
144
|
+
'Authorization' => "key=#{@notification.app.auth_key}")
|
146
145
|
post.body = @notification.as_json.to_json
|
147
146
|
@http.request(GCM_URI, post)
|
148
147
|
end
|