rpush 7.0.1 → 9.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -4
  3. data/README.md +24 -44
  4. data/lib/generators/rpush_migration_generator.rb +1 -0
  5. data/lib/generators/templates/rpush.rb +23 -13
  6. data/lib/generators/templates/rpush_7_1_0_updates.rb +12 -0
  7. data/lib/rpush/client/active_model/apns/notification.rb +0 -4
  8. data/lib/rpush/client/active_model/{gcm → fcm}/app.rb +4 -3
  9. data/lib/rpush/client/active_model/{gcm → fcm}/expiry_collapse_key_mutual_inclusion_validator.rb +1 -1
  10. data/lib/rpush/client/active_model/fcm/notification.rb +129 -0
  11. data/lib/rpush/client/active_model/fcm/notification_keys_in_allowed_list_validator.rb +20 -0
  12. data/lib/rpush/client/active_model.rb +4 -3
  13. data/lib/rpush/client/active_record/{gcm → fcm}/app.rb +2 -2
  14. data/lib/rpush/client/active_record/{gcm → fcm}/notification.rb +2 -2
  15. data/lib/rpush/client/active_record.rb +2 -2
  16. data/lib/rpush/client/redis/app.rb +2 -0
  17. data/lib/rpush/client/redis/{gcm → fcm}/app.rb +2 -2
  18. data/lib/rpush/client/redis/{gcm → fcm}/notification.rb +2 -2
  19. data/lib/rpush/client/redis.rb +2 -2
  20. data/lib/rpush/configuration.rb +2 -19
  21. data/lib/rpush/daemon/apns2/delivery.rb +0 -1
  22. data/lib/rpush/daemon/apnsp8/delivery.rb +0 -1
  23. data/lib/rpush/daemon/fcm/delivery.rb +162 -0
  24. data/lib/rpush/daemon/{gcm.rb → fcm.rb} +1 -1
  25. data/lib/rpush/daemon/google_credential_cache.rb +41 -0
  26. data/lib/rpush/daemon/service_config_methods.rb +0 -2
  27. data/lib/rpush/daemon/store/active_record.rb +15 -12
  28. data/lib/rpush/daemon/store/interface.rb +3 -3
  29. data/lib/rpush/daemon/store/redis.rb +13 -9
  30. data/lib/rpush/daemon/webpush/delivery.rb +2 -2
  31. data/lib/rpush/daemon.rb +3 -9
  32. data/lib/rpush/reflection_collection.rb +3 -3
  33. data/lib/rpush/version.rb +2 -2
  34. data/lib/rpush.rb +1 -1
  35. data/spec/functional/apns2_spec.rb +2 -6
  36. data/spec/functional/cli_spec.rb +41 -15
  37. data/spec/functional/embed_spec.rb +57 -26
  38. data/spec/functional/{gcm_priority_spec.rb → fcm_priority_spec.rb} +13 -7
  39. data/spec/functional/fcm_spec.rb +77 -0
  40. data/spec/functional/retry_spec.rb +21 -4
  41. data/spec/functional/synchronization_spec.rb +1 -1
  42. data/spec/functional_spec_helper.rb +1 -7
  43. data/spec/spec_helper.rb +4 -1
  44. data/spec/support/active_record_setup.rb +3 -1
  45. data/spec/unit/client/active_record/{gcm → fcm}/app_spec.rb +2 -2
  46. data/spec/unit/client/active_record/fcm/notification_spec.rb +10 -0
  47. data/spec/unit/client/active_record/shared/app.rb +1 -1
  48. data/spec/unit/client/redis/fcm/app_spec.rb +5 -0
  49. data/spec/unit/client/redis/fcm/notification_spec.rb +5 -0
  50. data/spec/unit/client/shared/apns/notification.rb +0 -15
  51. data/spec/unit/client/shared/fcm/app.rb +4 -0
  52. data/spec/unit/client/shared/fcm/notification.rb +92 -0
  53. data/spec/unit/configuration_spec.rb +1 -1
  54. data/spec/unit/daemon/apnsp8/delivery_spec.rb +1 -1
  55. data/spec/unit/daemon/fcm/delivery_spec.rb +127 -0
  56. data/spec/unit/daemon/service_config_methods_spec.rb +1 -1
  57. data/spec/unit/daemon/shared/store.rb +0 -42
  58. data/spec/unit/daemon/wns/delivery_spec.rb +1 -1
  59. data/spec/unit/logger_spec.rb +1 -1
  60. data/spec/unit_spec_helper.rb +1 -1
  61. metadata +127 -69
  62. data/lib/rpush/apns_feedback.rb +0 -18
  63. data/lib/rpush/client/active_model/gcm/notification.rb +0 -62
  64. data/lib/rpush/daemon/apns/delivery.rb +0 -43
  65. data/lib/rpush/daemon/apns/feedback_receiver.rb +0 -91
  66. data/lib/rpush/daemon/apns.rb +0 -17
  67. data/lib/rpush/daemon/dispatcher/apns_tcp.rb +0 -152
  68. data/lib/rpush/daemon/dispatcher/tcp.rb +0 -22
  69. data/lib/rpush/daemon/gcm/delivery.rb +0 -241
  70. data/lib/rpush/daemon/tcp_connection.rb +0 -190
  71. data/spec/functional/apns_spec.rb +0 -162
  72. data/spec/functional/gcm_spec.rb +0 -46
  73. data/spec/functional/new_app_spec.rb +0 -44
  74. data/spec/unit/apns_feedback_spec.rb +0 -39
  75. data/spec/unit/client/active_record/gcm/notification_spec.rb +0 -14
  76. data/spec/unit/client/redis/gcm/app_spec.rb +0 -5
  77. data/spec/unit/client/redis/gcm/notification_spec.rb +0 -5
  78. data/spec/unit/client/shared/gcm/app.rb +0 -4
  79. data/spec/unit/client/shared/gcm/notification.rb +0 -77
  80. data/spec/unit/daemon/apns/delivery_spec.rb +0 -108
  81. data/spec/unit/daemon/apns/feedback_receiver_spec.rb +0 -137
  82. data/spec/unit/daemon/dispatcher/tcp_spec.rb +0 -32
  83. data/spec/unit/daemon/gcm/delivery_spec.rb +0 -387
  84. data/spec/unit/daemon/tcp_connection_spec.rb +0 -292
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 409c28bf9f63343232e1c7db56f8d7131acc70b4828032059f37eab3a4606e6c
4
- data.tar.gz: 3f07d7e79828fa43ab5ed73a9b19183a9f4ac9e5a3d8891f1ecfec42c7375c03
3
+ metadata.gz: e4ab9013682357312b9f5050d6c466c62866f78c68cc0fcb72ad89ccdc4409e0
4
+ data.tar.gz: ab086d28a744140499a6434c5fcec99b6c77c4cd929163a02ac4d9d77f94bb99
5
5
  SHA512:
