rpush 1.0.0 → 2.0.0.beta1

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.
Files changed (193) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/README.md +12 -14
  4. data/bin/rpush +11 -2
  5. data/lib/generators/rpush_generator.rb +2 -0
  6. data/lib/generators/templates/add_adm.rb +5 -5
  7. data/lib/generators/templates/add_alert_is_json_to_rapns_notifications.rb +1 -1
  8. data/lib/generators/templates/add_app_to_rapns.rb +2 -2
  9. data/lib/generators/templates/add_fail_after_to_rpush_notifications.rb +1 -1
  10. data/lib/generators/templates/add_gcm.rb +32 -32
  11. data/lib/generators/templates/add_rpush.rb +67 -67
  12. data/lib/generators/templates/add_wpns.rb +2 -2
  13. data/lib/generators/templates/create_rapns_apps.rb +5 -5
  14. data/lib/generators/templates/create_rapns_feedback.rb +2 -2
  15. data/lib/generators/templates/create_rapns_notifications.rb +15 -15
  16. data/lib/generators/templates/rpush.rb +10 -7
  17. data/lib/generators/templates/rpush_2_0_0_updates.rb +23 -0
  18. data/lib/rpush.rb +4 -28
  19. data/lib/rpush/client/active_model.rb +21 -0
  20. data/lib/rpush/client/active_model/adm/app.rb +23 -0
  21. data/lib/rpush/client/active_model/adm/data_validator.rb +14 -0
  22. data/lib/rpush/client/active_model/adm/notification.rb +28 -0
  23. data/lib/rpush/client/active_model/apns/app.rb +37 -0
  24. data/lib/rpush/client/active_model/apns/binary_notification_validator.rb +16 -0
  25. data/lib/rpush/client/active_model/apns/device_token_format_validator.rb +14 -0
  26. data/lib/rpush/client/active_model/apns/notification.rb +90 -0
  27. data/lib/rpush/client/active_model/gcm/app.rb +19 -0
  28. data/lib/rpush/client/active_model/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +14 -0
  29. data/lib/rpush/client/active_model/gcm/notification.rb +31 -0
  30. data/lib/rpush/client/active_model/notification.rb +26 -0
  31. data/lib/rpush/client/active_model/payload_data_size_validator.rb +13 -0
  32. data/lib/rpush/client/active_model/registration_ids_count_validator.rb +13 -0
  33. data/lib/rpush/client/active_model/wpns/app.rb +13 -0
  34. data/lib/rpush/client/active_model/wpns/notification.rb +17 -0
  35. data/lib/rpush/client/active_record.rb +19 -0
  36. data/lib/rpush/client/active_record/adm/app.rb +11 -0
  37. data/lib/rpush/client/active_record/adm/notification.rb +11 -0
  38. data/lib/rpush/client/active_record/apns/app.rb +11 -0
  39. data/lib/rpush/client/active_record/apns/feedback.rb +20 -0
  40. data/lib/rpush/client/active_record/apns/notification.rb +46 -0
  41. data/lib/rpush/client/active_record/app.rb +17 -0
  42. data/lib/rpush/client/active_record/gcm/app.rb +11 -0
  43. data/lib/rpush/client/active_record/gcm/notification.rb +11 -0
  44. data/lib/rpush/client/active_record/notification.rb +38 -0
  45. data/lib/rpush/client/active_record/wpns/app.rb +11 -0
  46. data/lib/rpush/client/active_record/wpns/notification.rb +11 -0
  47. data/lib/rpush/client/redis.rb +35 -0
  48. data/lib/rpush/client/redis/adm/app.rb +14 -0
  49. data/lib/rpush/client/redis/adm/notification.rb +11 -0
  50. data/lib/rpush/client/redis/apns/app.rb +11 -0
  51. data/lib/rpush/client/redis/apns/feedback.rb +20 -0
  52. data/lib/rpush/client/redis/apns/notification.rb +11 -0
  53. data/lib/rpush/client/redis/app.rb +22 -0
  54. data/lib/rpush/client/redis/gcm/app.rb +11 -0
  55. data/lib/rpush/client/redis/gcm/notification.rb +11 -0
  56. data/lib/rpush/client/redis/notification.rb +68 -0
  57. data/lib/rpush/client/redis/wpns/app.rb +11 -0
  58. data/lib/rpush/client/redis/wpns/notification.rb +11 -0
  59. data/lib/rpush/configuration.rb +27 -6
  60. data/lib/rpush/daemon.rb +36 -56
  61. data/lib/rpush/daemon/adm/delivery.rb +50 -52
  62. data/lib/rpush/daemon/apns.rb +6 -5
  63. data/lib/rpush/daemon/apns/delivery.rb +20 -44
  64. data/lib/rpush/daemon/apns/feedback_receiver.rb +11 -8
  65. data/lib/rpush/daemon/app_runner.rb +67 -60
  66. data/lib/rpush/daemon/batch.rb +54 -40
  67. data/lib/rpush/daemon/delivery.rb +13 -3
  68. data/lib/rpush/daemon/delivery_error.rb +10 -2
  69. data/lib/rpush/daemon/dispatcher/apns_tcp.rb +106 -0
  70. data/lib/rpush/daemon/dispatcher/http.rb +3 -3
  71. data/lib/rpush/daemon/dispatcher/tcp.rb +3 -3
  72. data/lib/rpush/daemon/dispatcher_loop.rb +15 -6
  73. data/lib/rpush/daemon/errors.rb +18 -0
  74. data/lib/rpush/daemon/feeder.rb +28 -39
  75. data/lib/rpush/daemon/gcm/delivery.rb +19 -20
  76. data/lib/rpush/daemon/interruptible_sleep.rb +26 -45
  77. data/lib/rpush/daemon/loggable.rb +2 -4
  78. data/lib/rpush/daemon/proc_title.rb +16 -0
  79. data/lib/rpush/daemon/queue_payload.rb +12 -0
  80. data/lib/rpush/daemon/reflectable.rb +3 -5
  81. data/lib/rpush/daemon/retry_header_parser.rb +6 -6
  82. data/lib/rpush/daemon/ring_buffer.rb +16 -0
  83. data/lib/rpush/daemon/service_config_methods.rb +23 -7
  84. data/lib/rpush/daemon/signal_handler.rb +51 -0
  85. data/lib/rpush/daemon/store/active_record.rb +71 -38
  86. data/lib/rpush/daemon/store/active_record/reconnectable.rb +15 -15
  87. data/lib/rpush/daemon/store/interface.rb +19 -0
  88. data/lib/rpush/daemon/store/redis.rb +149 -0
  89. data/lib/rpush/daemon/tcp_connection.rb +6 -11
  90. data/lib/rpush/daemon/wpns/delivery.rb +21 -30
  91. data/lib/rpush/deprecatable.rb +4 -3
  92. data/lib/rpush/deprecation.rb +7 -10
  93. data/lib/rpush/embed.rb +7 -2
  94. data/lib/rpush/logger.rb +11 -15
  95. data/lib/rpush/push.rb +0 -1
  96. data/lib/rpush/reflection.rb +6 -12
  97. data/lib/rpush/version.rb +1 -1
  98. data/lib/tasks/quality.rake +34 -0
  99. data/spec/.rubocop.yml +4 -0
  100. data/spec/functional/adm_spec.rb +3 -6
  101. data/spec/functional/apns_spec.rb +118 -24
  102. data/spec/functional/embed_spec.rb +22 -20
  103. data/spec/functional/gcm_spec.rb +4 -7
  104. data/spec/functional/new_app_spec.rb +61 -0
  105. data/spec/functional/retry_spec.rb +46 -0
  106. data/spec/functional/wpns_spec.rb +3 -6
  107. data/spec/functional_spec_helper.rb +26 -0
  108. data/spec/integration/rpush_spec.rb +13 -0
  109. data/spec/integration/support/gcm_success_response.json +1 -0
  110. data/spec/spec_helper.rb +60 -0
  111. data/spec/support/active_record_setup.rb +48 -0
  112. data/{config → spec/support/config}/database.yml +0 -0
  113. data/spec/support/install.sh +43 -7
  114. data/spec/support/simplecov_helper.rb +9 -5
  115. data/spec/support/simplecov_quality_formatter.rb +10 -6
  116. data/spec/unit/apns_feedback_spec.rb +3 -3
  117. data/spec/unit/{adm → client/active_record/adm}/app_spec.rb +3 -3
  118. data/spec/unit/{adm → client/active_record/adm}/notification_spec.rb +5 -7
  119. data/spec/unit/client/active_record/apns/app_spec.rb +29 -0
  120. data/spec/unit/client/active_record/apns/feedback_spec.rb +9 -0
  121. data/spec/unit/client/active_record/apns/notification_spec.rb +231 -0
  122. data/spec/unit/client/active_record/app_spec.rb +30 -0
  123. data/spec/unit/client/active_record/gcm/app_spec.rb +4 -0
  124. data/spec/unit/{gcm → client/active_record/gcm}/notification_spec.rb +5 -7
  125. data/spec/unit/client/active_record/notification_spec.rb +15 -0
  126. data/spec/unit/client/active_record/wpns/app_spec.rb +4 -0
  127. data/spec/unit/client/active_record/wpns/notification_spec.rb +21 -0
  128. data/spec/unit/configuration_spec.rb +12 -5
  129. data/spec/unit/daemon/adm/delivery_spec.rb +57 -54
  130. data/spec/unit/daemon/apns/certificate_expired_error_spec.rb +3 -3
  131. data/spec/unit/daemon/apns/delivery_spec.rb +90 -83
  132. data/spec/unit/daemon/apns/feedback_receiver_spec.rb +24 -17
  133. data/spec/unit/daemon/app_runner_spec.rb +66 -123
  134. data/spec/unit/daemon/batch_spec.rb +52 -115
  135. data/spec/unit/daemon/delivery_spec.rb +15 -1
  136. data/spec/unit/daemon/dispatcher/http_spec.rb +3 -2
  137. data/spec/unit/daemon/dispatcher/tcp_spec.rb +10 -9
  138. data/spec/unit/daemon/dispatcher_loop_spec.rb +7 -12
  139. data/spec/unit/daemon/feeder_spec.rb +40 -39
  140. data/spec/unit/daemon/gcm/delivery_spec.rb +108 -89
  141. data/spec/unit/daemon/reflectable_spec.rb +2 -2
  142. data/spec/unit/daemon/retryable_error_spec.rb +1 -1
  143. data/spec/unit/daemon/service_config_methods_spec.rb +6 -3
  144. data/spec/unit/daemon/signal_handler_spec.rb +72 -0
  145. data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +9 -9
  146. data/spec/unit/daemon/store/active_record_spec.rb +38 -47
  147. data/spec/unit/daemon/tcp_connection_spec.rb +22 -34
  148. data/spec/unit/daemon/too_many_requests_error_spec.rb +1 -1
  149. data/spec/unit/daemon/wpns/delivery_spec.rb +61 -50
  150. data/spec/unit/daemon_spec.rb +46 -81
  151. data/spec/unit/embed_spec.rb +4 -2
  152. data/spec/unit/logger_spec.rb +30 -40
  153. data/spec/unit/notification_shared.rb +9 -79
  154. data/spec/unit/push_spec.rb +3 -8
  155. data/spec/unit/reflection_spec.rb +25 -25
  156. data/spec/unit/rpush_spec.rb +1 -2
  157. data/spec/unit_spec_helper.rb +33 -88
  158. metadata +119 -67
  159. data/lib/rpush/TODO +0 -3
  160. data/lib/rpush/adm/app.rb +0 -15
  161. data/lib/rpush/adm/data_validator.rb +0 -11
  162. data/lib/rpush/adm/notification.rb +0 -29
  163. data/lib/rpush/apns/app.rb +0 -29
  164. data/lib/rpush/apns/binary_notification_validator.rb +0 -12
  165. data/lib/rpush/apns/device_token_format_validator.rb +0 -12
  166. data/lib/rpush/apns/feedback.rb +0 -16
  167. data/lib/rpush/apns/notification.rb +0 -84
  168. data/lib/rpush/app.rb +0 -18
  169. data/lib/rpush/daemon/apns/certificate_expired_error.rb +0 -20
  170. data/lib/rpush/daemon/apns/disconnection_error.rb +0 -20
  171. data/lib/rpush/gcm/app.rb +0 -11
  172. data/lib/rpush/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +0 -11
  173. data/lib/rpush/gcm/notification.rb +0 -30
  174. data/lib/rpush/notification.rb +0 -69
  175. data/lib/rpush/notifier.rb +0 -52
  176. data/lib/rpush/payload_data_size_validator.rb +0 -10
  177. data/lib/rpush/railtie.rb +0 -11
  178. data/lib/rpush/registration_ids_count_validator.rb +0 -10
  179. data/lib/rpush/wpns/app.rb +0 -9
  180. data/lib/rpush/wpns/notification.rb +0 -26
  181. data/lib/tasks/cane.rake +0 -18
  182. data/lib/tasks/rpush.rake +0 -16
  183. data/spec/unit/apns/app_spec.rb +0 -29
  184. data/spec/unit/apns/feedback_spec.rb +0 -9
  185. data/spec/unit/apns/notification_spec.rb +0 -208
  186. data/spec/unit/app_spec.rb +0 -30
  187. data/spec/unit/daemon/apns/disconnection_error_spec.rb +0 -18
  188. data/spec/unit/daemon/interruptible_sleep_spec.rb +0 -68
  189. data/spec/unit/gcm/app_spec.rb +0 -4
  190. data/spec/unit/notification_spec.rb +0 -15
  191. data/spec/unit/notifier_spec.rb +0 -49
  192. data/spec/unit/wpns/app_spec.rb +0 -4
  193. data/spec/unit/wpns/notification_spec.rb +0 -30
