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.
Files changed (201) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/README.md +37 -22
  4. data/bin/rpush +13 -4
  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 +28 -7
  17. data/lib/generators/templates/rpush_2_0_0_updates.rb +42 -0
  18. data/lib/rpush/client/active_model/adm/app.rb +23 -0
  19. data/lib/rpush/client/active_model/adm/data_validator.rb +14 -0
  20. data/lib/rpush/client/active_model/adm/notification.rb +28 -0
  21. data/lib/rpush/client/active_model/apns/app.rb +37 -0
  22. data/lib/rpush/client/active_model/apns/binary_notification_validator.rb +16 -0
  23. data/lib/rpush/client/active_model/apns/device_token_format_validator.rb +14 -0
  24. data/lib/rpush/client/active_model/apns/notification.rb +90 -0
  25. data/lib/rpush/client/active_model/gcm/app.rb +19 -0
  26. data/lib/rpush/client/active_model/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +14 -0
  27. data/lib/rpush/client/active_model/gcm/notification.rb +31 -0
  28. data/lib/rpush/client/active_model/notification.rb +26 -0
  29. data/lib/rpush/client/active_model/payload_data_size_validator.rb +13 -0
  30. data/lib/rpush/client/active_model/registration_ids_count_validator.rb +13 -0
  31. data/lib/rpush/client/active_model/wpns/app.rb +13 -0
  32. data/lib/rpush/client/active_model/wpns/notification.rb +17 -0
  33. data/lib/rpush/client/active_model.rb +21 -0
  34. data/lib/rpush/client/active_record/adm/app.rb +11 -0
  35. data/lib/rpush/client/active_record/adm/notification.rb +11 -0
  36. data/lib/rpush/client/active_record/apns/app.rb +11 -0
  37. data/lib/rpush/client/active_record/apns/feedback.rb +22 -0
  38. data/lib/rpush/client/active_record/apns/notification.rb +46 -0
  39. data/lib/rpush/client/active_record/app.rb +17 -0
  40. data/lib/rpush/client/active_record/gcm/app.rb +11 -0
  41. data/lib/rpush/client/active_record/gcm/notification.rb +11 -0
  42. data/lib/rpush/client/active_record/notification.rb +38 -0
  43. data/lib/rpush/client/active_record/wpns/app.rb +11 -0
  44. data/lib/rpush/client/active_record/wpns/notification.rb +11 -0
  45. data/lib/rpush/client/active_record.rb +19 -0
  46. data/lib/rpush/client/redis/adm/app.rb +14 -0
  47. data/lib/rpush/client/redis/adm/notification.rb +11 -0
  48. data/lib/rpush/client/redis/apns/app.rb +11 -0
  49. data/lib/rpush/client/redis/apns/feedback.rb +20 -0
  50. data/lib/rpush/client/redis/apns/notification.rb +11 -0
  51. data/lib/rpush/client/redis/app.rb +24 -0
  52. data/lib/rpush/client/redis/gcm/app.rb +11 -0
  53. data/lib/rpush/client/redis/gcm/notification.rb +11 -0
  54. data/lib/rpush/client/redis/notification.rb +68 -0
  55. data/lib/rpush/client/redis/wpns/app.rb +11 -0
  56. data/lib/rpush/client/redis/wpns/notification.rb +11 -0
  57. data/lib/rpush/client/redis.rb +35 -0
  58. data/lib/rpush/configuration.rb +27 -6
  59. data/lib/rpush/daemon/adm/delivery.rb +56 -55
  60. data/lib/rpush/daemon/apns/delivery.rb +20 -44
  61. data/lib/rpush/daemon/apns/feedback_receiver.rb +11 -8
  62. data/lib/rpush/daemon/apns.rb +6 -5
  63. data/lib/rpush/daemon/app_runner.rb +103 -99
  64. data/lib/rpush/daemon/batch.rb +54 -40
  65. data/lib/rpush/daemon/delivery.rb +13 -3
  66. data/lib/rpush/daemon/delivery_error.rb +10 -2
  67. data/lib/rpush/daemon/dispatcher/apns_tcp.rb +114 -0
  68. data/lib/rpush/daemon/dispatcher/http.rb +3 -3
  69. data/lib/rpush/daemon/dispatcher/tcp.rb +3 -3
  70. data/lib/rpush/daemon/dispatcher_loop.rb +37 -23
  71. data/lib/rpush/daemon/errors.rb +18 -0
  72. data/lib/rpush/daemon/feeder.rb +28 -39
  73. data/lib/rpush/daemon/gcm/delivery.rb +19 -20
  74. data/lib/rpush/daemon/interruptible_sleep.rb +26 -45
  75. data/lib/rpush/daemon/loggable.rb +2 -4
  76. data/lib/rpush/daemon/proc_title.rb +16 -0
  77. data/lib/rpush/daemon/queue_payload.rb +12 -0
  78. data/lib/rpush/daemon/reflectable.rb +3 -5
  79. data/lib/rpush/daemon/retry_header_parser.rb +6 -6
  80. data/lib/rpush/daemon/retryable_error.rb +2 -0
  81. data/lib/rpush/daemon/ring_buffer.rb +16 -0
  82. data/lib/rpush/daemon/service_config_methods.rb +23 -7
  83. data/lib/rpush/daemon/signal_handler.rb +56 -0
  84. data/lib/rpush/daemon/store/active_record/reconnectable.rb +21 -17
  85. data/lib/rpush/daemon/store/active_record.rb +71 -38
  86. data/lib/rpush/daemon/store/interface.rb +19 -0
  87. data/lib/rpush/daemon/store/redis.rb +149 -0
  88. data/lib/rpush/daemon/string_helpers.rb +15 -0
  89. data/lib/rpush/daemon/synchronizer.rb +60 -0
  90. data/lib/rpush/daemon/tcp_connection.rb +6 -11
  91. data/lib/rpush/daemon/wpns/delivery.rb +21 -30
  92. data/lib/rpush/daemon.rb +40 -60
  93. data/lib/rpush/deprecatable.rb +4 -3
  94. data/lib/rpush/deprecation.rb +7 -10
  95. data/lib/rpush/embed.rb +8 -3
  96. data/lib/rpush/logger.rb +11 -15
  97. data/lib/rpush/push.rb +1 -2
  98. data/lib/rpush/reflection.rb +8 -12
  99. data/lib/rpush/version.rb +1 -1
  100. data/lib/rpush.rb +5 -29
  101. data/lib/tasks/quality.rake +35 -0
  102. data/lib/tasks/test.rake +1 -5
  103. data/spec/.rubocop.yml +4 -0
  104. data/spec/functional/adm_spec.rb +3 -6
  105. data/spec/functional/apns_spec.rb +117 -24
  106. data/spec/functional/embed_spec.rb +20 -20
  107. data/spec/functional/gcm_spec.rb +4 -7
  108. data/spec/functional/new_app_spec.rb +59 -0
  109. data/spec/functional/retry_spec.rb +46 -0
  110. data/spec/functional/synchronization_spec.rb +68 -0
  111. data/spec/functional/wpns_spec.rb +3 -6
  112. data/spec/functional_spec_helper.rb +26 -0
  113. data/spec/integration/rpush_spec.rb +13 -0
  114. data/spec/integration/support/gcm_success_response.json +1 -0
  115. data/spec/spec_helper.rb +60 -0
  116. data/spec/support/active_record_setup.rb +48 -0
  117. data/{config → spec/support/config}/database.yml +0 -0
  118. data/spec/support/install.sh +43 -7
  119. data/spec/support/simplecov_helper.rb +9 -5
  120. data/spec/support/simplecov_quality_formatter.rb +10 -6
  121. data/spec/unit/apns_feedback_spec.rb +3 -3
  122. data/spec/unit/{adm → client/active_record/adm}/app_spec.rb +3 -3
  123. data/spec/unit/{adm → client/active_record/adm}/notification_spec.rb +5 -7
  124. data/spec/unit/client/active_record/apns/app_spec.rb +29 -0
  125. data/spec/unit/client/active_record/apns/feedback_spec.rb +9 -0
  126. data/spec/unit/client/active_record/apns/notification_spec.rb +231 -0
  127. data/spec/unit/client/active_record/app_spec.rb +30 -0
  128. data/spec/unit/client/active_record/gcm/app_spec.rb +4 -0
  129. data/spec/unit/{gcm → client/active_record/gcm}/notification_spec.rb +5 -7
  130. data/spec/unit/client/active_record/notification_spec.rb +21 -0
  131. data/spec/unit/client/active_record/wpns/app_spec.rb +4 -0
  132. data/spec/unit/client/active_record/wpns/notification_spec.rb +21 -0
  133. data/spec/unit/configuration_spec.rb +12 -5
  134. data/spec/unit/daemon/adm/delivery_spec.rb +66 -55
  135. data/spec/unit/daemon/apns/certificate_expired_error_spec.rb +3 -3
  136. data/spec/unit/daemon/apns/delivery_spec.rb +90 -83
  137. data/spec/unit/daemon/apns/feedback_receiver_spec.rb +22 -17
  138. data/spec/unit/daemon/app_runner_spec.rb +78 -186
  139. data/spec/unit/daemon/batch_spec.rb +52 -115
  140. data/spec/unit/daemon/delivery_spec.rb +15 -1
  141. data/spec/unit/daemon/dispatcher/http_spec.rb +3 -2
  142. data/spec/unit/daemon/dispatcher/tcp_spec.rb +10 -9
  143. data/spec/unit/daemon/dispatcher_loop_spec.rb +6 -24
  144. data/spec/unit/daemon/feeder_spec.rb +38 -39
  145. data/spec/unit/daemon/gcm/delivery_spec.rb +122 -101
  146. data/spec/unit/daemon/reflectable_spec.rb +2 -2
  147. data/spec/unit/daemon/retryable_error_spec.rb +1 -1
  148. data/spec/unit/daemon/service_config_methods_spec.rb +6 -3
  149. data/spec/unit/daemon/signal_handler_spec.rb +95 -0
  150. data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +48 -27
  151. data/spec/unit/daemon/store/active_record_spec.rb +38 -47
  152. data/spec/unit/daemon/tcp_connection_spec.rb +22 -34
  153. data/spec/unit/daemon/wpns/delivery_spec.rb +58 -50
  154. data/spec/unit/daemon_spec.rb +48 -82
  155. data/spec/unit/embed_spec.rb +6 -4
  156. data/spec/unit/logger_spec.rb +35 -43
  157. data/spec/unit/notification_shared.rb +9 -79
  158. data/spec/unit/push_spec.rb +6 -10
  159. data/spec/unit/reflection_spec.rb +25 -25
  160. data/spec/unit/rpush_spec.rb +1 -2
  161. data/spec/unit_spec_helper.rb +33 -88
  162. metadata +126 -76
  163. data/lib/rpush/TODO +0 -3
  164. data/lib/rpush/adm/app.rb +0 -15
  165. data/lib/rpush/adm/data_validator.rb +0 -11
  166. data/lib/rpush/adm/notification.rb +0 -29
  167. data/lib/rpush/apns/app.rb +0 -29
  168. data/lib/rpush/apns/binary_notification_validator.rb +0 -12
  169. data/lib/rpush/apns/device_token_format_validator.rb +0 -12
  170. data/lib/rpush/apns/feedback.rb +0 -16
  171. data/lib/rpush/apns/notification.rb +0 -84
  172. data/lib/rpush/app.rb +0 -18
  173. data/lib/rpush/daemon/apns/certificate_expired_error.rb +0 -20
  174. data/lib/rpush/daemon/apns/disconnection_error.rb +0 -20
  175. data/lib/rpush/daemon/dispatcher_loop_collection.rb +0 -33
  176. data/lib/rpush/daemon/too_many_requests_error.rb +0 -20
  177. data/lib/rpush/gcm/app.rb +0 -11
  178. data/lib/rpush/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +0 -11
  179. data/lib/rpush/gcm/notification.rb +0 -30
  180. data/lib/rpush/notification.rb +0 -69
  181. data/lib/rpush/notifier.rb +0 -52
  182. data/lib/rpush/payload_data_size_validator.rb +0 -10
  183. data/lib/rpush/railtie.rb +0 -11
  184. data/lib/rpush/registration_ids_count_validator.rb +0 -10
  185. data/lib/rpush/wpns/app.rb +0 -9
  186. data/lib/rpush/wpns/notification.rb +0 -26
  187. data/lib/tasks/cane.rake +0 -18
  188. data/lib/tasks/rpush.rake +0 -16
  189. data/spec/unit/apns/app_spec.rb +0 -29
  190. data/spec/unit/apns/feedback_spec.rb +0 -9
  191. data/spec/unit/apns/notification_spec.rb +0 -208
  192. data/spec/unit/app_spec.rb +0 -30
  193. data/spec/unit/daemon/apns/disconnection_error_spec.rb +0 -18
  194. data/spec/unit/daemon/dispatcher_loop_collection_spec.rb +0 -37
  195. data/spec/unit/daemon/interruptible_sleep_spec.rb +0 -68
  196. data/spec/unit/daemon/too_many_requests_error_spec.rb +0 -14
  197. data/spec/unit/gcm/app_spec.rb +0 -4
  198. data/spec/unit/notification_spec.rb +0 -15
  199. data/spec/unit/notifier_spec.rb +0 -49
  200. data/spec/unit/wpns/app_spec.rb +0 -4
  201. data/spec/unit/wpns/notification_spec.rb +0 -30
