rpush_extended 3.2.5
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 +7 -0
- data/CHANGELOG.md +365 -0
- data/LICENSE +7 -0
- data/README.md +393 -0
- data/bin/rpush +4 -0
- data/lib/generators/rpush_config_generator.rb +7 -0
- data/lib/generators/rpush_migration_generator.rb +66 -0
- data/lib/generators/templates/add_adm.rb +23 -0
- data/lib/generators/templates/add_alert_is_json_to_rapns_notifications.rb +9 -0
- data/lib/generators/templates/add_app_to_rapns.rb +11 -0
- data/lib/generators/templates/add_fail_after_to_rpush_notifications.rb +9 -0
- data/lib/generators/templates/add_gcm.rb +117 -0
- data/lib/generators/templates/add_rpush.rb +402 -0
- data/lib/generators/templates/add_wpns.rb +16 -0
- data/lib/generators/templates/create_rapns_apps.rb +16 -0
- data/lib/generators/templates/create_rapns_feedback.rb +25 -0
- data/lib/generators/templates/create_rapns_notifications.rb +36 -0
- data/lib/generators/templates/rename_rapns_to_rpush.rb +87 -0
- data/lib/generators/templates/rpush.rb +135 -0
- data/lib/generators/templates/rpush_2_0_0_updates.rb +79 -0
- data/lib/generators/templates/rpush_2_1_0_updates.rb +11 -0
- data/lib/generators/templates/rpush_2_6_0_updates.rb +10 -0
- data/lib/generators/templates/rpush_2_7_0_updates.rb +12 -0
- data/lib/generators/templates/rpush_3_0_0_updates.rb +11 -0
- data/lib/generators/templates/rpush_3_0_1_updates.rb +13 -0
- data/lib/generators/templates/rpush_3_1_0_add_pushy.rb +9 -0
- data/lib/generators/templates/rpush_3_1_1_updates.rb +15 -0
- data/lib/generators/templates/rpush_3_2_0_add_apns_p8.rb +15 -0
- data/lib/generators/templates/rpush_3_2_4_updates.rb +9 -0
- data/lib/generators/templates/rpush_3_3_0_updates.rb +9 -0
- data/lib/generators/templates/rpush_3_3_1_updates.rb +11 -0
- data/lib/rpush/apns_feedback.rb +17 -0
- data/lib/rpush/cli.rb +213 -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 +104 -0
- data/lib/rpush/client/active_model/apns2/app.rb +15 -0
- data/lib/rpush/client/active_model/apns2/notification.rb +9 -0
- data/lib/rpush/client/active_model/apnsp8/app.rb +23 -0
- data/lib/rpush/client/active_model/apnsp8/notification.rb +9 -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 +59 -0
- data/lib/rpush/client/active_model/notification.rb +22 -0
- data/lib/rpush/client/active_model/payload_data_size_validator.rb +13 -0
- data/lib/rpush/client/active_model/pushy/app.rb +20 -0
- data/lib/rpush/client/active_model/pushy/notification.rb +31 -0
- data/lib/rpush/client/active_model/pushy/time_to_live_validator.rb +14 -0
- data/lib/rpush/client/active_model/registration_ids_count_validator.rb +13 -0
- data/lib/rpush/client/active_model/wns/app.rb +23 -0
- data/lib/rpush/client/active_model/wns/notification.rb +32 -0
- data/lib/rpush/client/active_model/wpns/app.rb +13 -0
- data/lib/rpush/client/active_model/wpns/notification.rb +28 -0
- data/lib/rpush/client/active_model.rb +34 -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 +18 -0
- data/lib/rpush/client/active_record/apns/notification.rb +40 -0
- data/lib/rpush/client/active_record/apns2/app.rb +11 -0
- data/lib/rpush/client/active_record/apns2/notification.rb +10 -0
- data/lib/rpush/client/active_record/apnsp8/app.rb +11 -0
- data/lib/rpush/client/active_record/apnsp8/notification.rb +10 -0
- data/lib/rpush/client/active_record/app.rb +13 -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 +42 -0
- data/lib/rpush/client/active_record/pushy/app.rb +11 -0
- data/lib/rpush/client/active_record/pushy/notification.rb +11 -0
- data/lib/rpush/client/active_record/wns/app.rb +11 -0
- data/lib/rpush/client/active_record/wns/badge_notification.rb +15 -0
- data/lib/rpush/client/active_record/wns/notification.rb +11 -0
- data/lib/rpush/client/active_record/wns/raw_notification.rb +13 -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 +33 -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/apns2/app.rb +11 -0
- data/lib/rpush/client/redis/apns2/notification.rb +11 -0
- data/lib/rpush/client/redis/apnsp8/app.rb +11 -0
- data/lib/rpush/client/redis/apnsp8/notification.rb +11 -0
- data/lib/rpush/client/redis/app.rb +29 -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 +74 -0
- data/lib/rpush/client/redis/pushy/app.rb +16 -0
- data/lib/rpush/client/redis/pushy/notification.rb +18 -0
- data/lib/rpush/client/redis/wns/app.rb +14 -0
- data/lib/rpush/client/redis/wns/badge_notification.rb +15 -0
- data/lib/rpush/client/redis/wns/notification.rb +11 -0
- data/lib/rpush/client/redis/wns/raw_notification.rb +11 -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 +56 -0
- data/lib/rpush/configuration.rb +115 -0
- data/lib/rpush/daemon/adm/delivery.rb +226 -0
- data/lib/rpush/daemon/adm.rb +9 -0
- data/lib/rpush/daemon/apns/delivery.rb +43 -0
- data/lib/rpush/daemon/apns/feedback_receiver.rb +90 -0
- data/lib/rpush/daemon/apns.rb +17 -0
- data/lib/rpush/daemon/apns2/delivery.rb +127 -0
- data/lib/rpush/daemon/apns2.rb +10 -0
- data/lib/rpush/daemon/apnsp8/delivery.rb +166 -0
- data/lib/rpush/daemon/apnsp8/token.rb +43 -0
- data/lib/rpush/daemon/apnsp8.rb +10 -0
- data/lib/rpush/daemon/app_runner.rb +190 -0
- data/lib/rpush/daemon/batch.rb +138 -0
- data/lib/rpush/daemon/constants.rb +59 -0
- data/lib/rpush/daemon/delivery.rb +46 -0
- data/lib/rpush/daemon/delivery_error.rb +27 -0
- data/lib/rpush/daemon/dispatcher/apns_http2.rb +51 -0
- data/lib/rpush/daemon/dispatcher/apns_tcp.rb +152 -0
- data/lib/rpush/daemon/dispatcher/apnsp8_http2.rb +33 -0
- data/lib/rpush/daemon/dispatcher/http.rb +21 -0
- data/lib/rpush/daemon/dispatcher/tcp.rb +22 -0
- data/lib/rpush/daemon/dispatcher_loop.rb +73 -0
- data/lib/rpush/daemon/errors.rb +18 -0
- data/lib/rpush/daemon/feeder.rb +69 -0
- data/lib/rpush/daemon/gcm/delivery.rb +241 -0
- data/lib/rpush/daemon/gcm.rb +9 -0
- data/lib/rpush/daemon/interruptible_sleep.rb +24 -0
- data/lib/rpush/daemon/loggable.rb +33 -0
- data/lib/rpush/daemon/proc_title.rb +17 -0
- data/lib/rpush/daemon/pushy/delivery.rb +90 -0
- data/lib/rpush/daemon/pushy.rb +9 -0
- data/lib/rpush/daemon/queue_payload.rb +12 -0
- data/lib/rpush/daemon/retry_header_parser.rb +23 -0
- data/lib/rpush/daemon/retryable_error.rb +22 -0
- data/lib/rpush/daemon/ring_buffer.rb +16 -0
- data/lib/rpush/daemon/rpc/client.rb +27 -0
- data/lib/rpush/daemon/rpc/server.rb +82 -0
- data/lib/rpush/daemon/rpc.rb +9 -0
- data/lib/rpush/daemon/service_config_methods.rb +51 -0
- data/lib/rpush/daemon/signal_handler.rb +75 -0
- data/lib/rpush/daemon/store/active_record/reconnectable.rb +80 -0
- data/lib/rpush/daemon/store/active_record.rb +214 -0
- data/lib/rpush/daemon/store/interface.rb +20 -0
- data/lib/rpush/daemon/store/redis.rb +166 -0
- data/lib/rpush/daemon/string_helpers.rb +15 -0
- data/lib/rpush/daemon/synchronizer.rb +62 -0
- data/lib/rpush/daemon/tcp_connection.rb +190 -0
- data/lib/rpush/daemon/wns/badge_request.rb +32 -0
- data/lib/rpush/daemon/wns/delivery.rb +178 -0
- data/lib/rpush/daemon/wns/post_request.rb +33 -0
- data/lib/rpush/daemon/wns/raw_request.rb +22 -0
- data/lib/rpush/daemon/wns/toast_request.rb +54 -0
- data/lib/rpush/daemon/wns.rb +9 -0
- data/lib/rpush/daemon/wpns/delivery.rb +132 -0
- data/lib/rpush/daemon/wpns.rb +9 -0
- data/lib/rpush/daemon.rb +179 -0
- data/lib/rpush/deprecatable.rb +24 -0
- data/lib/rpush/deprecation.rb +26 -0
- data/lib/rpush/embed.rb +41 -0
- data/lib/rpush/logger.rb +92 -0
- data/lib/rpush/multi_json_helper.rb +16 -0
- data/lib/rpush/plugin.rb +44 -0
- data/lib/rpush/push.rb +11 -0
- data/lib/rpush/reflectable.rb +13 -0
- data/lib/rpush/reflection_collection.rb +44 -0
- data/lib/rpush/reflection_public_methods.rb +11 -0
- data/lib/rpush/version.rb +14 -0
- data/lib/rpush.rb +43 -0
- data/lib/tasks/quality.rake +35 -0
- data/lib/tasks/test.rake +69 -0
- data/spec/.rubocop.yml +4 -0
- data/spec/functional/adm_spec.rb +50 -0
- data/spec/functional/apns2_spec.rb +232 -0
- data/spec/functional/apns_spec.rb +162 -0
- data/spec/functional/cli_spec.rb +36 -0
- data/spec/functional/embed_spec.rb +49 -0
- data/spec/functional/gcm_spec.rb +46 -0
- data/spec/functional/new_app_spec.rb +44 -0
- data/spec/functional/pushy_spec.rb +22 -0
- data/spec/functional/retry_spec.rb +42 -0
- data/spec/functional/synchronization_spec.rb +97 -0
- data/spec/functional/wpns_spec.rb +71 -0
- data/spec/functional_spec_helper.rb +32 -0
- data/spec/spec_helper.rb +69 -0
- data/spec/support/active_record_setup.rb +73 -0
- data/spec/support/cert_with_password.pem +90 -0
- data/spec/support/cert_without_password.pem +59 -0
- data/spec/support/config/database.yml +44 -0
- data/spec/support/simplecov_helper.rb +24 -0
- data/spec/support/simplecov_quality_formatter.rb +12 -0
- data/spec/tmp/.gitkeep +0 -0
- data/spec/unit/apns_feedback_spec.rb +28 -0
- data/spec/unit/client/active_record/adm/app_spec.rb +58 -0
- data/spec/unit/client/active_record/adm/notification_spec.rb +43 -0
- 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 +324 -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/client/active_record/gcm/notification_spec.rb +67 -0
- data/spec/unit/client/active_record/notification_spec.rb +21 -0
- data/spec/unit/client/active_record/pushy/app_spec.rb +17 -0
- data/spec/unit/client/active_record/pushy/notification_spec.rb +65 -0
- data/spec/unit/client/active_record/wns/badge_notification_spec.rb +15 -0
- data/spec/unit/client/active_record/wns/raw_notification_spec.rb +26 -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 +46 -0
- data/spec/unit/daemon/adm/delivery_spec.rb +253 -0
- data/spec/unit/daemon/apns/certificate_expired_error_spec.rb +11 -0
- data/spec/unit/daemon/apns/delivery_spec.rb +108 -0
- data/spec/unit/daemon/apns/feedback_receiver_spec.rb +119 -0
- data/spec/unit/daemon/app_runner_spec.rb +188 -0
- data/spec/unit/daemon/batch_spec.rb +169 -0
- data/spec/unit/daemon/delivery_error_spec.rb +13 -0
- data/spec/unit/daemon/delivery_spec.rb +51 -0
- data/spec/unit/daemon/dispatcher/http_spec.rb +34 -0
- data/spec/unit/daemon/dispatcher/tcp_spec.rb +32 -0
- data/spec/unit/daemon/dispatcher_loop_spec.rb +53 -0
- data/spec/unit/daemon/feeder_spec.rb +96 -0
- data/spec/unit/daemon/gcm/delivery_spec.rb +387 -0
- data/spec/unit/daemon/proc_title_spec.rb +11 -0
- data/spec/unit/daemon/pushy/delivery_spec.rb +159 -0
- data/spec/unit/daemon/retryable_error_spec.rb +14 -0
- data/spec/unit/daemon/service_config_methods_spec.rb +36 -0
- data/spec/unit/daemon/signal_handler_spec.rb +99 -0
- data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +165 -0
- data/spec/unit/daemon/store/active_record_spec.rb +357 -0
- data/spec/unit/daemon/store/redis_spec.rb +365 -0
- data/spec/unit/daemon/tcp_connection_spec.rb +292 -0
- data/spec/unit/daemon/wns/delivery_spec.rb +176 -0
- data/spec/unit/daemon/wns/post_request_spec.rb +117 -0
- data/spec/unit/daemon/wpns/delivery_spec.rb +167 -0
- data/spec/unit/daemon_spec.rb +138 -0
- data/spec/unit/deprecatable_spec.rb +32 -0
- data/spec/unit/deprecation_spec.rb +15 -0
- data/spec/unit/embed_spec.rb +47 -0
- data/spec/unit/logger_spec.rb +127 -0
- data/spec/unit/notification_shared.rb +53 -0
- data/spec/unit/plugin_spec.rb +36 -0
- data/spec/unit/push_spec.rb +34 -0
- data/spec/unit/reflectable_spec.rb +27 -0
- data/spec/unit/reflection_collection_spec.rb +26 -0
- data/spec/unit/rpush_spec.rb +8 -0
- data/spec/unit_spec_helper.rb +26 -0
- metadata +709 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Rpush
|
|
2
|
+
module Daemon
|
|
3
|
+
class InterruptibleSleep
|
|
4
|
+
def sleep(duration)
|
|
5
|
+
@thread = Thread.new { Kernel.sleep duration }
|
|
6
|
+
Thread.pass
|
|
7
|
+
|
|
8
|
+
begin
|
|
9
|
+
@thread.join
|
|
10
|
+
rescue StandardError # rubocop:disable Lint/HandleExceptions
|
|
11
|
+
ensure
|
|
12
|
+
@thread = nil
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def stop
|
|
17
|
+
@thread.kill if @thread
|
|
18
|
+
rescue StandardError # rubocop:disable Lint/HandleExceptions
|
|
19
|
+
ensure
|
|
20
|
+
@thread = nil
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Rpush
|
|
2
|
+
module Daemon
|
|
3
|
+
module Loggable
|
|
4
|
+
def log_debug(msg)
|
|
5
|
+
Rpush.logger.debug(app_prefix(msg))
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def log_info(msg)
|
|
9
|
+
Rpush.logger.info(app_prefix(msg))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def log_warn(msg)
|
|
13
|
+
Rpush.logger.warn(app_prefix(msg))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def log_error(e)
|
|
17
|
+
if e.is_a?(Exception)
|
|
18
|
+
Rpush.logger.error(e)
|
|
19
|
+
else
|
|
20
|
+
Rpush.logger.error(app_prefix(e))
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def app_prefix(msg)
|
|
27
|
+
app = instance_variable_get('@app')
|
|
28
|
+
msg = "[#{app.name}] #{msg}" if app
|
|
29
|
+
msg
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Rpush
|
|
2
|
+
module Daemon
|
|
3
|
+
class ProcTitle
|
|
4
|
+
def self.update
|
|
5
|
+
return if Rpush.config.embedded || Rpush.config.push
|
|
6
|
+
Process.respond_to?(:setproctitle) ? Process.setproctitle(proc_title) : $0 = proc_title
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.proc_title
|
|
10
|
+
total_dispatchers = AppRunner.total_dispatchers
|
|
11
|
+
dispatchers_str = total_dispatchers == 1 ? 'dispatcher' : 'dispatchers'
|
|
12
|
+
total_queued = AppRunner.total_queued
|
|
13
|
+
format("rpush | %d queued | %d %s", total_queued, total_dispatchers, dispatchers_str)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
module Rpush
|
|
2
|
+
module Daemon
|
|
3
|
+
module Pushy
|
|
4
|
+
class Delivery < Rpush::Daemon::Delivery
|
|
5
|
+
include MultiJsonHelper
|
|
6
|
+
|
|
7
|
+
attr_reader :http, :notification, :batch, :pushy_uri
|
|
8
|
+
|
|
9
|
+
def initialize(app, http, notification, batch)
|
|
10
|
+
@http = http
|
|
11
|
+
@notification = notification
|
|
12
|
+
@batch = batch
|
|
13
|
+
@pushy_uri = URI.parse("https://api.pushy.me/push?api_key=#{app.api_key}")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def perform
|
|
17
|
+
response = send_request
|
|
18
|
+
process_response(response)
|
|
19
|
+
rescue SocketError => error
|
|
20
|
+
mark_retryable(notification, Time.now + 10.seconds, error)
|
|
21
|
+
raise
|
|
22
|
+
rescue StandardError => error
|
|
23
|
+
mark_failed(error)
|
|
24
|
+
raise
|
|
25
|
+
ensure
|
|
26
|
+
batch.notification_processed
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def send_request
|
|
32
|
+
post = Net::HTTP::Post.new(pushy_uri)
|
|
33
|
+
post.content_type = 'application/json'
|
|
34
|
+
post.body = notification.to_json
|
|
35
|
+
http.request(pushy_uri, post)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def process_response(response)
|
|
39
|
+
case response.code.to_i
|
|
40
|
+
when 200
|
|
41
|
+
process_delivery(response)
|
|
42
|
+
when 429, 500, 502, 503, 504
|
|
43
|
+
retry_delivery(response)
|
|
44
|
+
else
|
|
45
|
+
fail_delivery(response)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def process_delivery(response)
|
|
50
|
+
mark_delivered
|
|
51
|
+
body = multi_json_load(response.body)
|
|
52
|
+
external_device_id = body['id']
|
|
53
|
+
notification.external_device_id = external_device_id
|
|
54
|
+
Rpush::Daemon.store.update_notification(notification)
|
|
55
|
+
log_info("#{notification.id} received an external id=#{external_device_id}")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def retry_delivery(response)
|
|
59
|
+
time = deliver_after_header(response)
|
|
60
|
+
if time
|
|
61
|
+
mark_retryable(notification, time)
|
|
62
|
+
else
|
|
63
|
+
mark_retryable_exponential(notification)
|
|
64
|
+
end
|
|
65
|
+
log_warn("Pushy responded with a #{response.code} error. #{retry_message}")
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def deliver_after_header(response)
|
|
69
|
+
Rpush::Daemon::RetryHeaderParser.parse(response.header['retry-after'])
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def retry_message
|
|
73
|
+
deliver_after = notification.deliver_after.strftime('%Y-%m-%d %H:%M:%S')
|
|
74
|
+
"Notification #{notification.id} will be retried after #{deliver_after} (retry #{notification.retries})."
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def fail_delivery(response)
|
|
78
|
+
fail_message = fail_message(response)
|
|
79
|
+
log_error("#{notification.id} failed: #{fail_message}")
|
|
80
|
+
fail Rpush::DeliveryError.new(response.code.to_i, notification.id, fail_message)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def fail_message(response)
|
|
84
|
+
body = multi_json_load(response.body)
|
|
85
|
+
body['error'] || Rpush::Daemon::HTTP_STATUS_CODES[response.code.to_i]
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Rpush
|
|
2
|
+
module Daemon
|
|
3
|
+
class RetryHeaderParser
|
|
4
|
+
def self.parse(header)
|
|
5
|
+
new(header).parse
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def initialize(header)
|
|
9
|
+
@header = header
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def parse
|
|
13
|
+
return unless @header
|
|
14
|
+
|
|
15
|
+
if @header.to_s =~ /^[0-9]+$/
|
|
16
|
+
Time.now + @header.to_i
|
|
17
|
+
else
|
|
18
|
+
Time.httpdate(@header)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Rpush
|
|
2
|
+
class RetryableError < StandardError
|
|
3
|
+
attr_reader :code, :description, :response
|
|
4
|
+
|
|
5
|
+
def initialize(code, notification_id, description, response)
|
|
6
|
+
@code = code
|
|
7
|
+
@notification_id = notification_id
|
|
8
|
+
@description = description
|
|
9
|
+
@response = response
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_s
|
|
13
|
+
message
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def message
|
|
17
|
+
"Retryable error for #{@notification_id}, received error #{@code} (#{@description}) - retry after #{@response.header['retry-after']}"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class RateLimitError < RetryableError; end
|
|
22
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Rpush
|
|
2
|
+
module Daemon
|
|
3
|
+
module Rpc
|
|
4
|
+
class Client
|
|
5
|
+
def initialize(pid)
|
|
6
|
+
@socket = UNIXSocket.open(Rpc.socket_path(pid))
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def status
|
|
10
|
+
call(:status)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def close
|
|
14
|
+
@socket.close
|
|
15
|
+
rescue StandardError # rubocop:disable Lint/HandleExceptions
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def call(cmd, args = {})
|
|
21
|
+
@socket.puts(JSON.dump([cmd, args]))
|
|
22
|
+
JSON.parse(@socket.gets)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
require 'socket'
|
|
2
|
+
require 'singleton'
|
|
3
|
+
|
|
4
|
+
module Rpush
|
|
5
|
+
module Daemon
|
|
6
|
+
module Rpc
|
|
7
|
+
class Server
|
|
8
|
+
include Singleton
|
|
9
|
+
include Loggable
|
|
10
|
+
include Reflectable
|
|
11
|
+
|
|
12
|
+
def self.start
|
|
13
|
+
instance.start
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.stop
|
|
17
|
+
instance.stop
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def start
|
|
21
|
+
@stop = false
|
|
22
|
+
|
|
23
|
+
@thread = Thread.new(UNIXServer.open(Rpc.socket_path)) do |server|
|
|
24
|
+
begin
|
|
25
|
+
loop do
|
|
26
|
+
socket = server.accept
|
|
27
|
+
break if @stop
|
|
28
|
+
read_loop(socket)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
server.close
|
|
32
|
+
rescue StandardError => e
|
|
33
|
+
log_error(e)
|
|
34
|
+
ensure
|
|
35
|
+
File.unlink(Rpc.socket_path) if File.exist?(Rpc.socket_path)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def stop
|
|
41
|
+
@stop = true
|
|
42
|
+
UNIXSocket.new(Rpc.socket_path)
|
|
43
|
+
@thread.join if @thread
|
|
44
|
+
rescue StandardError => e
|
|
45
|
+
log_error(e)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def read_loop(socket)
|
|
51
|
+
loop do
|
|
52
|
+
line = socket.gets
|
|
53
|
+
break unless line
|
|
54
|
+
|
|
55
|
+
begin
|
|
56
|
+
cmd, args = JSON.load(line)
|
|
57
|
+
log_debug("[rpc:server] #{cmd.to_sym.inspect}, args: #{args.inspect}")
|
|
58
|
+
response = process(cmd, args)
|
|
59
|
+
socket.puts(JSON.dump(response))
|
|
60
|
+
rescue StandardError => e
|
|
61
|
+
log_error(e)
|
|
62
|
+
reflect(:error, e)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
socket.close
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def process(cmd, args) # rubocop:disable Lint/UnusedMethodArgument
|
|
70
|
+
case cmd
|
|
71
|
+
when 'status'
|
|
72
|
+
status
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def status
|
|
77
|
+
Rpush::Daemon::AppRunner.status
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module Rpush
|
|
2
|
+
module Daemon
|
|
3
|
+
module ServiceConfigMethods
|
|
4
|
+
DISPATCHERS = {
|
|
5
|
+
http: Rpush::Daemon::Dispatcher::Http,
|
|
6
|
+
tcp: Rpush::Daemon::Dispatcher::Tcp,
|
|
7
|
+
apns_tcp: Rpush::Daemon::Dispatcher::ApnsTcp,
|
|
8
|
+
apns_http2: Rpush::Daemon::Dispatcher::ApnsHttp2,
|
|
9
|
+
apnsp8_http2: Rpush::Daemon::Dispatcher::Apnsp8Http2
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
def batch_deliveries(value = nil)
|
|
13
|
+
return batch_deliveries? if value.nil?
|
|
14
|
+
@batch_deliveries = value
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def batch_deliveries?
|
|
18
|
+
@batch_deliveries == true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def dispatcher(name = nil, options = {})
|
|
22
|
+
@dispatcher_name = name
|
|
23
|
+
@dispatcher_options = options
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def dispatcher_class
|
|
27
|
+
DISPATCHERS[@dispatcher_name] || (fail NotImplementedError)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def delivery_class
|
|
31
|
+
const_get('Delivery')
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def new_dispatcher(app)
|
|
35
|
+
dispatcher_class.new(app, delivery_class, @dispatcher_options)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def loops(classes, options = {})
|
|
39
|
+
classes = Array[*classes]
|
|
40
|
+
@loops = classes.map { |cls| [cls, options] }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def loop_instances(app)
|
|
44
|
+
(@loops || []).map do |cls, options|
|
|
45
|
+
next unless options.key?(:if) ? options[:if].call : true
|
|
46
|
+
cls.new(app)
|
|
47
|
+
end.compact
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
module Rpush
|
|
2
|
+
module Daemon
|
|
3
|
+
class SignalHandler
|
|
4
|
+
extend Loggable
|
|
5
|
+
|
|
6
|
+
class << self
|
|
7
|
+
attr_reader :thread
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.start
|
|
11
|
+
return unless trap_signals?
|
|
12
|
+
|
|
13
|
+
read_io, @write_io = IO.pipe
|
|
14
|
+
start_handler(read_io)
|
|
15
|
+
%w(INT TERM HUP USR2).each do |signal|
|
|
16
|
+
Signal.trap(signal) { @write_io.puts(signal) }
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.stop
|
|
21
|
+
@write_io.puts('break') if @write_io
|
|
22
|
+
@thread.join if @thread
|
|
23
|
+
rescue StandardError => e
|
|
24
|
+
log_error(e)
|
|
25
|
+
reflect(:error, e)
|
|
26
|
+
ensure
|
|
27
|
+
@thread = nil
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.start_handler(read_io)
|
|
31
|
+
@thread = Thread.new do
|
|
32
|
+
while readable_io = IO.select([read_io]) # rubocop:disable AssignmentInCondition
|
|
33
|
+
signal = readable_io.first[0].gets.strip
|
|
34
|
+
|
|
35
|
+
begin
|
|
36
|
+
case signal
|
|
37
|
+
when 'HUP'
|
|
38
|
+
handle_hup
|
|
39
|
+
when 'USR2'
|
|
40
|
+
handle_usr2
|
|
41
|
+
when 'INT', 'TERM'
|
|
42
|
+
Thread.new { Rpush::Daemon.shutdown }
|
|
43
|
+
break
|
|
44
|
+
when 'break'
|
|
45
|
+
break
|
|
46
|
+
else
|
|
47
|
+
Rpush.logger.error("Unhandled signal: #{signal}")
|
|
48
|
+
end
|
|
49
|
+
rescue StandardError => e
|
|
50
|
+
Rpush.logger.error("Error raised when handling signal '#{signal}'")
|
|
51
|
+
Rpush.logger.error(e)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def self.handle_hup
|
|
58
|
+
Rpush.logger.reopen
|
|
59
|
+
Rpush.logger.info('Received HUP signal.')
|
|
60
|
+
Rpush::Daemon.store.reopen_log
|
|
61
|
+
Synchronizer.sync
|
|
62
|
+
Feeder.wakeup
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def self.handle_usr2
|
|
66
|
+
Rpush.logger.info('Received USR2 signal.')
|
|
67
|
+
AppRunner.debug
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def self.trap_signals?
|
|
71
|
+
!Rpush.config.embedded
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
class PGError < StandardError; end unless defined?(PGError)
|
|
2
|
+
module PG
|
|
3
|
+
class Error < StandardError; end unless defined?(::PG::Error)
|
|
4
|
+
end
|
|
5
|
+
class Mysql; class Error < StandardError; end; end unless defined?(Mysql)
|
|
6
|
+
module Mysql2; class Error < StandardError; end; end unless defined?(Mysql2)
|
|
7
|
+
module ActiveRecord
|
|
8
|
+
class JDBCError < StandardError; end unless defined?(::ActiveRecord::JDBCError)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# :nocov:
|
|
12
|
+
unless defined?(::SQLite3::Exception)
|
|
13
|
+
module SQLite3
|
|
14
|
+
class Exception < StandardError; end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
module Rpush
|
|
19
|
+
module Daemon
|
|
20
|
+
module Store
|
|
21
|
+
class ActiveRecord
|
|
22
|
+
module Reconnectable
|
|
23
|
+
ADAPTER_ERRORS = [
|
|
24
|
+
::ActiveRecord::ConnectionNotEstablished,
|
|
25
|
+
::ActiveRecord::ConnectionTimeoutError,
|
|
26
|
+
::ActiveRecord::JDBCError,
|
|
27
|
+
::ActiveRecord::StatementInvalid,
|
|
28
|
+
Mysql::Error,
|
|
29
|
+
Mysql2::Error,
|
|
30
|
+
PG::Error,
|
|
31
|
+
PGError,
|
|
32
|
+
SQLite3::Exception
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
def with_database_reconnect_and_retry
|
|
36
|
+
::ActiveRecord::Base.connection_pool.with_connection do
|
|
37
|
+
yield
|
|
38
|
+
end
|
|
39
|
+
rescue *ADAPTER_ERRORS => e
|
|
40
|
+
Rpush.logger.error(e)
|
|
41
|
+
sleep_to_avoid_thrashing
|
|
42
|
+
database_connection_lost
|
|
43
|
+
retry
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def database_connection_lost
|
|
47
|
+
Rpush.logger.warn("Lost connection to database, reconnecting...")
|
|
48
|
+
attempts = 0
|
|
49
|
+
loop do
|
|
50
|
+
begin
|
|
51
|
+
Rpush.logger.warn("Attempt #{attempts += 1}")
|
|
52
|
+
reconnect_database
|
|
53
|
+
check_database_is_connected
|
|
54
|
+
break
|
|
55
|
+
rescue *ADAPTER_ERRORS => e
|
|
56
|
+
Rpush.logger.error(e)
|
|
57
|
+
sleep_to_avoid_thrashing
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
Rpush.logger.warn("Database reconnected")
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def reconnect_database
|
|
64
|
+
::ActiveRecord::Base.clear_all_connections!
|
|
65
|
+
::ActiveRecord::Base.establish_connection
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def check_database_is_connected
|
|
69
|
+
# Simply asking the adapter for the connection state is not sufficient.
|
|
70
|
+
Rpush::Client::ActiveRecord::Notification.count
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def sleep_to_avoid_thrashing
|
|
74
|
+
sleep 2
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|