@@ -0,0 +1,11 @@
1
+ module Rpush
2
+ module Client
3
+ module Redis
4
+ module Adm
5
+ class Notification < Rpush::Client::Redis::Notification
6
+ include Rpush::Client::ActiveModel::Adm::Notification
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Rpush
2
+ module Client
3
+ module Redis
4
+ module Apns
5
+ class App < Rpush::Client::Redis::App
6
+ include Rpush::Client::ActiveModel::Apns::App
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,20 @@
1
+ module Rpush
2
+ module Client
3
+ module Redis
4
+ module Apns
5
+ class Feedback
6
+ include Modis::Model
7
+
8
+ attribute :app_id, :integer
9
+ attribute :device_token, :string
10
+ attribute :failed_at, :timestamp
11
+
12
+ validates :device_token, presence: true
13
+ validates :failed_at, presence: true
14
+
15
+ validates_with Rpush::Client::ActiveModel::Apns::DeviceTokenFormatValidator
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ module Rpush
2
+ module Client
3
+ module Redis
4
+ module Apns
5
+ class Notification < Rpush::Client::Redis::Notification
6
+ include Rpush::Client::ActiveModel::Apns::Notification
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,22 @@
1
+ module Rpush
2
+ module Client
3
+ module Redis
4
+ class App
5
+ include Modis::Model
6
+ self.namespace = 'apps'
7
+
8
+ attribute :name, :string
9
+ attribute :environment, :string
10
+ attribute :certificate, :string
11
+ attribute :password, :string
12
+ attribute :connections, :integer, default: 1
13
+ attribute :auth_key, :string
14
+ attribute :client_id, :string
15
+ attribute :client_secret, :string
16
+
17
+ validates :name, presence: true
18
+ validates_numericality_of :connections, greater_than: 0, only_integer: true
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ module Rpush
2
+ module Client
3
+ module Redis
4
+ module Gcm
5
+ class App < Rpush::Client::Redis::App
6
+ include Rpush::Client::ActiveModel::Gcm::App
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Rpush
2
+ module Client
3
+ module Redis
4
+ module Gcm
5
+ class Notification < Rpush::Client::Redis::Notification
6
+ include Rpush::Client::ActiveModel::Gcm::Notification
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,68 @@
1
+ module Rpush
2
+ module Client
3
+ module Redis
4
+ class Notification
5
+ include Rpush::MultiJsonHelper
6
+ include Modis::Model
7
+ include Rpush::Client::ActiveModel::Notification
8
+
9
+ after_create :register_notification
10
+
11
+ self.namespace = 'notifications'
12
+
13
+ def self.absolute_pending_namespace
14
+ "#{absolute_namespace}:pending"
15
+ end
16
+
17
+ def self.absolute_retryable_namespace
18
+ "#{absolute_namespace}:retryable"
19
+ end
20
+
21
+ attribute :badge, :integer
22
+ attribute :device_token, :string
23
+ attribute :sound, :string, default: 'default'
24
+ attribute :alert, :hash, strict: false
25
+ attribute :data, :hash
26
+ attribute :expiry, :integer, default: 1.day.to_i
27
+ attribute :delivered, :boolean
28
+ attribute :delivered_at, :timestamp
29
+ attribute :failed, :boolean
30
+ attribute :failed_at, :timestamp
31
+ attribute :fail_after, :timestamp
32
+ attribute :retries, :integer, default: 0
33
+ attribute :error_code, :integer
34
+ attribute :error_description, :string
35
+ attribute :deliver_after, :timestamp
36
+ attribute :alert_is_json, :boolean
37
+ attribute :app_id, :integer
38
+ attribute :collapse_key, :string
39
+ attribute :delay_while_idle, :boolean
40
+ attribute :registration_ids, :array
41
+ attribute :uri, :string
42
+ attribute :priority, :integer
43
+
44
+ def app
45
+ return nil unless app_id
46
+ @app ||= Rpush::Client::Redis::App.find(app_id)
47
+ end
48
+
49
+ def app=(app)
50
+ @app = app
51
+ if app
52
+ self.app_id = app.id
53
+ else
54
+ self.app_id = nil
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def register_notification
61
+ Modis.with_connection do |redis|
62
+ redis.zadd(self.class.absolute_pending_namespace, id, id)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,11 @@
1
+ module Rpush
2
+ module Client
3
+ module Redis
4
+ module Wpns
5
+ class App < Rpush::Client::Redis::App
6
+ include Rpush::Client::ActiveModel::Wpns::App
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Rpush
2
+ module Client
3
+ module Redis
4
+ module Wpns
5
+ class Notification < Rpush::Client::Redis::Notification
6
+ include Rpush::Client::ActiveModel::Wpns::Notification
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -4,12 +4,28 @@ module Rpush
4
4
  end