6
- metadata.gz: 400a7241c337ff9874767be4ee051d1494676665bd17e9b3acb2e3ce8efae236971a138888da6c0172e0c649276e97f4d639430733bad345e7980d408e8c3436
7
- data.tar.gz: e81b66da807a2bc8a386a12825aed37c452672be899b69ff633d65b80548903669e7d63b3b1eec899633557a489157e8083ed562b2665c017566df9ad220c151
6
+ metadata.gz: 862a057ab8cce2f73eff784838302ac0128214e0f744ed108b91afb33dce0867f7e7f06e131a29b46f6f49be7cca4e809f317ed37c50d1512eaa480a8ad7532d
7
+ data.tar.gz: 2f2d5cd377c79a1ec1ada2677f5c409d58d27d40a90b899b7fd43b98f122148623a0a78ca17c862b18b38245fe2df9a2f1cc7c68f25dc8cbe3dfa48a1f779c1f
data/CHANGELOG.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # Changelog
2
2
 
3
+ ## [Unreleased](https://github.com/rpush/rpush/tree/HEAD)
4
+
5
+ **Merged pull requests:**
6
+
7
+ [Full Changelog](https://github.com/rpush/rpush/compare/v9.0.0...HEAD)
8
+
9
+ ## [v9.0.0](https://github.com/rpush/rpush/tree/v9.0.0) (2024-09-09)
10
+
11
+ **Merged pull requests:**
12
+
13
+ * Support for Ruby 3.2 & 3.3 [\#679](https://github.com/rpush/rpush/pull/679) ([benlangfeld](https://github.com/benlangfeld))
14
+
15
+ **Breaking:**
16
+
17
+ * Removed legacy APNSv1 implementation (Apple binary protocol) since this was shut down in 2021. [\#680](https://github.com/rpush/rpush/pull/680) ([benlangfeld](https://github.com/benlangfeld))
18
+ * Removed legacy GCM implementation since this was shut down by Google in August 2024 and replaced by FCM (supported in RPush 8.0.0) [\#688](https://github.com/rpush/rpush/pull/688) ([benlangfeld](https://github.com/benlangfeld))
19
+ * Drop support for Ruby 2.x [\#672](https://github.com/rpush/rpush/pull/672) ([benlangfeld](https://github.com/benlangfeld))
20
+
21
+ [Full Changelog](https://github.com/rpush/rpush/compare/v8.0.0...v9.0.0)
22
+
23
+ ## [v8.0.0](https://github.com/rpush/rpush/tree/v8.0.0) (2024-09-06)
24
+
25
+ **Merged pull requests:**
26
+
27
+ * Support for FCMv1 [\#620](https://github.com/rpush/rpush/pull/620) ([mirkode](https://github.com/mirkode)), [\#660](https://github.com/rpush/rpush/pull/660) ([AnilRh](https://github.com/AnilRh)) and [\#673](https://github.com/rpush/rpush/pull/673) ([SixiS](https://github.com/SixiS), [Henridv](https://github.com/Henridv) & [benlangfeld](https://github.com/benlangfeld))
28
+ * No longer silence content-available notifications for APNs. Reverts the following change from the v6.0.0 release. See https://github.com/rpush/rpush/issues/647.
29
+ * Fix silent APNS notifications for Apns2 and Apnsp8 [\#596](https://github.com/rpush/rpush/pull/596) ([shved270189](https://github.com/shved270189))
30
+
31
+ **Breaking:**
32
+
33
+ * Dropped support for Ruby 2.4, 2.5, 2.6 and Rails 5.2.
34
+
35
+ [Full Changelog](https://github.com/rpush/rpush/compare/v7.0.1...v8.0.0)
36
+
3
37
  ## [v7.0.1](https://github.com/rpush/rpush/tree/v7.0.1) (2022-03-02)
4
38
 
5
39
  [Full Changelog](https://github.com/rpush/rpush/compare/v7.0.0...v7.0.1)
@@ -8,10 +42,6 @@
8
42
 
9
43
  - Fix deprecation warnings from the redis gem [\#636](https://github.com/rpush/rpush/pull/636) ([sharang-d](https://github.com/sharang-d))
10
44
 
11
- ## [Unreleased](https://github.com/rpush/rpush/tree/HEAD)
12
-
13
- [Full Changelog](https://github.com/rpush/rpush/compare/v7.0.0...HEAD)
14
-
15
45
  ## [v7.0.0](https://github.com/rpush/rpush/tree/HEAD)
16
46
 
17
47
  [Full Changelog](https://github.com/rpush/rpush/compare/v6.0.1...v7.0.0)
data/README.md CHANGED
@@ -57,10 +57,9 @@ There is a choice of two modes (and one legacy mode) using certificates or using
57
57
 
58
58
  * `Rpush::Apns2` This requires an annually renewable certificate. see https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/establishing_a_certificate-based_connection_to_apns
59
59
  * `Rpush::Apnsp8` This uses encrypted tokens and requires an encryption key id and encryption key (provide as a p8 file). (see https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/establishing_a_token-based_connection_to_apns)
60
- * `Rpush::Apns` There is also the original APNS (the original version using certificates with a binary underlying protocol over TCP directly rather than over Http/2).
61
60
  Apple have [announced](https://developer.apple.com/news/?id=c88acm2b) that this is not supported after March 31, 2021.
62
61
 
63
- If this is your first time using the APNs, you will need to generate either SSL certificates (for Apns2 or Apns) or an Encryption Key (p8) and an Encryption Key ID (for Apnsp8). See [Generating Certificates](https://github.com/rpush/rpush/wiki/Generating-Certificates) for instructions.
62
+ If this is your first time using the APNs, you will need to generate either SSL certificates (for standard Apns) or an Encryption Key (p8) and an Encryption Key ID (for Apnsp8). See [Generating Certificates](https://github.com/rpush/rpush/wiki/Generating-Certificates) for instructions.
64
63
 
65
64
  ##### Apnsp8
66
65
 
@@ -83,6 +82,7 @@ n = Rpush::Apnsp8::Notification.new
83
82
  n.app = Rpush::Apnsp8::App.find_by_name("ios_app")
84
83
  n.device_token = "..." # hex string
85
84
  n.alert = "hi mom!"
85
+ # n.alert = { title: "push title", subtitle: "more to say", body: "hi mom!" }
86
86
  n.data = { foo: :bar }
87
87
  n.save!
88
88
  ```
@@ -107,6 +107,7 @@ n = Rpush::Apns2::Notification.new
107
107
  n.app = Rpush::Apns2::App.find_by_name("ios_app")
108
108
  n.device_token = "..." # hex string
109
109
  n.alert = "hi mom!"
110
+ # n.alert = { title: "push title", subtitle: "more to say", body: "hi mom!" }
110
111
  n.data = {
111
112
  headers: { 'apns-topic': "BUNDLE ID" }, # the bundle id of the app, like com.example.appname. Not necessary if set on the app (see above)
112
113
  foo: :bar
@@ -116,61 +117,41 @@ n.save!
116
117
 
117
118
  You should also implement the [ssl_certificate_will_expire](https://github.com/rpush/rpush/wiki/Reflection-API) reflection to monitor when your certificate is due to expire.
118
119
 
119
- ##### Apns (legacy protocol)
120
-
121
- ```ruby
122
- app = Rpush::Apns::App.new
123
- app.name = "ios_app"
124
- app.certificate = File.read("/path/to/sandbox.pem")
125
- app.environment = "development" # APNs environment.
126
- app.password = "certificate password"
127
- app.connections = 1
128
- app.save!
129
- ```
130
-
131
- ```ruby
132
- n = Rpush::Apns::Notification.new
133
- n.app = Rpush::Apns::App.find_by_name("ios_app")
134
- n.device_token = "..." # hex string
135
- n.alert = "hi mom!"
136
- n.data = { foo: :bar }
137
- n.save!
138
- ```
139
-
140
120
  ##### Safari Push Notifications
141
121
 
142
122
  Using one of the notifications methods above, the `url_args` attribute is available for Safari Push Notifications.
143
123
 
144
124
  ##### Environment
145
125
 
146
- The app `environment` for any Apns* option is "development" for XCode installs, and "production" for app store and TestFlight. Note that for Apns2 you can now use one (production + sandbox) certificate (you don't need a separate "sandbox" or development certificate), but if you do generate a development/sandbox certificate it can only be used for "development". With Apnsp8 tokens, you can target either "development" or "production" environments.
126
+ The app `environment` for any Apns* option is "development" for XCode installs, and "production" for app store and TestFlight. Note that you can now use one (production + sandbox) certificate (you don't need a separate "sandbox" or development certificate), but if you do generate a development/sandbox certificate it can only be used for "development". With Apnsp8 tokens, you can target either "development" or "production" environments.
147
127
 
148
128
  #### Firebase Cloud Messaging
149
129
 
150
- FCM and GCM are – as of writing compatible with each other. See also [this comment](https://github.com/rpush/rpush/issues/284#issuecomment-228330206) for further references.
130
+ You will need two params to make use of FCM via Rpush.
131
+ - `firebase_project_id` - The `Project ID` in your Firebase Project Settings
132
+ - `json_key` - The JSON key file for a service account with the `Firebase Admin SDK Administrator Service Agent` role.
133
+
134
+ Create service account in the google cloud account attached to your firebase account:
135
+ https://console.cloud.google.com/iam-admin/serviceaccounts
136
+ Make sure it has Role `Firebase Admin SDK Administrator Service Agent`
137
+ Add + Download the json key for the service account.
151
138
 
152
- Please refer to the Firebase Console on where to find your `auth_key` (probably called _Server Key_ there). To verify you have the right key, use tools like [Postman](https://www.getpostman.com/), [HTTPie](https://httpie.org/), `curl` or similar before reporting a new issue. See also [this comment](https://github.com/rpush/rpush/issues/346#issuecomment-289218776).
139
+ Once you have those two params, you can create an FCM app and send notifications.
153
140
 
154
141
  ```ruby
155
- app = Rpush::Gcm::App.new
156
- app.name = "android_app"
157
- app.auth_key = "..."
158
- app.connections = 1
159
- app.save!
142
+ fcm_app = Rpush::Fcm::App.new
143
+ fcm_app.name = "fcm_app"
144
+ fcm_app.firebase_project_id = "someapp-123456"
145
+ fcm_app.json_key = Rails.root.join("your/key/somewhere.json").read # or from a ENV variable - just needs to be the whole json file
146
+ fcm_app.connections = 30
147
+ fcm_app.save!
160
148
  ```
161
149
 
162
150
  ```ruby
163
- n = Rpush::Gcm::Notification.new
164
- n.app = Rpush::Gcm::App.find_by_name("android_app")
165
- n.registration_ids = ["..."]
166
- n.data = { message: "hi mom!" }
167
- n.priority = 'high' # Optional, can be either 'normal' or 'high'
168
- n.content_available = true # Optional
169
- # Optional notification payload. See the reference below for more keys you can use!
170
- n.notification = { body: 'great match!',
171
- title: 'Portugal vs. Denmark',
172
- icon: 'myicon'
173
- }
151
+ n = Rpush::Fcm::Notification.new
152
+ n.app = Rpush::Fcm::App.where(name: "fcm_app").first
153
+ n.device_token = device_token # Note that device_token is used here instead of registration_ids
154
+ n.data = {}.transform_values(&:to_s) # All values going in here have to be strings, if you have anything else - nothing goes through
174
155
  n.save!
175
156
  ```
176
157
 
@@ -374,7 +355,6 @@ Rpush will deliver all pending notifications and then exit.
374
355
 
375
356
  ```ruby
376
357
  Rpush.push
377
- Rpush.apns_feedback
378
358
  ```
379
359
 
380
360
  See [Push API](https://github.com/rpush/rpush/wiki/Push-API) for more details.
@@ -470,7 +450,7 @@ This will run RSpec against all versions of Rails.
470
450
  You need to specify a `BUNDLE_GEMFILE` pointing to the gemfile before running the normal test command:
471
451
 
472
452
  ```
473
- BUNDLE_GEMFILE=gemfiles/rails_5.2.gemfile rspec spec/unit/apns_feedback_spec.rb
453
+ BUNDLE_GEMFILE=gemfiles/rails_6.0.gemfile rspec spec/unit/apns_feedback_spec.rb
474
454
  ```
475
455
 
476
456
  ##### Multiple database adapter support
@@ -53,6 +53,7 @@ class RpushMigrationGenerator < Rails::Generators::Base
53
53
  add_rpush_migration('rpush_4_1_0_updates')
54
54
  add_rpush_migration('rpush_4_1_1_updates')
55
55
  add_rpush_migration('rpush_4_2_0_updates')
56
+ add_rpush_migration('rpush_7_1_0_updates')
56
57
  end
57
58
 
58
59
  protected
@@ -30,9 +30,6 @@ Rpush.configure do |config|
30
30
  # If the logger goes to stdout, you can disable foreground logging to avoid duplication.
31
31
  # config.foreground_logging = false
32
32
 
33
- # config.apns.feedback_receiver.enabled = true
34
- # config.apns.feedback_receiver.frequency = 60
35
-
36
33
  end
37
34
 
38
35
  Rpush.reflect do |on|
@@ -76,30 +73,43 @@ Rpush.reflect do |on|
76
73
  # on.notification_id_will_retry do |app, notification_id, retry_after|
77
74
  # end
78
75
 
79
- # Called when a TCP connection is lost and will be reconnected.
80
- # on.tcp_connection_lost do |app, error|
76
+ # Called for each recipient which successfully receives a notification. This
77
+ # can occur more than once for the same notification when there are multiple
78
+ # recipients.
79
+ # on.fcm_delivered_to_recipient do |notification|
80
+ # end
81
+
82
+ # Called for each recipient which fails to receive a notification. This
83
+ # can occur more than once for the same notification when there are multiple
84
+ # recipients. (do not handle invalid device tokens here)
85
+ # on.fcm_failed_to_recipient do |notification, error|
86
+ # end
87
+
88
+ # Called when the FCM returns a failure that indicates an invalid device token.
89
+ # You will need to delete the device token from your records.
90
+ # on.fcm_invalid_device_token do |app, error, device_token|
81
91
  # end
82
92
 
83
93
  # Called for each recipient which successfully receives a notification. This
84
94
  # can occur more than once for the same notification when there are multiple
85
95
  # recipients.
86
- # on.gcm_delivered_to_recipient do |notification, registration_id|
96
+ # on.fcm_delivered_to_recipient do |notification, device_token|
87
97
  # end
88
98
 
89
99
  # Called for each recipient which fails to receive a notification. This
90
100
  # can occur more than once for the same notification when there are multiple
91
- # recipients. (do not handle invalid registration IDs here)
92
- # on.gcm_failed_to_recipient do |notification, error, registration_id|
101
+ # recipients. (do not handle invalid device tokens here)
102
+ # on.fcm_failed_to_recipient do |notification, error, device_token|
93
103
  # end
94
104
 
95
- # Called when the GCM returns a canonical registration ID.
105
+ # Called when the FCM returns a canonical device token.
96
106
  # You will need to replace old_id with canonical_id in your records.
97
- # on.gcm_canonical_id do |old_id, canonical_id|
107
+ # on.fcm_canonical_id do |old_id, canonical_id|
98
108
  # end
99
109
 
100
- # Called when the GCM returns a failure that indicates an invalid registration id.
101
- # You will need to delete the registration_id from your records.
102
- # on.gcm_invalid_registration_id do |app, error, registration_id|
110
+ # Called when the FCM returns a failure that indicates an invalid device token.
111
+ # You will need to delete the device_token from your records.
112
+ # on.fcm_invalid_device_token do |app, error, device_token|
103
113
  # end
104
114
 
105
115
  # Called when an SSL certificate will expire within 1 month.
@@ -0,0 +1,12 @@
1
+ class Rpush710Updates < ActiveRecord::Migration["#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"]
2
+ def self.up
3
+ add_column :rpush_apps, :firebase_project_id, :string
4
+ add_column :rpush_apps, :json_key, :text
5
+ end
6
+
7
+ def self.down
8
+ remove_column :rpush_apps, :firebase_project_id
9
+ remove_column :rpush_apps, :json_key
10
+ end
11
+ end
12
+
@@ -52,10 +52,6 @@ module Rpush
52
52
  self.data = (data || {}).merge(CONTENT_AVAILABLE_KEY => true)
53
53
  end
54
54
 
55
- def content_available?
56
- (self.data || {})[CONTENT_AVAILABLE_KEY]
57
- end
58
-
59
55
  def as_json(options = nil) # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
60
56
  json = ActiveSupport::OrderedHash.new
61
57
 
@@ -1,16 +1,17 @@
1
1
  module Rpush
2
2
  module Client
3
3
  module ActiveModel
4
- module Gcm
4
+ module Fcm
5
5
  module App
6
6
  def self.included(base)
7
7
  base.instance_eval do
8
- validates :auth_key, presence: true
8
+ # TODO: Add whatever validation is needed here
9
+ # validates :auth_key, presence: true
9
10
  end
10
11
  end
11
12
 
12
13
  def service_name
13
- 'gcm'
14
+ 'fcm'
14
15
  end
15
16
  end
16
17
  end
@@ -1,7 +1,7 @@
1
1
  module Rpush
2
2
  module Client
3
3
  module ActiveModel
4
- module Gcm
4
+ module Fcm
5
5
  class ExpiryCollapseKeyMutualInclusionValidator < ::ActiveModel::Validator
6
6
  def validate(record)
7
7
  return unless record.collapse_key && !record.expiry
@@ -0,0 +1,129 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveModel
4
+ module Fcm
5
+ module Notification
6
+ FCM_PRIORITY_HIGH = Rpush::Client::ActiveModel::Apns::Notification::APNS_PRIORITY_IMMEDIATE
7
+ FCM_PRIORITY_NORMAL = Rpush::Client::ActiveModel::Apns::Notification::APNS_PRIORITY_CONSERVE_POWER
8
+ FCM_PRIORITIES = [FCM_PRIORITY_HIGH, FCM_PRIORITY_NORMAL]
9
+
10
+ ROOT_NOTIFICATION_KEYS = %w[title body image].freeze
11
+ ANDROID_NOTIFICATION_KEYS = %w[icon tag color click_action body_loc_key body_loc_args title_loc_key
12
+ title_loc_args channel_id ticker sticky event_time local_only
13
+ default_vibrate_timings default_light_settings vibrate_timings
14
+ visibility notification_count light_settings].freeze
15
+
16
+ def self.included(base)
17
+ base.instance_eval do
18
+ validates :device_token, presence: true
19
+ validates :priority, inclusion: { in: FCM_PRIORITIES }, allow_nil: true
20
+
21
+ validates_with Rpush::Client::ActiveModel::PayloadDataSizeValidator, limit: 4096
22
+ validates_with Rpush::Client::ActiveModel::RegistrationIdsCountValidator, limit: 1000
23
+
24
+ validates_with Rpush::Client::ActiveModel::Fcm::ExpiryCollapseKeyMutualInclusionValidator
25
+ validates_with Rpush::Client::ActiveModel::Fcm::NotificationKeysInAllowedListValidator
26
+ end
27
+ end
28
+
29
+ def payload_data_size
30
+ multi_json_dump(as_json['message']['data']).bytesize
31
+ end
32
+
33
+ # This is a hack. The schema defines `priority` to be an integer, but FCM expects a string.
34
+ # But for users of rpush to have an API they might expect (setting priority to `high`, not 10)
35
+ # we do a little conversion here.
36
+ def priority=(priority)
37
+ case priority
38
+ when 'high', FCM_PRIORITY_HIGH
39
+ super(FCM_PRIORITY_HIGH)
40
+ when 'normal', FCM_PRIORITY_NORMAL
41
+ super(FCM_PRIORITY_NORMAL)
42
+ else
43
+ errors.add(:priority, 'must be one of either "normal" or "high"')
44
+ end
45
+ end
46
+
47
+ def dry_run=(value)
48
+ fail ArgumentError, 'FCM does not support dry run' if value
49
+ end
50
+
51
+ def as_json(options = nil) # rubocop:disable Metrics/PerceivedComplexity
52
+ json = {
53
+ 'data' => data,
54
+ 'android' => android_config,
55
+ 'apns' => apns_config,
56
+ 'token' => device_token
57
+ }
58
+
59
+ json['notification'] = root_notification if notification
60
+ { 'message' => json }
61
+ end
62
+
63
+ def android_config
64
+ json = ActiveSupport::OrderedHash.new
65
+ json['notification'] = android_notification if notification
66
+ json['collapse_key'] = collapse_key if collapse_key
67
+ json['priority'] = priority_str if priority
68
+ json['ttl'] = "#{expiry}s" if expiry
69
+ json
70
+ end
71
+
72
+ def apns_config
73
+ json = ActiveSupport::OrderedHash.new
74
+ json['payload'] = ActiveSupport::OrderedHash.new
75
+
76
+ aps = ActiveSupport::OrderedHash.new
77
+ aps['mutable-content'] = 1 if mutable_content
78
+ aps['content-available'] = 1 if content_available
79
+ aps['sound'] = 'default' if sound == 'default'
80
+
81
+ json['payload']['aps'] = aps
82
+
83
+ json
84
+ end
85
+
86
+ def notification=(value)
87
+ value = value.with_indifferent_access if value.is_a?(Hash)
88
+ super(value)
89
+ end
90
+
91
+ def root_notification
92
+ return {} unless notification
93
+
94
+ notification.slice(*ROOT_NOTIFICATION_KEYS)
95
+ end
96
+
97
+ def android_notification
98
+ json = notification&.slice(*ANDROID_NOTIFICATION_KEYS) || {}
99
+ json['notification_priority'] = priority_for_notification if priority
100
+ json['sound'] = sound if sound
101
+ json['default_sound'] = sound == 'default' ? true : false
102
+ json
103
+ end
104
+
105
+ def priority_str
106
+ case
107
+ when priority <= 5 then 'normal'
108
+ else
109
+ 'high'
110
+ end
111
+ end
112
+
113
+ def priority_for_notification
114
+ case priority
115
+ when 0 then 'PRIORITY_UNSPECIFIED'
116
+ when 1 then 'PRIORITY_MIN'
117
+ when 2 then 'PRIORITY_LOW'
118
+ when 5 then 'PRIORITY_DEFAULT'
119
+ when 6 then 'PRIORITY_HIGH'
120
+ when 10 then 'PRIORITY_MAX'
121
+ else
122
+ 'PRIORITY_DEFAULT'
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,20 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveModel
4
+ module Fcm
5
+ class NotificationKeysInAllowedListValidator < ::ActiveModel::Validator
6
+ def validate(record)
7
+ return unless record.notification
8
+
9
+ allowed_keys = Notification::ROOT_NOTIFICATION_KEYS + Notification::ANDROID_NOTIFICATION_KEYS
10
+ invalid_keys = record.notification.keys - allowed_keys
11
+
12
+ return if invalid_keys.empty?
13
+
14
+ record.errors.add(:notification, "contains invalid keys: #{invalid_keys.join(', ')}")
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -20,9 +20,10 @@ require 'rpush/client/active_model/adm/data_validator'
20
20
  require 'rpush/client/active_model/adm/app'
21
21
  require 'rpush/client/active_model/adm/notification'
22
22
 
23
- require 'rpush/client/active_model/gcm/expiry_collapse_key_mutual_inclusion_validator'
24
- require 'rpush/client/active_model/gcm/app'
25
- require 'rpush/client/active_model/gcm/notification'
23
+ require 'rpush/client/active_model/fcm/expiry_collapse_key_mutual_inclusion_validator'
24
+ require 'rpush/client/active_model/fcm/notification_keys_in_allowed_list_validator'
25
+ require 'rpush/client/active_model/fcm/app'
26
+ require 'rpush/client/active_model/fcm/notification'
26
27
 
27
28
  require 'rpush/client/active_model/wpns/app'
28
29
  require 'rpush/client/active_model/wpns/notification'
@@ -1,9 +1,9 @@
1
1
  module Rpush
2
2
  module Client
3
3
  module ActiveRecord
4
- module Gcm
4
+ module Fcm
5
5
  class App < Rpush::Client::ActiveRecord::App
6
- include Rpush::Client::ActiveModel::Gcm::App
6
+ include Rpush::Client::ActiveModel::Fcm::App
7
7
  end
8
8
  end
9
9
  end
@@ -1,9 +1,9 @@
1
1
  module Rpush
2
2
  module Client
3
3
  module ActiveRecord
4
- module Gcm
4
+ module Fcm
5
5
  class Notification < Rpush::Client::ActiveRecord::Notification
6
- include Rpush::Client::ActiveModel::Gcm::Notification
6
+ include Rpush::Client::ActiveModel::Fcm::Notification
7
7
  end
8
8
  end
9
9
  end
@@ -16,8 +16,8 @@ require 'rpush/client/active_record/apns2/app'
16
16
  require 'rpush/client/active_record/apnsp8/notification'
17
17
  require 'rpush/client/active_record/apnsp8/app'
18
18
 
19
- require 'rpush/client/active_record/gcm/notification'
20
- require 'rpush/client/active_record/gcm/app'
19
+ require 'rpush/client/active_record/fcm/notification'
20
+ require 'rpush/client/active_record/fcm/app'
21
21
 
22
22
  require 'rpush/client/active_record/wpns/notification'
23
23
  require 'rpush/client/active_record/wpns/app'
@@ -19,6 +19,8 @@ module Rpush
19
19
  attribute :team_id, :string
20
20
  attribute :bundle_id, :string
21
21
  attribute :feedback_enabled, :boolean, default: true
22
+ attribute :firebase_project_id, :string
23
+ attribute :json_key, :string
22
24
 
23
25
  index :name
24
26
 
@@ -1,9 +1,9 @@
1
1
  module Rpush
2
2
  module Client
3
3
  module Redis
4
- module Gcm
4
+ module Fcm
5
5
  class App < Rpush::Client::Redis::App
6
- include Rpush::Client::ActiveModel::Gcm::App
6
+ include Rpush::Client::ActiveModel::Fcm::App
7
7
  end
8
8
  end
9
9
  end
@@ -1,9 +1,9 @@
1
1
  module Rpush
2
2
  module Client
3
3
  module Redis
4
- module Gcm
4
+ module Fcm
5
5
  class Notification < Rpush::Client::Redis::Notification
6
- include Rpush::Client::ActiveModel::Gcm::Notification
6
+ include Rpush::Client::ActiveModel::Fcm::Notification
7
7
  end
8
8
  end
9
9
  end
@@ -27,8 +27,8 @@ require 'rpush/client/redis/apns2/notification'
27
27
  require 'rpush/client/redis/apnsp8/app'
28
28
  require 'rpush/client/redis/apnsp8/notification'
29
29
 
30
- require 'rpush/client/redis/gcm/app'
31
- require 'rpush/client/redis/gcm/notification'
30
+ require 'rpush/client/redis/fcm/app'
31
+ require 'rpush/client/redis/fcm/notification'
32
32
 
33
33
  require 'rpush/client/redis/adm/app'
34
34
  require 'rpush/client/redis/adm/notification'
@@ -16,27 +16,12 @@ module Rpush
16
16
  end
17
17
  end
18
18
 
19
- CURRENT_ATTRS = [:push_poll, :embedded, :pid_file, :batch_size, :push, :client, :logger, :log_file, :foreground, :foreground_logging, :log_level, :plugin, :apns]
19
+ CURRENT_ATTRS = [:push_poll, :embedded, :pid_file, :batch_size, :push, :client, :logger, :log_file, :foreground, :foreground_logging, :log_level, :plugin]
20
20
  DEPRECATED_ATTRS = []
21
21
  CONFIG_ATTRS = CURRENT_ATTRS + DEPRECATED_ATTRS
22
22
 
23
23
  class ConfigurationError < StandardError; end
24
24
 
25
- class ApnsFeedbackReceiverConfiguration < Struct.new(:frequency, :enabled) # rubocop:disable Style/StructInheritance
26
- def initialize
27
- super
28
- self.enabled = true
29
- self.frequency = 60
30
- end
31
- end
32
-
33
- class ApnsConfiguration < Struct.new(:feedback_receiver) # rubocop:disable Style/StructInheritance
34
- def initialize
35
- super
36
- self.feedback_receiver = ApnsFeedbackReceiverConfiguration.new
37
- end
38
- end
39
-
40
25
  class Configuration < Struct.new(*CONFIG_ATTRS) # rubocop:disable Style/StructInheritance
41
26
  include Deprecatable
42
27
 
@@ -55,8 +40,6 @@ module Rpush
55
40
  self.foreground = false
56
41
  self.foreground_logging = true
57
42
 
58
- self.apns = ApnsConfiguration.new
59
-
60
43
  # Internal options.
61
44
  self.embedded = false
62
45
  self.push = false
@@ -106,7 +89,7 @@ module Rpush
106
89
  client_module = Rpush::Client.const_get(client.to_s.camelize)
107
90
  Rpush.send(:include, client_module) unless Rpush.ancestors.include?(client_module)
108
91
 
109
- [:Apns, :Gcm, :Wpns, :Wns, :Adm, :Pushy, :Webpush].each do |service|
92
+ [:Apns, :Fcm, :Wpns, :Wns, :Adm, :Pushy, :Webpush].each do |service|
110
93
  Rpush.const_set(service, client_module.const_get(service)) unless Rpush.const_defined?(service)
111
94
  end
112
95
 
@@ -112,7 +112,6 @@ module Rpush
112
112
  headers['apns-expiration'] = '0'
113
113
  headers['apns-priority'] = '10'
114
114
  headers['apns-topic'] = @app.bundle_id
115
- headers['apns-push-type'] = 'background' if notification.content_available?
116
115
 
117
116
  headers.merge notification_data(notification)[HTTP2_HEADERS_KEY] || {}
118
117
  end
@@ -149,7 +149,6 @@ module Rpush
149
149
  headers['apns-priority'] = '10'
150
150
  headers['apns-topic'] = @app.bundle_id
151
151
  headers['authorization'] = "bearer #{jwt_token}"
152
- headers['apns-push-type'] = 'background' if notification.content_available?
153
152
 
154
153
  headers.merge notification_data(notification)[HTTP2_HEADERS_KEY] || {}
155
154
  end