rpush 1.0.0 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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}")