5
5
 
6
6
  def self.configure
7
- yield config if block_given?
7
+ if block_given?
8
+ yield config
9
+ initialize_client
10
+ end
11
+ end
12
+
13
+ def self.initialize_client
14
+ return if @client_initialized
15
+ require "rpush/client/#{config.client}"
16
+ client_module = Rpush::Client.const_get(config.client.to_s.camelize)
17
+ Rpush.send(:include, client_module)
18
+
19
+ [:Apns, :Gcm, :Wpns, :Adm].each do |service|
20
+ Rpush.const_set(service, client_module.const_get(service))
21
+ end
22
+
23
+ @client_initialized = true
8
24
  end
9
25
 
10
26
  CONFIG_ATTRS = [:foreground, :push_poll, :feedback_poll, :embedded,
11
- :check_for_errors, :pid_file, :batch_size, :push, :store, :logger,
12
- :batch_storage_updates, :wakeup]
27
+ :check_for_errors, :pid_file, :batch_size, :push, :client, :logger,
28
+ :batch_storage_updates, :log_dir, :environment]
13
29
 
14
30
  class ConfigurationWithoutDefaults < Struct.new(*CONFIG_ATTRS)
15
31
  end
@@ -17,6 +33,11 @@ module Rpush
17
33
  class Configuration < Struct.new(*CONFIG_ATTRS)