@@ -6,11 +6,11 @@ class AddWpns < ActiveRecord::Migration
6
6
  end
7
7
 
8
8
  def self.up
9
- add_column :rapns_notifications, :uri, :string, :null => true
9
+ add_column :rapns_notifications, :uri, :string, null: true
10
10
  end
11
11
 
12
12
  def self.down
13
- AddWpns::Rapns::Notification.where(:type => 'Rapns::Wpns::Notification').delete_all
13
+ AddWpns::Rapns::Notification.where(type: 'Rapns::Wpns::Notification').delete_all
14
14
  remove_column :rapns_notifications, :uri
15
15
  end
16
16
  end
@@ -1,11 +1,11 @@
1
1
  class CreateRapnsApps < ActiveRecord::Migration
2
2
  def self.up
3
3
  create_table :rapns_apps do |t|
4
- t.string :key, :null => false
5
- t.string :environment, :null => false
6
- t.text :certificate, :null => false
7
- t.string :password, :null => true
8
- t.integer :connections, :null => false, :default => 1
4
+ t.string :key, null: false
5
+ t.string :environment, null: false
6
+ t.text :certificate, null: false
7
+ t.string :password, null: true
8
+ t.integer :connections, null: false, default: 1
9
9
  t.timestamps
10
10
  end
