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
@@ -0,0 +1,149 @@
|
|
1
|
+
module Rpush
|
2
|
+
module Daemon
|
3
|
+
module Store
|
4
|
+
class Redis
|
5
|
+
DEFAULT_MARK_OPTIONS = { persist: true }
|
6
|
+
|
7
|
+
def app(app_id)
|
8
|
+
Rpush::Client::Redis::App.find(app_id)
|
9
|
+
end
|
10
|
+
|
11
|
+
def all_apps
|
12
|
+
Rpush::Client::Redis::App.all
|
13
|
+
end
|
14
|
+
|
15
|
+
def deliverable_notifications(limit)
|
16
|
+
retryable_ids = retryable_notification_ids
|
17
|
+
limit -= retryable_ids.size
|
18
|
+
pending_ids = limit > 0 ? pending_notification_ids(limit) : []
|
19
|
+
ids = retryable_ids + pending_ids
|
20
|
+
ids.map { |id| Rpush::Client::Redis::Notification.find(id) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def mark_delivered(notification, time, opts = {})
|
24
|
+
opts = DEFAULT_MARK_OPTIONS.dup.merge(opts)
|
25
|
+
notification.delivered = true
|
26
|
+
notification.delivered_at = time
|
27
|
+
notification.save!(validate: false) if opts[:persist]
|
28
|
+
end
|
29
|
+
|
30
|
+
def mark_batch_delivered(notifications)
|
31
|
+
now = Time.now
|
32
|
+
notifications.each { |n| mark_delivered(n, now) }
|
33
|
+
end
|
34
|
+
|
35
|
+
def mark_failed(notification, code, description, time, opts = {})
|
36
|
+
opts = DEFAULT_MARK_OPTIONS.dup.merge(opts)
|
37
|
+
notification.delivered = false
|
38
|
+
notification.delivered_at = nil
|
39
|
+
notification.failed = true
|
40
|
+
notification.failed_at = time
|
41
|
+
notification.error_code = code
|
42
|
+
notification.error_description = description
|
43
|
+
notification.save!(validate: false) if opts[:persist]
|
44
|
+
end
|
45
|
+
|
46
|
+
def mark_batch_failed(notifications, code, description)
|
47
|
+
now = Time.now
|
48
|
+
notifications.each { |n| mark_failed(n, code, description, now) }
|
49
|
+
end
|
50
|
+
|
51
|
+
def mark_ids_failed(ids, code, description, time)
|
52
|
+
ids.each { |id| mark_failed(Rpush::Client::Redis::Apns::Notification.find(id), code, description, time) }
|
53
|
+
end
|
54
|
+
|
55
|
+
def mark_retryable(notification, deliver_after, opts = {})
|
56
|
+
opts = DEFAULT_MARK_OPTIONS.dup.merge(opts)
|
57
|
+
notification.delivered = false
|
58
|
+
notification.delivered_at = nil
|
59
|
+
notification.failed = false
|
60
|
+
notification.failed_at = nil
|
61
|
+
notification.retries += 1
|
62
|
+
notification.deliver_after = deliver_after
|
63
|
+
|
64
|
+
return unless opts[:persist]
|
65
|
+
|
66
|
+
notification.save!(validate: false)
|
67
|
+
namespace = Rpush::Client::Redis::Notification.absolute_retryable_namespace
|
68
|
+
Modis.with_connection do |redis|
|
69
|
+
redis.zadd(namespace, deliver_after.to_i, notification.id)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def mark_batch_retryable(notifications, deliver_after)
|
74
|
+
notifications.each { |n| mark_retryable(n, deliver_after) }
|
75
|
+
end
|
76
|
+
|
77
|
+
def mark_ids_retryable(ids, deliver_after)
|
78
|
+
ids.each { |id| mark_retryable(Rpush::Client::Redis::Apns::Notification.find(id), deliver_after) }
|
79
|
+
end
|
80
|
+
|
81
|
+
def create_apns_feedback(failed_at, device_token, app)
|
82
|
+
Rpush::Client::Redis::Apns::Feedback.create!(failed_at: failed_at, device_token: device_token, app_id: app.id)
|
83
|
+
end
|
84
|
+
|
85
|
+
def create_gcm_notification(attrs, data, registration_ids, deliver_after, app) # rubocop:disable ParameterLists
|
86
|
+
notification = Rpush::Client::Redis::Gcm::Notification.new
|
87
|
+
create_gcm_like_notification(notification, attrs, data, registration_ids, deliver_after, app)
|
88
|
+
end
|
89
|
+
|
90
|
+
def create_adm_notification(attrs, data, registration_ids, deliver_after, app) # rubocop:disable ParameterLists
|
91
|
+
notification = Rpush::Client::Redis::Adm::Notification.new
|
92
|
+
create_gcm_like_notification(notification, attrs, data, registration_ids, deliver_after, app)
|
93
|
+
end
|
94
|
+
|
95
|
+
def update_app(app)
|
96
|
+
app.save!
|
97
|
+
end
|
98
|
+
|
99
|
+
def update_notification(notification)
|
100
|
+
notification.save!
|
101
|
+
end
|
102
|
+
|
103
|
+
def release_connection
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def create_gcm_like_notification(notification, attrs, data, registration_ids, deliver_after, app) # rubocop:disable ParameterLists
|
109
|
+
notification.assign_attributes(attrs)
|
110
|
+
notification.data = data
|
111
|
+
notification.registration_ids = registration_ids
|
112
|
+
notification.deliver_after = deliver_after
|
113
|
+
notification.app = app
|
114
|
+
notification.save!
|
115
|
+
notification
|
116
|
+
end
|
117
|
+
|
118
|
+
def retryable_notification_ids
|
119
|
+
retryable_ns = Rpush::Client::Redis::Notification.absolute_retryable_namespace
|
120
|
+
|
121
|
+
Modis.with_connection do |redis|
|
122
|
+
retryable_results = redis.multi do
|
123
|
+
now = Time.now.to_i
|
124
|
+
redis.zrangebyscore(retryable_ns, 0, now)
|
125
|
+
redis.zremrangebyscore(retryable_ns, 0, now)
|
126
|
+
end
|
127
|
+
|
128
|
+
retryable_results.first
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def pending_notification_ids(limit)
|
133
|
+
pending_ns = Rpush::Client::Redis::Notification.absolute_pending_namespace
|
134
|
+
|
135
|
+
Modis.with_connection do |redis|
|
136
|
+
pending_results = redis.multi do
|
137
|
+
redis.zrange(pending_ns, 0, limit)
|
138
|
+
redis.zremrangebyrank(pending_ns, 0, limit)
|
139
|
+
end
|
140
|
+
|
141
|
+
pending_results.first
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
Rpush::Daemon::Store::Interface.check(Rpush::Daemon::Store::Redis)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Rpush
|
2
|
+
module Daemon
|
3
|
+
module StringHelpers
|
4
|
+
def pluralize(count, singular, plural = nil)
|
5
|
+
if count == 1 || count =~ /^1(\.0+)?$/
|
6
|
+
word = singular
|
7
|
+
else
|
8
|
+
word = plural || singular.pluralize
|
9
|
+
end
|
10
|
+
|
11
|
+
"#{count || 0} #{word}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Rpush
|
2
|
+
module Daemon
|
3
|
+
class Synchronizer
|
4
|
+
extend Loggable
|
5
|
+
extend StringHelpers
|
6
|
+
|
7
|
+
def self.sync
|
8
|
+
apps = Rpush::Daemon.store.all_apps
|
9
|
+
apps.each { |app| sync_app(app) }
|
10
|
+
removed = AppRunner.app_ids - apps.map(&:id)
|
11
|
+
removed.each { |app_id| AppRunner.stop_app(app_id) }
|
12
|
+
|
13
|
+
ProcTitle.update
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.sync_app(app)
|
17
|
+
if !AppRunner.app_running?(app)
|
18
|
+
AppRunner.start_app(app)
|
19
|
+
elsif certificate_changed?(app)
|
20
|
+
log_info("[#{app.name}] Certificate changed, restarting...")
|
21
|
+
AppRunner.stop_app(app.id)
|
22
|
+
AppRunner.start_app(app)
|
23
|
+
elsif environment_changed?(app)
|
24
|
+
log_info("[#{app.name}] Environment changed, restarting...")
|
25
|
+
AppRunner.stop_app(app.id)
|
26
|
+
AppRunner.start_app(app)
|
27
|
+
else
|
28
|
+
sync_dispatcher_count(app)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.sync_dispatcher_count(app)
|
33
|
+
num_dispatchers = AppRunner.num_dispatchers_for_app(app)
|
34
|
+
diff = num_dispatchers - app.connections
|
35
|
+
return if diff == 0
|
36
|
+
|
37
|
+
if diff > 0
|
38
|
+
AppRunner.decrement_dispatchers(app, diff)
|
39
|
+
start_stop_str = "Stopped"
|
40
|
+
else
|
41
|
+
AppRunner.increment_dispatchers(app, diff.abs)
|
42
|
+
start_stop_str = "Started"
|
43
|
+
end
|
44
|
+
|
45
|
+
num_dispatchers = AppRunner.num_dispatchers_for_app(app)
|
46
|
+
log_info("[#{app.name}] #{start_stop_str} #{pluralize(diff.abs, 'dispatcher')}. #{num_dispatchers} running.")
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.certificate_changed?(app)
|
50
|
+
old_app = AppRunner.app_with_id(app.id)
|
51
|
+
app.certificate != old_app.certificate
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.environment_changed?(app)
|
55
|
+
old_app = AppRunner.app_with_id(app.id)
|
56
|
+
app.environment != old_app.environment
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -27,11 +27,9 @@ module Rpush
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def close
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
rescue IOError
|
34
|
-
end
|
30
|
+
@ssl_socket.close if @ssl_socket
|
31
|
+
@tcp_socket.close if @tcp_socket
|
32
|
+
rescue IOError # rubocop:disable HandleExceptions
|
35
33
|
end
|
36
34
|
|
37
35
|
def read(num_bytes)
|
@@ -50,11 +48,10 @@ module Rpush
|
|
50
48
|
begin
|
51
49
|
write_data(data)
|
52
50
|
rescue Errno::EPIPE, Errno::ETIMEDOUT, OpenSSL::SSL::SSLError, IOError => e
|
53
|
-
retry_count += 1
|
51
|
+
retry_count += 1
|
54
52
|
|
55
53
|
if retry_count == 1
|
56
54
|
log_error("Lost connection to #{@host}:#{@port} (#{e.class.name}), reconnecting...")
|
57
|
-
reflect(:apns_connection_lost, @app, e) # deprecated
|
58
55
|
reflect(:tcp_connection_lost, @app, e)
|
59
56
|
end
|
60
57
|
|
@@ -63,7 +60,7 @@ module Rpush
|
|
63
60
|
sleep 1
|
64
61
|
retry
|
65
62
|
else
|
66
|
-
raise TcpConnectionError, "#{@app.name} tried #{retry_count-1} times to reconnect but failed (#{e.class.name})."
|
63
|
+
raise TcpConnectionError, "#{@app.name} tried #{retry_count - 1} times to reconnect but failed (#{e.class.name})."
|
67
64
|
end
|
68
65
|
end
|
69
66
|
end
|
@@ -110,7 +107,6 @@ module Rpush
|
|
110
107
|
ssl_socket = OpenSSL::SSL::SSLSocket.new(tcp_socket, @ssl_context)
|
111
108
|
ssl_socket.sync = true
|
112
109
|
ssl_socket.connect
|
113
|
-
log_info("Connected to #{@host}:#{@port}")
|
114
110
|
[tcp_socket, ssl_socket]
|
115
111
|
end
|
116
112
|
|
@@ -118,10 +114,9 @@ module Rpush
|
|
118
114
|
cert = @ssl_context.cert
|
119
115
|
if certificate_expired?
|
120
116
|
log_error(certificate_msg('expired'))
|
121
|
-
|
117
|
+
fail Rpush::CertificateExpiredError.new(@app, cert.not_after)
|
122
118
|
elsif certificate_expires_soon?
|
123
119
|
log_warn(certificate_msg('will expire'))
|
124
|
-
reflect(:apns_certificate_will_expire, @app, cert.not_after) # deprecated
|
125
120
|
reflect(:ssl_certificate_will_expire, @app, cert.not_after)
|
126
121
|
end
|
127
122
|
end
|
@@ -1,10 +1,8 @@
|
|
1
1
|
module Rpush
|
2
2
|
module Daemon
|
3
3
|
module Wpns
|
4
|
-
|
5
4
|
# http://msdn.microsoft.com/en-us/library/windowsphone/develop/ff941100%28v=vs.105%29.aspx
|
6
5
|
class Delivery < Rpush::Daemon::Delivery
|
7
|
-
|
8
6
|
FAILURE_MESSAGES = {
|
9
7
|
400 => 'Bad XML or malformed notification URI.',
|
10
8
|
401 => 'Unauthorized to send a notification to this app.'
|
@@ -18,12 +16,12 @@ module Rpush
|
|
18
16
|
end
|
19
17
|
|
20
18
|
def perform
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
19
|
+
handle_response(do_post)
|
20
|
+
rescue StandardError => error
|
21
|
+
mark_failed(error)
|
22
|
+
raise
|
23
|
+
ensure
|
24
|
+
@batch.notification_processed
|
27
25
|
end
|
28
26
|
|
29
27
|
private
|
@@ -34,25 +32,21 @@ module Rpush
|
|
34
32
|
when 200
|
35
33
|
ok(response)
|
36
34
|
when 406
|
37
|
-
not_acceptable
|
35
|
+
not_acceptable
|
38
36
|
when 412
|
39
|
-
precondition_failed
|
37
|
+
precondition_failed
|
40
38
|
when 503
|
41
|
-
service_unavailable
|
39
|
+
service_unavailable
|
42
40
|
else
|
43
41
|
handle_failure(code)
|
44
42
|
end
|
45
43
|
end
|
46
44
|
|
47
|
-
def handle_failure(code, msg=nil)
|
45
|
+
def handle_failure(code, msg = nil)
|
48
46
|
unless msg
|
49
|
-
msg =
|
50
|
-
FAILURE_MESSAGES[code]
|
51
|
-
else
|
52
|
-
Rpush::Daemon::HTTP_STATUS_CODES[code]
|
53
|
-
end
|
47
|
+
msg = FAILURE_MESSAGES.key?(code) ? FAILURE_MESSAGES[code] : Rpush::Daemon::HTTP_STATUS_CODES[code]
|
54
48
|
end
|
55
|
-
|
49
|
+
fail Rpush::DeliveryError.new(code, @notification.id, msg)
|
56
50
|
end
|
57
51
|
|
58
52
|
def ok(response)
|
@@ -62,22 +56,22 @@ module Rpush
|
|
62
56
|
mark_delivered
|
63
57
|
log_info("#{@notification.id} sent successfully")
|
64
58
|
when ["QueueFull"]
|
65
|
-
mark_retryable(@notification, Time.now + (60*10))
|
59
|
+
mark_retryable(@notification, Time.now + (60 * 10))
|
66
60
|
log_warn("#{@notification.id} cannot be sent. The Queue is full.")
|
67
61
|
when ["Suppressed"]
|
68
62
|
handle_failure(200, "Notification was received but suppressed by the service.")
|
69
63
|
end
|
70
64
|
end
|
71
65
|
|
72
|
-
def not_acceptable
|
66
|
+
def not_acceptable
|
73
67
|
retry_notification("Per-day throttling limit reached.")
|
74
68
|
end
|
75
69
|
|
76
|
-
def precondition_failed
|
70
|
+
def precondition_failed
|
77
71
|
retry_notification("Device unreachable.")
|
78
72
|
end
|
79
73
|
|
80
|
-
def service_unavailable
|
74
|
+
def service_unavailable
|
81
75
|
mark_retryable_exponential(@notification)
|
82
76
|
log_warn("Service Unavailable. " + retry_message)
|
83
77
|
end
|
@@ -87,20 +81,17 @@ module Rpush
|
|
87
81
|
end
|
88
82
|
|
89
83
|
def retry_notification(reason)
|
90
|
-
deliver_after = Time.now + (60*60)
|
84
|
+
deliver_after = Time.now + (60 * 60)
|
91
85
|
mark_retryable(@notification, deliver_after)
|
92
86
|
log_warn("#{reason} " + retry_message)
|
93
87
|
end
|
94
88
|
|
95
89
|
def do_post
|
96
90
|
body = notification_to_xml
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
"X-NotificationClass" => '2'
|
102
|
-
}
|
103
|
-
post = Net::HTTP::Post.new(URI.parse(@notification.uri).path, initheader=header)
|
91
|
+
post = Net::HTTP::Post.new(URI.parse(@notification.uri).path, "Content-Length" => body.length.to_s,
|
92
|
+
"Content-Type" => "text/xml",
|
93
|
+
"X-WindowsPhone-Target" => "toast",
|
94
|
+
"X-NotificationClass" => '2')
|
104
95
|
post.body = body
|
105
96
|
@http.request(URI.parse(@notification.uri), post)
|
106
97
|
end
|
data/lib/rpush/daemon.rb
CHANGED
@@ -2,31 +2,36 @@ require 'thread'
|
|
2
2
|
require 'socket'
|
3
3
|
require 'pathname'
|
4
4
|
require 'openssl'
|
5
|
-
|
6
5
|
require 'net/http/persistent'
|
7
6
|
|
7
|
+
require 'rpush/daemon/errors'
|
8
8
|
require 'rpush/daemon/constants'
|
9
9
|
require 'rpush/daemon/reflectable'
|
10
10
|
require 'rpush/daemon/loggable'
|
11
|
+
require 'rpush/daemon/string_helpers'
|
11
12
|
require 'rpush/daemon/interruptible_sleep'
|
12
13
|
require 'rpush/daemon/delivery_error'
|
13
14
|
require 'rpush/daemon/retryable_error'
|
14
|
-
require 'rpush/daemon/too_many_requests_error'
|
15
15
|
require 'rpush/daemon/delivery'
|
16
16
|
require 'rpush/daemon/feeder'
|
17
17
|
require 'rpush/daemon/batch'
|
18
|
+
require 'rpush/daemon/queue_payload'
|
19
|
+
require 'rpush/daemon/synchronizer'
|
18
20
|
require 'rpush/daemon/app_runner'
|
19
21
|
require 'rpush/daemon/tcp_connection'
|
20
22
|
require 'rpush/daemon/dispatcher_loop'
|
21
|
-
require 'rpush/daemon/dispatcher_loop_collection'
|
22
23
|
require 'rpush/daemon/dispatcher/http'
|
23
24
|
require 'rpush/daemon/dispatcher/tcp'
|
25
|
+
require 'rpush/daemon/dispatcher/apns_tcp'
|
24
26
|
require 'rpush/daemon/service_config_methods'
|
25
27
|
require 'rpush/daemon/retry_header_parser'
|
28
|
+
require 'rpush/daemon/ring_buffer'
|
29
|
+
require 'rpush/daemon/signal_handler'
|
30
|
+
require 'rpush/daemon/proc_title'
|
31
|
+
|
32
|
+
require 'rpush/daemon/store/interface'
|
26
33
|
|
27
34
|
require 'rpush/daemon/apns/delivery'
|
28
|
-
require 'rpush/daemon/apns/disconnection_error'
|
29
|
-
require 'rpush/daemon/apns/certificate_expired_error'
|
30
35
|
require 'rpush/daemon/apns/feedback_receiver'
|
31
36
|
require 'rpush/daemon/apns'
|
32
37
|
|
@@ -46,69 +51,59 @@ module Rpush
|
|
46
51
|
end
|
47
52
|
|
48
53
|
def self.start
|
49
|
-
|
50
|
-
|
54
|
+
Process.daemon if daemonize?
|
55
|
+
SignalHandler.start
|
51
56
|
initialize_store
|
52
|
-
|
57
|
+
write_pid_file
|
58
|
+
Synchronizer.sync
|
53
59
|
|
54
|
-
|
55
|
-
|
56
|
-
store.after_daemonize
|
57
|
-
end
|
60
|
+
# No further store connections will be made from this thread.
|
61
|
+
store.release_connection
|
58
62
|
|
59
|
-
|
60
|
-
AppRunner.sync
|
63
|
+
# Blocking call, returns after Feeder.stop is called from another thread.
|
61
64
|
Feeder.start
|
65
|
+
|
66
|
+
# Wait for shutdown to complete.
|
67
|
+
shutdown_lock.synchronize { true }
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.shutdown
|
71
|
+
puts "\nShutting down..."
|
72
|
+
|
73
|
+
shutdown_lock.synchronize do
|
74
|
+
Feeder.stop
|
75
|
+
AppRunner.stop
|
76
|
+
delete_pid_file
|
77
|
+
end
|
62
78
|
end
|
63
79
|
|
64
|
-
def self.
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
delete_pid_file
|
80
|
+
def self.shutdown_lock
|
81
|
+
return @shutdown_lock if @shutdown_lock
|
82
|
+
@shutdown_lock = Mutex.new
|
83
|
+
@shutdown_lock
|
69
84
|
end
|
70
85
|
|
71
86
|
def self.initialize_store
|
72
87
|
return if store
|
73
88
|
begin
|
74
|
-
name = Rpush.config.
|
89
|
+
name = Rpush.config.client.to_s
|
75
90
|
require "rpush/daemon/store/#{name}"
|
76
91
|
self.store = Rpush::Daemon::Store.const_get(name.camelcase).new
|
77
92
|
rescue StandardError, LoadError => e
|
78
|
-
Rpush.logger.error("Failed to load '#{Rpush.config.
|
93
|
+
Rpush.logger.error("Failed to load '#{Rpush.config.client}' storage backend.")
|
79
94
|
Rpush.logger.error(e)
|
95
|
+
exit 1
|
80
96
|
end
|
81
97
|
end
|
82
98
|
|
83
99
|
protected
|
84
100
|
|
85
101
|
def self.daemonize?
|
86
|
-
!(Rpush.config.foreground || Rpush.config.embedded || Rpush.jruby?)
|
87
|
-
end
|
88
|
-
|
89
|
-
def self.trap_signals?
|
90
|
-
!Rpush.config.embedded
|
91
|
-
end
|
92
|
-
|
93
|
-
def self.setup_signal_traps
|
94
|
-
@shutting_down = false
|
95
|
-
|
96
|
-
Signal.trap('SIGHUP') { AppRunner.sync }
|
97
|
-
Signal.trap('SIGUSR2') { AppRunner.debug }
|
98
|
-
|
99
|
-
['SIGINT', 'SIGTERM'].each do |signal|
|
100
|
-
Signal.trap(signal) { handle_shutdown_signal }
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def self.handle_shutdown_signal
|
105
|
-
exit 1 if @shutting_down
|
106
|
-
@shutting_down = true
|
107
|
-
shutdown
|
102
|
+
!(Rpush.config.push || Rpush.config.foreground || Rpush.config.embedded || Rpush.jruby?)
|
108
103
|
end
|
109
104
|
|
110
105
|
def self.write_pid_file
|
111
|
-
|
106
|
+
unless Rpush.config.pid_file.blank?
|
112
107
|
begin
|
113
108
|
File.open(Rpush.config.pid_file, 'w') { |f| f.puts Process.pid }
|
114
109
|
rescue SystemCallError => e
|
@@ -119,22 +114,7 @@ module Rpush
|
|
119
114
|
|
120
115
|
def self.delete_pid_file
|
121
116
|
pid_file = Rpush.config.pid_file
|
122
|
-
File.delete(pid_file) if !pid_file.blank? && File.
|
123
|
-
end
|
124
|
-
|
125
|
-
# :nocov:
|
126
|
-
def self.daemonize
|
127
|
-
if RUBY_VERSION < "1.9"
|
128
|
-
exit if fork
|
129
|
-
Process.setsid
|
130
|
-
exit if fork
|
131
|
-
Dir.chdir "/"
|
132
|
-
STDIN.reopen "/dev/null"
|
133
|
-
STDOUT.reopen "/dev/null", "a"
|
134
|
-
STDERR.reopen "/dev/null", "a"
|
135
|
-
else
|
136
|
-
Process.daemon
|
137
|
-
end
|
117
|
+
File.delete(pid_file) if !pid_file.blank? && File.exist?(pid_file)
|
138
118
|
end
|
139
119
|
end
|
140
120
|
end
|
data/lib/rpush/deprecatable.rb
CHANGED
@@ -5,16 +5,17 @@ module Rpush
|
|
5
5
|
end
|
6
6
|
|
7
7
|
module ClassMethods
|
8
|
-
def deprecated(method_name, version, msg=nil)
|
8
|
+
def deprecated(method_name, version, msg = nil)
|
9
|
+
method_name_as_var = method_name.to_s.tr('=', '_setter_')
|
9
10
|
instance_eval do
|
10
|
-
alias_method "#{
|
11
|
+
alias_method "#{method_name_as_var}_without_warning", method_name
|
11
12
|
end
|
12
13
|
warning = "#{method_name} is deprecated and will be removed from Rpush #{version}."
|
13
14
|
warning << " #{msg}" if msg
|
14
15
|
class_eval(<<-RUBY, __FILE__, __LINE__)
|
15
16
|
def #{method_name}(*args, &blk)
|
16
17
|
Rpush::Deprecation.warn(#{warning.inspect})
|
17
|
-
#{
|
18
|
+
#{method_name_as_var}_without_warning(*args, &blk)
|
18
19
|
end
|
19
20
|
RUBY
|
20
21
|
end
|
data/lib/rpush/deprecation.rb
CHANGED
@@ -1,13 +1,11 @@
|
|
1
1
|
module Rpush
|
2
2
|
class Deprecation
|
3
3
|
def self.muted
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
Thread.current[:rpush_mute_deprecations] = orig_val
|
10
|
-
end
|
4
|
+
orig_val = Thread.current[:rpush_mute_deprecations]
|
5
|
+
Thread.current[:rpush_mute_deprecations] = true
|
6
|
+
yield
|
7
|
+
ensure
|
8
|
+
Thread.current[:rpush_mute_deprecations] = orig_val
|
11
9
|
end
|
12
10
|
|
13
11
|
def self.muted?
|
@@ -15,9 +13,8 @@ module Rpush
|
|
15
13
|
end
|
16
14
|
|
17
15
|
def self.warn(msg)
|
18
|
-
|
19
|
-
|
20
|
-
end
|
16
|
+
return if Rpush::Deprecation.muted?
|
17
|
+
STDERR.puts "DEPRECATION WARNING: #{msg}"
|
21
18
|
end
|
22
19
|
end
|
23
20
|
end
|
data/lib/rpush/embed.rb
CHANGED
@@ -2,23 +2,28 @@ module Rpush
|
|
2
2
|
def self.embed(options = {})
|
3
3
|
Rpush.require_for_daemon
|
4
4
|
|
5
|
+
if @embed_thread
|
6
|
+
STDERR.puts 'Rpush.embed can only be run once inside this process.'
|
7
|
+
end
|
8
|
+
|
5
9
|
config = Rpush::ConfigurationWithoutDefaults.new
|
6
10
|
options.each { |k, v| config.send("#{k}=", v) }
|
7
11
|
config.embedded = true
|
8
12
|
Rpush.config.update(config)
|
9
|
-
Rpush::Daemon.start
|
10
|
-
|
11
13
|
Kernel.at_exit { shutdown }
|
14
|
+
@embed_thread = Thread.new { Rpush::Daemon.start }
|
12
15
|
end
|
13
16
|
|
14
17
|
def self.shutdown
|
15
18
|
return unless Rpush.config.embedded
|
16
19
|
Rpush::Daemon.shutdown
|
20
|
+
@embed_thread.join if @embed_thread
|
21
|
+
@embed_thread = nil
|
17
22
|
end
|
18
23
|
|
19
24
|
def self.sync
|
20
25
|
return unless Rpush.config.embedded
|
21
|
-
Rpush::Daemon::
|
26
|
+
Rpush::Daemon::Synchronizer.sync
|
22
27
|
end
|
23
28
|
|
24
29
|
def self.debug
|
data/lib/rpush/logger.rb
CHANGED
@@ -1,19 +1,15 @@
|
|
1
1
|
module Rpush
|
2
2
|
class Logger
|
3
|
-
def initialize
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
@logger = nil
|
14
|
-
error(e)
|
15
|
-
error('Logging disabled.')
|
16
|
-
end
|
3
|
+
def initialize
|
4
|
+
log_dir = File.join(Rpush.config.log_dir, 'log')
|
5
|
+
FileUtils.mkdir_p(log_dir)
|
6
|
+
log = File.open(File.join(log_dir, 'rpush.log'), 'a')
|
7
|
+
log.sync = true
|
8
|
+
setup_logger(log)
|
9
|
+
rescue Errno::ENOENT, Errno::EPERM => e
|
10
|
+
@logger = nil
|
11
|
+
error(e)
|
12
|
+
error('Logging disabled.')
|
17
13
|
end
|
18
14
|
|
19
15
|
def info(msg)
|
@@ -53,7 +49,7 @@ module Rpush
|
|
53
49
|
|
54
50
|
if io == STDERR
|
55
51
|
io.puts formatted_msg
|
56
|
-
elsif
|
52
|
+
elsif Rpush.config.foreground
|
57
53
|
io.puts formatted_msg
|
58
54
|
end
|
59
55
|
|