18
34
  include Deprecatable
19
35
 
36
+ deprecated(:batch_storage_updates=, '2.1.0', 'Updates are now always batched by the storage backends.')
37
+ deprecated(:check_for_errors=, '2.1.0', 'APNs error detection is now performed asynchronously and does not require pauses.')
38
+
39
+ delegate :redis_options, :redis_options=, to: :Modis
40
+
20
41
  def initialize
21
42
  super
22
43
  set_defaults
@@ -60,16 +81,16 @@ module Rpush
60
81
 
61
82
  self.push_poll = 2
62
83
  self.feedback_poll = 60
63
- self.check_for_errors = true
64
84
  self.batch_size = 100
65
85
  self.pid_file = nil
66
- self.store = :active_record
86
+ self.client = :active_record
67
87
  self.logger = nil
68
- self.batch_storage_updates = true
88
+ self.log_dir = Rails.root
69
89
 
70
90
  # Internal options.
71
91
  self.embedded = false
72
92
  self.push = false
93
+ self.environment = Rails.env
73
94
  end
74
95
  end
75
96
  end
@@ -2,9 +2,9 @@ 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'
@@ -15,18 +15,23 @@ 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'
18
19
  require 'rpush/daemon/app_runner'
19
20
  require 'rpush/daemon/tcp_connection'