11
11
  end
@@ -1,8 +1,8 @@
1
1
  class CreateRapnsFeedback < ActiveRecord::Migration
2
2
  def self.up
3
3
  create_table :rapns_feedback do |t|
4
- t.string :device_token, :null => false, :limit => 64
5
- t.timestamp :failed_at, :null => false
4
+ t.string :device_token, null: false, limit: 64
5
+ t.timestamp :failed_at, null: false
6
6
  t.timestamps
7
7
  end
8
8
 
@@ -1,28 +1,28 @@
1
1
  class CreateRapnsNotifications < ActiveRecord::Migration
2
2
  def self.up
3
3
  create_table :rapns_notifications do |t|
4
- t.integer :badge, :null => true
5
- t.string :device_token, :null => false, :limit => 64
6
- t.string :sound, :null => true, :default => "1.aiff"
7
- t.string :alert, :null => true
8
- t.text :attributes_for_device, :null => true
9
- t.integer :expiry, :null => false, :default => 1.day.to_i
10
- t.boolean :delivered, :null => false, :default => false
11
- t.timestamp :delivered_at, :null => true
12
- t.boolean :failed, :null => false, :default => false
13
- t.timestamp :failed_at, :null => true
14
- t.integer :error_code, :null => true
15
- t.string :error_description, :null => true
16
- t.timestamp :deliver_after, :null => true
4
+ t.integer :badge, null: true
5
+ t.string :device_token, null: false, limit: 64
6
+ t.string :sound, null: true, default: "1.aiff"
7
+ t.string :alert, null: true
8
+ t.text :attributes_for_device, null: true
9
+ t.integer :expiry, null: false, default: 1.day.to_i
10
+ t.boolean :delivered, null: false, default: false
11
+ t.timestamp :delivered_at, null: true
12
+ t.boolean :failed, null: false, default: false
13
+ t.timestamp :failed_at, null: true
14
+ t.integer :error_code, null: true
15
+ t.string :error_description, null: true
16
+ t.timestamp :deliver_after, null: true
17
17
  t.timestamps