20
21
  require 'rpush/daemon/dispatcher_loop'
21
22
  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
- setup_signal_traps if trap_signals?
50
-
54
+ SignalHandler.start
55
+ Process.daemon if daemonize?
51
56
  initialize_store
52
- return unless store
53
-
54
- if daemonize?
55
- daemonize
56
- store.after_daemonize
57
- end
58
-
59
57
  write_pid_file
60
58
  AppRunner.sync
59
+
60
+ # No further store connections will be made from this thread.
61
+ store.release_connection
62
+
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 }
62
68
  end
63
69
 
64
70
  def self.shutdown(quiet = false)
65
71
  puts "\nShutting down..." unless quiet
66
- Feeder.stop
67
- AppRunner.stop
68
- delete_pid_file
72
+
73
+ shutdown_lock.synchronize do
74
+ Feeder.stop
75
+ AppRunner.stop
76
+ delete_pid_file
77
+ end
78
+ end
79
+
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.store.to_s
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.store}' storage backend.")
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
- if !Rpush.config.pid_file.blank?
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.exists?(pid_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
@@ -12,7 +12,7 @@ module Rpush
12
12
  AMAZON_ADM_URL = 'https://api.amazon.com/messaging/registrations/%s/messages'
13
13
 
14
14
  # Data used to request authorization tokens.
15
- ACCESS_TOKEN_REQUEST_DATA = {"grant_type" => "client_credentials", "scope" => "messaging:push"}
15
+ ACCESS_TOKEN_REQUEST_DATA = { "grant_type" => "client_credentials", "scope" => "messaging:push" }
16
16
 
17
17
  def initialize(app, http, notification, batch)
18
18
  @app = app
@@ -24,29 +24,27 @@ module Rpush
24
24
  end
25
25
 
26
26
  def perform
27
- begin
28
- @notification.registration_ids.each do |registration_id|
29
- handle_response(do_post(registration_id), registration_id)
30
- end
31
-
32
- if(@sent_registration_ids.empty?)
33
- raise Rpush::DeliveryError.new(nil, @notification.id, describe_errors)
34
- else
35
- unless(@failed_registration_ids.empty?)
36
- @notification.error_description = describe_errors
37
- Rpush::Daemon.store.update_notification(@notification)
38
- end
39
-
40
- mark_delivered
27
+ @notification.registration_ids.each do |registration_id|
28
+ handle_response(do_post(registration_id), registration_id)
29
+ end
30
+ if @sent_registration_ids.empty?
31
+ fail Rpush::DeliveryError.new(nil, @notification.id, describe_errors)
32
+ else
33
+ unless @failed_registration_ids.empty?
34
+ @notification.error_description = describe_errors
35
+ Rpush::Daemon.store.update_notification(@notification)
41
36
  end
42
- rescue Rpush::RetryableError => error
43
- handle_retryable(error)
44
- rescue Rpush::TooManyRequestsError => error
45
- handle_too_many_requests(error)
46
- rescue Rpush::DeliveryError => error
47
- mark_failed(error.code, error.description)
48
- raise
37
+ mark_delivered
49
38
  end
39
+ rescue Rpush::RetryableError => error
40
+ handle_retryable(error)
41
+ rescue Rpush::TooManyRequestsError => error
42
+ handle_too_many_requests(error)
43
+ rescue StandardError => error
44
+ mark_failed(error)
45
+ raise
46
+ ensure
47
+ @batch.notification_processed
50
48
  end
51
49
 
52
50
  protected
@@ -62,25 +60,25 @@ module Rpush
62
60
  when 429
63
61
  too_many_requests(response)
64
62
  when 500
65
- internal_server_error(response, current_registration_id)
63
+ internal_server_error(current_registration_id)
66
64
  when 503
67
65
  service_unavailable(response)
68
66
  else
69
- raise Rpush::DeliveryError.new(response.code, @notification.id, Rpush::Daemon::HTTP_STATUS_CODES[response.code.to_i])
67
+ fail Rpush::DeliveryError.new(response.code, @notification.id, Rpush::Daemon::HTTP_STATUS_CODES[response.code.to_i])
70
68
  end
71
69
  end
72
70
 
73
71
  def ok(response, current_registration_id)
74
72
  response_body = multi_json_load(response.body)
75
73
 
76
- if(response_body.has_key?('registrationID'))
74
+ if response_body.key?('registrationID')
77
75
  @sent_registration_ids << response_body['registrationID']
78
76
  log_info("#{@notification.id} sent to #{response_body['registrationID']}")
79
77
  end
80
78
 
81
- if(current_registration_id != response_body['registrationID'])
82
- reflect(:adm_canonical_id, current_registration_id, response_body['registrationID'])
83
- end
79
+ return if current_registration_id == response_body['registrationID']
80
+
81
+ reflect(:adm_canonical_id, current_registration_id, response_body['registrationID'])
84
82
  end
85
83
 
86
84
  def handle_retryable(error)
@@ -88,7 +86,7 @@ module Rpush
88
86
  when 401
89
87
  # clear app access_token so a new one is fetched
90
88
  @notification.app.access_token = nil
91
- get_access_token
89
+ access_token
92
90
  mark_retryable(@notification, Time.now) if @notification.app.access_token
93
91
  when 503
94
92
  retry_delivery(@notification, error.response)
@@ -97,7 +95,7 @@ module Rpush
97
95
  end
98
96
 
99
97
  def handle_too_many_requests(error)
100
- if(@sent_registration_ids.empty?)
98
+ if @sent_registration_ids.empty?
101
99
  # none sent yet, just resend after the specified retry-after response.header
102
100
  retry_delivery(@notification, error.response)
103
101
  else
@@ -120,30 +118,30 @@ module Rpush
120
118
  def bad_request(response, current_registration_id)
121
119
  response_body = multi_json_load(response.body)
122
120
 
123
- if(response_body.has_key?('reason'))
124
- log_warn("bad_request: #{current_registration_id} (#{response_body['reason']})")
125
- @failed_registration_ids[current_registration_id] = response_body['reason']
126
- end
121
+ return unless response_body.key?('reason')
122
+
123
+ log_warn("bad_request: #{current_registration_id} (#{response_body['reason']})")
124
+ @failed_registration_ids[current_registration_id] = response_body['reason']
127
125
  end
128
126
 
129
127
  def unauthorized(response)
130
128
  # Indicate a notification is retryable. Because ADM requires separate request for each push token, this will safely mark the entire notification to retry delivery.
131
- raise Rpush::RetryableError.new(response.code.to_i, @notification.id, 'ADM responded with an Unauthorized Error.', response)
129
+ fail Rpush::RetryableError.new(response.code.to_i, @notification.id, 'ADM responded with an Unauthorized Error.', response)
132
130
  end
133
131
 
134
132
  def too_many_requests(response)
135
133
  # raise error so the current notification stops sending messages to remaining reg ids
136
- raise Rpush::TooManyRequestsError.new(response.code.to_i, @notification.id, 'Exceeded maximum allowable rate of messages.', response)
134
+ fail Rpush::TooManyRequestsError.new(response.code.to_i, @notification.id, 'Exceeded maximum allowable rate of messages.', response)
137
135
  end
138
136
 
139
- def internal_server_error(response, current_registration_id)
137
+ def internal_server_error(current_registration_id)
140
138
  @failed_registration_ids[current_registration_id] = "Internal Server Error"
141
139
  log_warn("internal_server_error: #{current_registration_id} (Internal Server Error)")
142
140
  end
143
141
 
144
142
  def service_unavailable(response)
145
143
  # Indicate a notification is retryable. Because ADM requires separate request for each push token, this will safely mark the entire notification to retry delivery.
146
- raise Rpush::RetryableError.new(response.code.to_i, @notification.id, 'ADM responded with an Service Unavailable Error.', response)
144
+ fail Rpush::RetryableError.new(response.code.to_i, @notification.id, 'ADM responded with an Service Unavailable Error.', response)
147
145
  end
148
146
 
149
147
  def create_new_notification(response, registration_ids)
@@ -156,7 +154,8 @@ module Rpush
156
154
  end
157
155
 
158
156
  def retry_delivery(notification, response)
159
- if time = deliver_after_header(response)
157
+ time = deliver_after_header(response)
158
+ if time
160
159
  mark_retryable(notification, time)
161
160
  else
162
161
  mark_retryable_exponential(notification)
@@ -178,23 +177,22 @@ module Rpush
178
177
  end
179
178
 
180
179
  def do_post(registration_id)
181
- adm_uri = URI.parse(AMAZON_ADM_URL % [registration_id])
182
- post = Net::HTTP::Post.new(adm_uri.path, initheader = {
183
- 'Content-Type' => 'application/json',
184
- 'Accept' => 'application/json',
185
- 'x-amzn-type-version' => 'com.amazon.device.messaging.ADMMessage@1.0',
186
- 'x-amzn-accept-type' => 'com.amazon.device.messaging.ADMSendResult@1.0',
187
- 'Authorization' => "Bearer #{get_access_token}"
188
- })
180
+ adm_uri = URI.parse(format(AMAZON_ADM_URL, registration_id))
181
+ post = Net::HTTP::Post.new(adm_uri.path,
182
+ 'Content-Type' => 'application/json',
183
+ 'Accept' => 'application/json',
184
+ 'x-amzn-type-version' => 'com.amazon.device.messaging.ADMMessage@1.0',
185
+ 'x-amzn-accept-type' => 'com.amazon.device.messaging.ADMSendResult@1.0',
186
+ 'Authorization' => "Bearer #{access_token}")
189
187
  post.body = @notification.as_json.to_json
190
188
 
191
189
  @http.request(adm_uri, post)
192
190
  end
193
191
 
194
- def get_access_token
195
- if(@notification.app.access_token.nil? || @notification.app.access_token_expired?)
196
- post = Net::HTTP::Post.new(AMAZON_TOKEN_URI.path, initheader = {'Content-Type' => 'application/x-www-form-urlencoded'})
197
- post.set_form_data(ACCESS_TOKEN_REQUEST_DATA.merge({'client_id' => @notification.app.client_id, 'client_secret' => @notification.app.client_secret}))
192
+ def access_token
193
+ if @notification.app.access_token.nil? || @notification.app.access_token_expired?
194
+ post = Net::HTTP::Post.new(AMAZON_TOKEN_URI.path, 'Content-Type' => 'application/x-www-form-urlencoded')
195
+ post.set_form_data(ACCESS_TOKEN_REQUEST_DATA.merge('client_id' => @notification.app.client_id, 'client_secret' => @notification.app.client_secret))
198
196
 
199
197
  handle_access_token(@http.request(AMAZON_TOKEN_URI, post))
200
198
  end
@@ -203,7 +201,7 @@ module Rpush
203
201
  end
204
202
 
205
203
  def handle_access_token(response)
206
- if(response.code.to_i == 200)
204
+ if response.code.to_i == 200
207
205
  update_access_token(JSON.parse(response.body))
208
206
  Rpush::Daemon.store.update_app(@notification.app)
209
207
  log_info("ADM access token updated: token = #{@notification.app.access_token}, expires = #{@notification.app.access_token_expiration}")