18
18
  end
19
19
 
20
- add_index :rapns_notifications, [:delivered, :failed, :deliver_after], :name => 'index_rapns_notifications_multi'
20
+ add_index :rapns_notifications, [:delivered, :failed, :deliver_after], name: 'index_rapns_notifications_multi'
21
21
  end
22
22
 
23
23
  def self.down
24
24
  if index_name_exists?(:rapns_notifications, 'index_rapns_notifications_multi', true)
25
- remove_index :rapns_notifications, :name => 'index_rapns_notifications_multi'
25
+ remove_index :rapns_notifications, name: 'index_rapns_notifications_multi'
26
26
  end
27
27
  drop_table :rapns_notifications
28
28
  end
@@ -2,6 +2,12 @@
2
2
 
3
3
  Rpush.configure do |config|
4
4
 
5
+ # Supported clients are :active_record and :redis.
6
+ # config.client = :active_record
7
+
8
+ # Options passed to Redis.new
9
+ # config.redis_options = {}
10
+
5
11
  # Run in the foreground?
6
12
  # config.foreground = false
7
13
 
@@ -11,15 +17,12 @@
11
17
  # Frequency in seconds to check for feedback
12
18
  # config.feedback_poll = 60
13
19
 
14
- # Disable APNs error checking after notification delivery.
15
- # config.check_for_errors = true
16
-
17
- # ActiveRecord notifications batch size.
20
+ # The maximum number of notifications to load from the store every `push_poll` seconds.
21
+ # If some notifications are still enqueued internally, Rpush will load the batch_size less
22
+ # the number enqueued. An exception to this is if the service is able to receive multiple
23
+ # notification payloads over the connection with a single write, such as APNs.
18
24
  # config.batch_size = 100
19
25
 
20
- # Perform updates to the storage backend in batches to reduce IO.
21
- # config.batch_storage_updates = true
22
-
23
26
  # Path to write PID file. Relative to Rails root unless absolute.
24
27
  # config.pid_file = '/path/to/rpush.pid'
25
28
 
@@ -56,12 +59,22 @@ Rpush.reflect do |on|
56
59
  # on.notification_failed do |notification|
57
60
  # end
58
61
 
62
+ # Called when the notification delivery failed and only the notification ID
63
+ # is present in memory.
64
+ # on.notification_id_failed do |app, notification_id, error_code, error_description|
65
+ # end
66
+
59
67
  # Called when a notification will be retried at a later date.
60
68
  # Call 'deliver_after' on the notification for the next delivery date
61
69
  # and 'retries' for the number of times this notification has been retried.
62
70
  # on.notification_will_retry do |notification|
63
71
  # end
64
72
 
73
+ # Called when a notification will be retried and only the notification ID
74
+ # is present in memory.
75
+ # on.notification_id_will_retry do |app, notification_id, retry_after|
76
+ # end
77
+
65
78
  # Called when a TCP connection is lost and will be reconnected.
66
79
  # on.tcp_connection_lost do |app, error|
67
80
  # end
@@ -98,6 +111,14 @@ Rpush.reflect do |on|
98
111
  # on.adm_canonical_id do |old_id, canonical_id|
99
112
  # end
100
113
 
114
+ # Called when Failed to deliver to ADM. Check the 'reason' string for further
115
+ # explanations.
116
+ #
117
+ # If the reason is the string 'Unregistered', you should remove
118
+ # this registration id from your records.
119
+ # on.adm_failed_to_recipient do |notification, registration_id, reason|
120
+ # end
121
+
101
122
  # Called when an exception is raised.
102
123
  # on.error do |error|
103
124
  # end
@@ -0,0 +1,42 @@
1
+ class Rpush200Updates < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :rpush_notifications, :processing, :boolean, null: false, default: false
4
+ add_column :rpush_notifications, :priority, :integer, null: true
5
+
6
+ if index_name_exists?(:rpush_notifications, :index_rpush_notifications_multi, true)
7
+ remove_index :rpush_notifications, name: :index_rpush_notifications_multi
8
+ end
9
+
10
+ add_index :rpush_notifications, [:delivered, :failed], name: 'index_rpush_notifications_multi', where: 'NOT delivered AND NOT failed'
11
+
12
+ rename_column :rpush_feedback, :app, :app_id
13
+
14
+ if postgresql?
15
+ execute('ALTER TABLE rpush_feedback ALTER COLUMN app_id TYPE integer USING (trim(app_id)::integer)')
16
+ else
17
+ change_column :rpush_feedback, :app_id, :integer
18
+ end
19
+ end
20
+
21
+ def self.down
22
+ change_column :rpush_feedback, :app_id, :string
23
+ rename_column :rpush_feedback, :app_id, :app
24
+
25
+ if index_name_exists?(:rpush_notifications, :index_rpush_notifications_multi, true)
26
+ remove_index :rpush_notifications, name: :index_rpush_notifications_multi
27
+ end
28
+
29
+ add_index :rpush_notifications, [:app_id, :delivered, :failed, :deliver_after], name: 'index_rpush_notifications_multi'
30
+
31
+ remove_column :rpush_notifications, :priority
32
+ remove_column :rpush_notifications, :processing
33
+ end
34
+
35
+ def self.adapter_name
36
+ ActiveRecord::Base.configurations[Rails.env]['adapter']
37
+ end
38
+
39
+ def self.postgresql?
40
+ adapter_name =~ /postgresql/
41
+ end
42
+ end
@@ -0,0 +1,23 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveModel
4
+ module Adm
5
+ module App
6
+ def self.included(base)
7
+ base.instance_eval do
8
+ validates :client_id, :client_secret, presence: true
9
+ end
10
+ end
11
+
12
+ def access_token_expired?
13
+ access_token_expiration.nil? || access_token_expiration < Time.now
14
+ end
15
+
16
+ def service_name
17
+ 'adm'
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,14 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveModel
4
+ module Adm
5
+ class DataValidator < ::ActiveModel::Validator
6
+ def validate(record)
7
+ return unless record.collapse_key.nil? && record.data.nil?
8
+ record.errors[:data] << 'must be set unless collapse_key is specified'
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,28 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveModel
4
+ module Adm
5
+ module Notification
6
+ def self.included(base)
7
+ base.instance_eval do
8
+ validates :registration_ids, presence: true
9
+
10
+ validates_with Rpush::Client::ActiveModel::PayloadDataSizeValidator, limit: 6144
11
+ validates_with Rpush::Client::ActiveModel::RegistrationIdsCountValidator, limit: 100
12
+
13
+ validates_with Rpush::Client::ActiveModel::Adm::DataValidator
14
+ end
15
+ end
16
+
17
+ def as_json
18
+ json = { 'data' => data }
19
+ json['consolidationKey'] = collapse_key if collapse_key
20
+ # number of seconds before message is expired
21
+ json['expiresAfter'] = expiry if expiry
22
+ json
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,37 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveModel
4
+ module Apns
5
+ module App
6
+ def self.included(base)
7
+ base.instance_eval do
8
+ validates :environment, presence: true, inclusion: { in: %w(development production sandbox) }
9
+ validates :certificate, presence: true
10
+ validate :certificate_has_matching_private_key
11
+ end
12
+ end
13
+
14
+ def service_name
15
+ 'apns'
16
+ end
17
+
18
+ private
19
+
20
+ def certificate_has_matching_private_key
21
+ result = false
22
+ if certificate.present?
23
+ begin
24
+ x509 = OpenSSL::X509::Certificate.new(certificate)
25
+ pkey = OpenSSL::PKey::RSA.new(certificate, password)
26
+ result = x509 && pkey
27
+ rescue OpenSSL::OpenSSLError
28
+ errors.add :certificate, 'Certificate value must contain a certificate and a private key.'
29
+ end
30
+ end
31
+ result
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,16 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveModel
4
+ module Apns
5
+ class BinaryNotificationValidator < ::ActiveModel::Validator
6
+ MAX_BYTES = 256
7
+
8
+ def validate(record)
9
+ return unless record.payload_size > MAX_BYTES
10
+ record.errors[:base] << "APN notification cannot be larger than #{MAX_BYTES} bytes. Try condensing your alert and device attributes."
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveModel
4
+ module Apns
5
+ class DeviceTokenFormatValidator < ::ActiveModel::Validator
6
+ def validate(record)
7
+ return if record.device_token =~ /^[a-z0-9]{64}$/i
8
+ record.errors[:device_token] << "is invalid"
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,90 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveModel
4
+ module Apns
5
+ module Notification
6
+ APNS_DEFAULT_EXPIRY = 1.day.to_i
7
+ APNS_PRIORITY_IMMEDIATE = 10
8
+ APNS_PRIORITY_CONSERVE_POWER = 5
9
+ APNS_PRIORITIES = [APNS_PRIORITY_IMMEDIATE, APNS_PRIORITY_CONSERVE_POWER]
10
+
11
+ def self.included(base)
12
+ base.instance_eval do
13
+ validates :device_token, presence: true
14
+ validates :badge, numericality: true, allow_nil: true
15
+ validates :priority, inclusion: { in: APNS_PRIORITIES }, allow_nil: true
16
+
17
+ validates_with Rpush::Client::ActiveModel::Apns::DeviceTokenFormatValidator
18
+ validates_with Rpush::Client::ActiveModel::Apns::BinaryNotificationValidator
19
+
20
+ base.const_set('APNS_DEFAULT_EXPIRY', APNS_DEFAULT_EXPIRY) unless base.const_defined?('APNS_DEFAULT_EXPIRY')
21
+ base.const_set('APNS_PRIORITY_IMMEDIATE', APNS_PRIORITY_IMMEDIATE) unless base.const_defined?('APNS_PRIORITY_IMMEDIATE')
22
+ base.const_set('APNS_PRIORITY_CONSERVE_POWER', APNS_PRIORITY_CONSERVE_POWER) unless base.const_defined?('APNS_PRIORITY_CONSERVE_POWER')
23
+ end
24
+ end
25
+
26
+ def device_token=(token)
27
+ write_attribute(:device_token, token.delete(" <>")) unless token.nil?
28
+ end
29
+
30
+ MDM_KEY = '__rpush_mdm__'
31
+ def mdm=(magic)
32
+ self.data = (data || {}).merge(MDM_KEY => magic)
33
+ end
34
+
35
+ CONTENT_AVAILABLE_KEY = '__rpush_content_available__'
36
+ def content_available=(bool)
37
+ return unless bool
38
+ self.data = (data || {}).merge(CONTENT_AVAILABLE_KEY => true)
39
+ end
40
+
41
+ def as_json # rubocop:disable Metrics/PerceivedComplexity
42
+ json = ActiveSupport::OrderedHash.new
43
+
44
+ if data && data.key?(MDM_KEY)
45
+ json['mdm'] = data[MDM_KEY]
46
+ else
47
+ json['aps'] = ActiveSupport::OrderedHash.new
48
+ json['aps']['alert'] = alert if alert
49
+ json['aps']['badge'] = badge if badge
50
+ json['aps']['sound'] = sound if sound
51
+
52
+ if data && data[CONTENT_AVAILABLE_KEY]
53
+ json['aps']['content-available'] = 1
54
+ end
55
+
56
+ if data
57
+ non_aps_attributes = data.reject { |k, _| k == CONTENT_AVAILABLE_KEY }
58
+ non_aps_attributes.each { |k, v| json[k.to_s] = v }
59
+ end
60
+ end
61
+
62
+ json
63
+ end
64
+
65
+ def to_binary(options = {})
66
+ frame_id = options[:for_validation] ? 0 : id
67
+ frame = ""
68
+ frame << [1, 32, device_token].pack("cnH*")
69
+ frame << [2, payload.bytesize, payload].pack("cna*")
70
+ frame << [3, 4, frame_id].pack("cnN")
71
+ frame << [4, 4, expiry || APNS_DEFAULT_EXPIRY].pack("cnN")
72
+ frame << [5, 1, priority_for_frame].pack("cnc")
73
+ [2, frame.bytesize].pack("cN") + frame
74
+ end
75
+
76
+ private
77
+
78
+ def priority_for_frame
79
+ # It is an error to use APNS_PRIORITY_IMMEDIATE for a notification that only contains content-available.
80
+ if as_json['aps'].keys == ['content-available']
81
+ APNS_PRIORITY_CONSERVE_POWER
82
+ else
83
+ priority || APNS_PRIORITY_IMMEDIATE
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,19 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveModel
4
+ module Gcm
5
+ module App
6
+ def self.included(base)
7
+ base.instance_eval do
8
+ validates :auth_key, presence: true
9
+ end
10
+ end
11
+
12
+ def service_name
13
+ 'gcm'
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveModel
4
+ module Gcm
5
+ class ExpiryCollapseKeyMutualInclusionValidator < ::ActiveModel::Validator
6
+ def validate(record)
7
+ return unless record.collapse_key && !record.expiry
8
+ record.errors[:expiry] << 'must be set when using a collapse_key'
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,31 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveModel
4
+ module Gcm
5
+ module Notification
6
+ def self.included(base)
7
+ base.instance_eval do
8
+ validates :registration_ids, presence: true
9
+
10
+ validates_with Rpush::Client::ActiveModel::PayloadDataSizeValidator, limit: 4096
11
+ validates_with Rpush::Client::ActiveModel::RegistrationIdsCountValidator, limit: 1000
12
+
13
+ validates_with Rpush::Client::ActiveModel::Gcm::ExpiryCollapseKeyMutualInclusionValidator
14
+ end
15
+ end
16
+
17
+ def as_json
18
+ json = {
19
+ 'registration_ids' => registration_ids,
20
+ 'delay_while_idle' => delay_while_idle,
21
+ 'data' => data
22
+ }
23
+ json['collapse_key'] = collapse_key if collapse_key
24
+ json['time_to_live'] = expiry if expiry
25
+ json
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveModel
4
+ module Notification
5
+ def self.included(base)
6
+ base.instance_eval do
7
+ validates :expiry, numericality: true, allow_nil: true
8
+ validates :app, presence: true
9
+ end
10
+ end
11
+
12
+ def payload
13
+ multi_json_dump(as_json)
14
+ end
15
+
16
+ def payload_size
17
+ payload.bytesize
18
+ end
19
+
20
+ def payload_data_size
21
+ multi_json_dump(as_json['data']).bytesize
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveModel
4
+ class PayloadDataSizeValidator < ::ActiveModel::Validator
5
+ def validate(record)
6
+ limit = options[:limit] || 1024
7
+ return unless record.data && record.payload_data_size > limit
8
+ record.errors[:base] << "Notification payload data cannot be larger than #{limit} bytes."
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveModel
4
+ class RegistrationIdsCountValidator < ::ActiveModel::Validator
5
+ def validate(record)
6
+ limit = options[:limit] || 100
7
+ return unless record.registration_ids && record.registration_ids.size > limit
8
+ record.errors[:base] << "Number of registration_ids cannot be larger than #{limit}."
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveModel
4
+ module Wpns
5
+ module App
6
+ def service_name
7
+ 'wpns'
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveModel
4
+ module Wpns
5
+ module Notification
6
+ def self.included(base)
7
+ base.instance_eval do
8
+ validates :uri, presence: true
9
+ validates :uri, format: { with: %r{https?://[\S]+} }
10
+ validates :alert, presence: true
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ require 'active_model'
2
+
3
+ require 'rpush/client/active_model/notification'
4
+ require 'rpush/client/active_model/payload_data_size_validator'
5
+ require 'rpush/client/active_model/registration_ids_count_validator'
6
+
7
+ require 'rpush/client/active_model/apns/binary_notification_validator'
8
+ require 'rpush/client/active_model/apns/device_token_format_validator'
9
+ require 'rpush/client/active_model/apns/app'
10
+ require 'rpush/client/active_model/apns/notification'
11
+
12
+ require 'rpush/client/active_model/adm/data_validator'
13
+ require 'rpush/client/active_model/adm/app'
14
+ require 'rpush/client/active_model/adm/notification'
15
+
16
+ require 'rpush/client/active_model/gcm/expiry_collapse_key_mutual_inclusion_validator'
17
+ require 'rpush/client/active_model/gcm/app'
18
+ require 'rpush/client/active_model/gcm/notification'
19
+
20
+ require 'rpush/client/active_model/wpns/app'
21
+ require 'rpush/client/active_model/wpns/notification'
@@ -0,0 +1,11 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveRecord
4
+ module Adm
5
+ class App < Rpush::Client::ActiveRecord::App
6
+ include Rpush::Client::ActiveModel::Adm::App
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveRecord
4
+ module Adm
5
+ class Notification < Rpush::Client::ActiveRecord::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 ActiveRecord
4
+ module Apns
5
+ class App < Rpush::Client::ActiveRecord::App
6
+ include Rpush::Client::ActiveModel::Apns::App
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end