rpush 4.1.0 → 5.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +254 -162
- data/README.md +57 -16
- data/lib/generators/rpush_migration_generator.rb +2 -0
- data/lib/generators/templates/rpush.rb +4 -0
- data/lib/generators/templates/rpush_4_1_1_updates.rb +9 -0
- data/lib/generators/templates/rpush_4_2_0_updates.rb +10 -0
- data/lib/rpush/apns_feedback.rb +1 -0
- data/lib/rpush/cli.rb +9 -22
- data/lib/rpush/client/active_model.rb +1 -1
- data/lib/rpush/client/active_model/apns/notification.rb +9 -1
- data/lib/rpush/client/active_model/apns/notification_payload_size_validator.rb +15 -0
- data/lib/rpush/client/active_model/apns2/notification.rb +14 -0
- data/lib/rpush/client/active_model/gcm/notification.rb +4 -3
- data/lib/rpush/client/active_model/wns/notification.rb +8 -0
- data/lib/rpush/client/active_record.rb +1 -0
- data/lib/rpush/client/active_record/apns/active_record_serializable_notification.rb +65 -0
- data/lib/rpush/client/active_record/apns/notification.rb +1 -29
- data/lib/rpush/client/active_record/apns2/notification.rb +4 -1
- data/lib/rpush/client/active_record/app.rb +1 -1
- data/lib/rpush/client/active_record/notification.rb +1 -1
- data/lib/rpush/client/redis/apns2/notification.rb +1 -0
- data/lib/rpush/client/redis/app.rb +2 -1
- data/lib/rpush/client/redis/notification.rb +2 -1
- data/lib/rpush/client/redis/pushy/notification.rb +0 -1
- data/lib/rpush/configuration.rb +2 -1
- data/lib/rpush/daemon.rb +2 -2
- data/lib/rpush/daemon/apns/feedback_receiver.rb +2 -1
- data/lib/rpush/daemon/apns2/delivery.rb +6 -1
- data/lib/rpush/daemon/apnsp8/delivery.rb +7 -2
- data/lib/rpush/daemon/app_runner.rb +1 -1
- data/lib/rpush/daemon/batch.rb +12 -5
- data/lib/rpush/daemon/delivery.rb +1 -2
- data/lib/rpush/daemon/dispatcher/apns_http2.rb +4 -2
- data/lib/rpush/daemon/dispatcher/apnsp8_http2.rb +2 -1
- data/lib/rpush/daemon/signal_handler.rb +1 -1
- data/lib/rpush/daemon/store/active_record.rb +1 -1
- data/lib/rpush/daemon/store/active_record/reconnectable.rb +1 -1
- data/lib/rpush/daemon/store/redis.rb +1 -1
- data/lib/rpush/daemon/wns/badge_request.rb +8 -3
- data/lib/rpush/daemon/wns/raw_request.rb +9 -2
- data/lib/rpush/daemon/wns/toast_request.rb +6 -2
- data/lib/rpush/logger.rb +1 -0
- data/lib/rpush/version.rb +2 -2
- data/spec/.rubocop.yml +1 -1
- data/spec/functional/apns2_spec.rb +85 -0
- data/spec/functional/gcm_priority_spec.rb +40 -0
- data/spec/support/active_record_setup.rb +5 -1
- data/spec/support/simplecov_helper.rb +1 -1
- data/spec/unit/apns_feedback_spec.rb +17 -6
- data/spec/unit/client/active_record/adm/app_spec.rb +2 -54
- data/spec/unit/client/active_record/adm/notification_spec.rb +2 -39
- data/spec/unit/client/active_record/apns/app_spec.rb +3 -26
- data/spec/unit/client/active_record/apns/feedback_spec.rb +1 -5
- data/spec/unit/client/active_record/apns/notification_spec.rb +29 -288
- data/spec/unit/client/active_record/apns2/app_spec.rb +4 -0
- data/spec/unit/client/active_record/apns2/notification_spec.rb +65 -0
- data/spec/unit/client/active_record/app_spec.rb +1 -26
- data/spec/unit/client/active_record/gcm/app_spec.rb +3 -1
- data/spec/unit/client/active_record/gcm/notification_spec.rb +6 -83
- data/spec/unit/client/active_record/notification_spec.rb +10 -11
- data/spec/unit/client/active_record/pushy/app_spec.rb +2 -13
- data/spec/unit/client/active_record/pushy/notification_spec.rb +2 -55
- data/spec/unit/client/active_record/shared/app.rb +14 -0
- data/spec/unit/{notification_shared.rb → client/active_record/shared/notification.rb} +12 -7
- data/spec/unit/client/active_record/wns/badge_notification_spec.rb +1 -11
- data/spec/unit/client/active_record/wns/raw_notification_spec.rb +3 -12
- data/spec/unit/client/active_record/wpns/app_spec.rb +3 -1
- data/spec/unit/client/active_record/wpns/notification_spec.rb +2 -17
- data/spec/unit/client/redis/adm/app_spec.rb +5 -0
- data/spec/unit/client/redis/adm/notification_spec.rb +5 -0
- data/spec/unit/client/redis/apns/app_spec.rb +5 -0
- data/spec/unit/client/redis/apns/feedback_spec.rb +5 -0
- data/spec/unit/client/redis/apns/notification_spec.rb +50 -0
- data/spec/unit/client/redis/apns2/app_spec.rb +4 -0
- data/spec/unit/client/redis/apns2/notification_spec.rb +50 -0
- data/spec/unit/client/redis/app_spec.rb +5 -0
- data/spec/unit/client/redis/gcm/app_spec.rb +5 -0
- data/spec/unit/client/redis/gcm/notification_spec.rb +5 -0
- data/spec/unit/client/redis/notification_spec.rb +5 -0
- data/spec/unit/client/redis/pushy/app_spec.rb +5 -0
- data/spec/unit/client/redis/pushy/notification_spec.rb +5 -0
- data/spec/unit/client/redis/wns/badge_notification_spec.rb +5 -0
- data/spec/unit/client/redis/wns/raw_notification_spec.rb +22 -0
- data/spec/unit/client/redis/wpns/app_spec.rb +5 -0
- data/spec/unit/client/redis/wpns/notification_spec.rb +5 -0
- data/spec/unit/client/shared/adm/app.rb +51 -0
- data/spec/unit/client/shared/adm/notification.rb +39 -0
- data/spec/unit/client/shared/apns/app.rb +29 -0
- data/spec/unit/client/shared/apns/feedback.rb +9 -0
- data/spec/unit/client/shared/apns/notification.rb +262 -0
- data/spec/unit/client/shared/app.rb +17 -0
- data/spec/unit/client/shared/gcm/app.rb +4 -0
- data/spec/unit/client/shared/gcm/notification.rb +77 -0
- data/spec/unit/client/shared/notification.rb +10 -0
- data/spec/unit/client/shared/pushy/app.rb +17 -0
- data/spec/unit/client/shared/pushy/notification.rb +55 -0
- data/spec/unit/client/shared/wns/badge_notification.rb +15 -0
- data/spec/unit/client/shared/wns/raw_notification.rb +21 -0
- data/spec/unit/client/shared/wpns/app.rb +4 -0
- data/spec/unit/client/shared/wpns/notification.rb +18 -0
- data/spec/unit/daemon/apns/feedback_receiver_spec.rb +19 -1
- data/spec/unit/daemon/batch_spec.rb +50 -2
- data/spec/unit/daemon/delivery_spec.rb +10 -0
- data/spec/unit/daemon/gcm/delivery_spec.rb +1 -1
- data/spec/unit/daemon/shared/store.rb +312 -0
- data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +7 -7
- data/spec/unit/daemon/store/active_record_spec.rb +7 -295
- data/spec/unit/daemon/store/redis_spec.rb +4 -293
- data/spec/unit/daemon/wns/post_request_spec.rb +64 -0
- data/spec/unit_spec_helper.rb +3 -0
- metadata +114 -14
- data/lib/rpush/client/active_model/apns/binary_notification_validator.rb +0 -16
data/README.md
CHANGED
@@ -21,7 +21,7 @@ Rpush aims to be the *de facto* gem for sending push notifications in Ruby. Its
|
|
21
21
|
|
22
22
|
#### Feature Highlights
|
23
23
|
|
24
|
-
* Use [**ActiveRecord**](https://github.com/rpush/rpush/wiki/Using-ActiveRecord) or [**Redis**](https://github.com/rpush/rpush/wiki/Using-Redis) for storage.
|
24
|
+
* Use [**ActiveRecord**](https://github.com/rpush/rpush/wiki/Using-ActiveRecord) or [**Redis**](https://github.com/rpush/rpush/wiki/Using-Redis) for storage.
|
25
25
|
* Plugins for [**Bugsnag**](https://github.com/rpush/rpush-plugin-bugsnag),
|
26
26
|
[**Sentry**](https://github.com/rpush/rpush-plugin-sentry), [**StatsD**](https://github.com/rpush/rpush-plugin-statsd) or [write your own](https://github.com/rpush/rpush/wiki/Writing-a-Plugin).
|
27
27
|
* Seamless integration with your projects, including **Rails**.
|
@@ -52,56 +52,97 @@ $ bundle exec rpush init
|
|
52
52
|
|
53
53
|
#### Apple Push Notification Service
|
54
54
|
|
55
|
+
There is a choice of two modes (and one legacy mode) using certificates or using tokens:
|
55
56
|
|
56
|
-
|
57
|
+
* `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
|
58
|
+
* `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)
|
59
|
+
* `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).
|
60
|
+
Apple have [announced](https://developer.apple.com/news/?id=11042019a) that this is not supported after November 2020.
|
61
|
+
|
62
|
+
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.
|
63
|
+
|
64
|
+
##### Apnsp8
|
65
|
+
|
66
|
+
To use the p8 APNs Api:
|
57
67
|
|
58
68
|
```ruby
|
59
|
-
app = Rpush::
|
69
|
+
app = Rpush::Apnsp8::App.new
|
60
70
|
app.name = "ios_app"
|
61
|
-
app.
|
71
|
+
app.apn_key = File.read("/path/to/sandbox.p8")
|
62
72
|
app.environment = "development" # APNs environment.
|
63
|
-
app.
|
73
|
+
app.apn_key_id = "APN KEY ID" # This is the Encryption Key ID provided by apple
|
74
|
+
app.team_id = "TEAM ID" # the team id - e.g. ABCDE12345
|
75
|
+
app.bundle_id = "BUNDLE ID" # the unique bundle id of the app, like com.example.appname
|
64
76
|
app.connections = 1
|
65
77
|
app.save!
|
66
78
|
```
|
67
79
|
|
68
80
|
```ruby
|
69
81
|
n = Rpush::Apns::Notification.new
|
70
|
-
n.app = Rpush::
|
82
|
+
n.app = Rpush::Apnsp8::App.find_by_name("ios_app")
|
71
83
|
n.device_token = "..." # hex string
|
72
84
|
n.alert = "hi mom!"
|
73
85
|
n.data = { foo: :bar }
|
74
86
|
n.save!
|
75
87
|
```
|
76
88
|
|
77
|
-
|
89
|
+
##### Apns2
|
78
90
|
|
79
|
-
|
91
|
+
(NB this uses the same protocol as Apnsp8, but authenticates with a certificate rather than tokens)
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
app = Rpush::Apns2::App.new
|
95
|
+
app.name = "ios_app"
|
96
|
+
app.certificate = File.read("/path/to/sandbox.pem")
|
97
|
+
app.environment = "development"
|
98
|
+
app.password = "certificate password"
|
99
|
+
app.connections = 1
|
100
|
+
app.save!
|
101
|
+
```
|
80
102
|
|
81
|
-
|
103
|
+
```ruby
|
104
|
+
n = Rpush::Apns2::Notification.new
|
105
|
+
n.app = Rpush::Apns2::App.find_by_name("ios_app")
|
106
|
+
n.device_token = "..." # hex string
|
107
|
+
n.alert = "hi mom!"
|
108
|
+
n.data = {
|
109
|
+
headers: { 'apns-topic': "BUNDLE ID", # the bundle id of the app, like com.example.appname
|
110
|
+
foo: :bar }
|
111
|
+
}
|
112
|
+
n.save!
|
113
|
+
```
|
82
114
|
|
83
|
-
|
115
|
+
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.
|
116
|
+
|
117
|
+
##### Apns (legacy protocol)
|
84
118
|
|
85
119
|
```ruby
|
86
|
-
app = Rpush::
|
120
|
+
app = Rpush::Apns::App.new
|
87
121
|
app.name = "ios_app"
|
88
|
-
app.
|
122
|
+
app.certificate = File.read("/path/to/sandbox.pem")
|
89
123
|
app.environment = "development" # APNs environment.
|
90
|
-
app.
|
91
|
-
app.team_id = "TEAM ID"
|
92
|
-
app.bundle_id = "BUNDLE ID"
|
124
|
+
app.password = "certificate password"
|
93
125
|
app.connections = 1
|
94
126
|
app.save!
|
95
127
|
```
|
96
128
|
|
97
129
|
```ruby
|
98
130
|
n = Rpush::Apns::Notification.new
|
99
|
-
n.app = Rpush::
|
131
|
+
n.app = Rpush::Apns::App.find_by_name("ios_app")
|
100
132
|
n.device_token = "..." # hex string
|
101
133
|
n.alert = "hi mom!"
|
102
134
|
n.data = { foo: :bar }
|
103
135
|
n.save!
|
104
136
|
```
|
137
|
+
|
138
|
+
##### Safari Push Notifications
|
139
|
+
|
140
|
+
Using one of the notifications methods above, the `url_args` attribute is available for Safari Push Notifications.
|
141
|
+
|
142
|
+
##### Environment
|
143
|
+
|
144
|
+
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.
|
145
|
+
|
105
146
|
#### Firebase Cloud Messaging
|
106
147
|
|
107
148
|
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.
|
@@ -51,6 +51,8 @@ class RpushMigrationGenerator < Rails::Generators::Base
|
|
51
51
|
add_rpush_migration('rpush_3_3_0_updates')
|
52
52
|
add_rpush_migration('rpush_3_3_1_updates')
|
53
53
|
add_rpush_migration('rpush_4_1_0_updates')
|
54
|
+
add_rpush_migration('rpush_4_1_1_updates')
|
55
|
+
add_rpush_migration('rpush_4_2_0_updates')
|
54
56
|
end
|
55
57
|
|
56
58
|
protected
|
@@ -26,6 +26,10 @@ Rpush.configure do |config|
|
|
26
26
|
# Define a custom logger.
|
27
27
|
# config.logger = MyLogger.new
|
28
28
|
|
29
|
+
# By default in foreground mode logs are directed both to the logger and to stdout.
|
30
|
+
# If the logger goes to stdout, you can disable foreground logging to avoid duplication.
|
31
|
+
# config.foreground_logging = false
|
32
|
+
|
29
33
|
# config.apns.feedback_receiver.enabled = true
|
30
34
|
# config.apns.feedback_receiver.frequency = 60
|
31
35
|
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class Rpush411Updates < ActiveRecord::VERSION::MAJOR >= 5 ? ActiveRecord::Migration["#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"] : ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
add_column :rpush_apps, :feedback_enabled, :boolean, default: true
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.down
|
7
|
+
remove_column :rpush_apps, :feedback_enabled
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class Rpush420Updates < ActiveRecord::VERSION::MAJOR >= 5 ? ActiveRecord::Migration["#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"] : ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
add_column :rpush_notifications, :sound_is_json, :boolean, null: true, default: false
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.down
|
7
|
+
remove_column :rpush_notifications, :sound_is_json
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
data/lib/rpush/apns_feedback.rb
CHANGED
@@ -7,6 +7,7 @@ module Rpush
|
|
7
7
|
# Redis stores every App type on the same namespace, hence the
|
8
8
|
# additional filtering
|
9
9
|
next unless app.service_name == 'apns'
|
10
|
+
next unless app.feedback_enabled
|
10
11
|
|
11
12
|
receiver = Rpush::Daemon::Apns::FeedbackReceiver.new(app)
|
12
13
|
receiver.check_for_feedback
|
data/lib/rpush/cli.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
3
|
require 'thor'
|
4
|
-
require '
|
4
|
+
require 'rainbow'
|
5
5
|
|
6
6
|
module Rpush
|
7
7
|
class CLI < Thor
|
@@ -14,7 +14,7 @@ module Rpush
|
|
14
14
|
end
|
15
15
|
|
16
16
|
class_option :config, type: :string, aliases: '-c', default: default_config_path
|
17
|
-
class_option 'rails-env', type: :string, aliases: '-e', default: 'development'
|
17
|
+
class_option 'rails-env', type: :string, aliases: '-e', default: ENV.fetch('RAILS_ENV', 'development')
|
18
18
|
|
19
19
|
option :foreground, type: :boolean, aliases: '-f', default: false
|
20
20
|
option 'pid-file', type: :string, aliases: '-p'
|
@@ -46,37 +46,29 @@ module Rpush
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
puts
|
49
|
+
puts Rainbow('✔').green
|
50
50
|
end
|
51
51
|
|
52
52
|
desc 'init', 'Initialize Rpush into the current directory'
|
53
53
|
option 'active-record', type: :boolean, desc: 'Install ActiveRecord migrations'
|
54
54
|
def init
|
55
55
|
underscore_option_names
|
56
|
-
check_ruby_version
|
57
56
|
require 'rails/generators'
|
58
57
|
|
59
|
-
puts "* " +
|
58
|
+
puts "* " + Rainbow('Installing config...').green
|
60
59
|
$RPUSH_CONFIG_PATH = default_config_path # rubocop:disable Style/GlobalVars
|
61
60
|
Rails::Generators.invoke('rpush_config')
|
62
61
|
|
63
62
|
install_migrations = options['active_record']
|
64
63
|
|
65
64
|
unless options.key?('active_record')
|
66
|
-
|
67
|
-
until has_answer
|
68
|
-
STDOUT.write "\n* #{ANSI.green { 'Install ActiveRecord migrations?' }} [y/n]: "
|
69
|
-
STDOUT.flush
|
70
|
-
answer = STDIN.gets.chomp.downcase
|
71
|
-
has_answer = %w(y n).include?(answer)
|
72
|
-
end
|
73
|
-
|
65
|
+
answer = ask("\n* #{Rainbow('Install ActiveRecord migrations?').green}", limited_to: %w[y n])
|
74
66
|
install_migrations = answer == 'y'
|
75
67
|
end
|
76
68
|
|
77
69
|
Rails::Generators.invoke('rpush_migration', ['--force']) if install_migrations
|
78
70
|
|
79
|
-
puts "\n* #{
|
71
|
+
puts "\n* #{Rainbow('Next steps:').green}"
|
80
72
|
puts " - Run 'bundle exec rake db:migrate'." if install_migrations
|
81
73
|
puts " - Review and update your configuration in #{default_config_path}."
|
82
74
|
puts " - Create your first app, see https://github.com/rpush/rpush for examples."
|
@@ -111,7 +103,6 @@ module Rpush
|
|
111
103
|
|
112
104
|
def config_setup
|
113
105
|
underscore_option_names
|
114
|
-
check_ruby_version
|
115
106
|
configure_rpush
|
116
107
|
end
|
117
108
|
|
@@ -126,7 +117,7 @@ module Rpush
|
|
126
117
|
ENV['RAILS_ENV'] = options['rails_env']
|
127
118
|
load 'config/environment.rb'
|
128
119
|
Rpush.config.update(options)
|
129
|
-
puts
|
120
|
+
puts Rainbow('✔').green
|
130
121
|
|
131
122
|
return true
|
132
123
|
end
|
@@ -136,7 +127,7 @@ module Rpush
|
|
136
127
|
|
137
128
|
def load_standalone
|
138
129
|
if !File.exist?(options[:config])
|
139
|
-
STDERR.puts(
|
130
|
+
STDERR.puts(Rainbow('ERROR: ').red + "#{options[:config]} does not exist. Please run 'rpush init' to generate it or specify the --config option.")
|
140
131
|
exit 1
|
141
132
|
else
|
142
133
|
load options[:config]
|
@@ -152,10 +143,6 @@ module Rpush
|
|
152
143
|
self.class.default_config_path
|
153
144
|
end
|
154
145
|
|
155
|
-
def check_ruby_version
|
156
|
-
STDERR.puts(ANSI.yellow { 'WARNING: ' } + "You are using an old and unsupported version of Ruby.") if RUBY_VERSION < '2.3.0' && RUBY_ENGINE == 'ruby'
|
157
|
-
end
|
158
|
-
|
159
146
|
def underscore_option_names
|
160
147
|
# Underscore option names so that they map directly to Configuration options.
|
161
148
|
new_options = options.dup
|
@@ -175,7 +162,7 @@ module Rpush
|
|
175
162
|
|
176
163
|
def rpush_process_pid
|
177
164
|
if Rpush.config.pid_file.blank?
|
178
|
-
STDERR.puts(
|
165
|
+
STDERR.puts(Rainbow('ERROR: ').red + 'config.pid_file is not set.')
|
179
166
|
exit 1
|
180
167
|
end
|
181
168
|
|
@@ -4,10 +4,10 @@ require 'rpush/client/active_model/notification'
|
|
4
4
|
require 'rpush/client/active_model/payload_data_size_validator'
|
5
5
|
require 'rpush/client/active_model/registration_ids_count_validator'
|
6
6
|
|
7
|
-
require 'rpush/client/active_model/apns/binary_notification_validator'
|
8
7
|
require 'rpush/client/active_model/apns/device_token_format_validator'
|
9
8
|
require 'rpush/client/active_model/apns/app'
|
10
9
|
require 'rpush/client/active_model/apns/notification'
|
10
|
+
require 'rpush/client/active_model/apns/notification_payload_size_validator'
|
11
11
|
|
12
12
|
require 'rpush/client/active_model/apns2/app'
|
13
13
|
require 'rpush/client/active_model/apns2/notification'
|
@@ -7,15 +7,23 @@ module Rpush
|
|
7
7
|
APNS_PRIORITY_IMMEDIATE = 10
|
8
8
|
APNS_PRIORITY_CONSERVE_POWER = 5
|
9
9
|
APNS_PRIORITIES = [APNS_PRIORITY_IMMEDIATE, APNS_PRIORITY_CONSERVE_POWER]
|
10
|
+
MAX_PAYLOAD_BYTESIZE = 2048
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def max_payload_bytesize
|
14
|
+
MAX_PAYLOAD_BYTESIZE
|
15
|
+
end
|
16
|
+
end
|
10
17
|
|
11
18
|
def self.included(base)
|
19
|
+
base.extend ClassMethods
|
12
20
|
base.instance_eval do
|
13
21
|
validates :device_token, presence: true
|
14
22
|
validates :badge, numericality: true, allow_nil: true
|
15
23
|
validates :priority, inclusion: { in: APNS_PRIORITIES }, allow_nil: true
|
16
24
|
|
17
25
|
validates_with Rpush::Client::ActiveModel::Apns::DeviceTokenFormatValidator
|
18
|
-
validates_with Rpush::Client::ActiveModel::Apns::
|
26
|
+
validates_with Rpush::Client::ActiveModel::Apns::NotificationPayloadSizeValidator
|
19
27
|
|
20
28
|
base.const_set('APNS_DEFAULT_EXPIRY', APNS_DEFAULT_EXPIRY) unless base.const_defined?('APNS_DEFAULT_EXPIRY')
|
21
29
|
base.const_set('APNS_PRIORITY_IMMEDIATE', APNS_PRIORITY_IMMEDIATE) unless base.const_defined?('APNS_PRIORITY_IMMEDIATE')
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Rpush
|
2
|
+
module Client
|
3
|
+
module ActiveModel
|
4
|
+
module Apns
|
5
|
+
class NotificationPayloadSizeValidator < ::ActiveModel::Validator
|
6
|
+
def validate(record)
|
7
|
+
limit = record.class.max_payload_bytesize
|
8
|
+
return unless record.payload.bytesize > limit
|
9
|
+
record.errors[:base] << "APN notification cannot be larger than #{limit} bytes. Try condensing your alert and device attributes."
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -3,6 +3,20 @@ module Rpush
|
|
3
3
|
module ActiveModel
|
4
4
|
module Apns2
|
5
5
|
include Rpush::Client::ActiveModel::Apns
|
6
|
+
|
7
|
+
module Notification
|
8
|
+
MAX_PAYLOAD_BYTESIZE = 4096
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def max_payload_bytesize
|
12
|
+
MAX_PAYLOAD_BYTESIZE
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.included(base)
|
17
|
+
base.extend ClassMethods
|
18
|
+
end
|
19
|
+
end
|
6
20
|
end
|
7
21
|
end
|
8
22
|
end
|
@@ -26,16 +26,16 @@ module Rpush
|
|
26
26
|
# I'm not happy about it, but this will have to do until I can take a further look.
|
27
27
|
def priority=(priority)
|
28
28
|
case priority
|
29
|
-
when 'high'
|
29
|
+
when 'high', GCM_PRIORITY_HIGH
|
30
30
|
super(GCM_PRIORITY_HIGH)
|
31
|
-
when 'normal'
|
31
|
+
when 'normal', GCM_PRIORITY_NORMAL
|
32
32
|
super(GCM_PRIORITY_NORMAL)
|
33
33
|
else
|
34
34
|
errors.add(:priority, 'must be one of either "normal" or "high"')
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
def as_json(options = nil)
|
38
|
+
def as_json(options = nil) # rubocop:disable Metrics/PerceivedComplexity
|
39
39
|
json = {
|
40
40
|
'registration_ids' => registration_ids,
|
41
41
|
'delay_while_idle' => delay_while_idle,
|
@@ -43,6 +43,7 @@ module Rpush
|
|
43
43
|
}
|
44
44
|
json['collapse_key'] = collapse_key if collapse_key
|
45
45
|
json['content_available'] = content_available if content_available
|
46
|
+
json['mutable_content'] = mutable_content if mutable_content
|
46
47
|
json['dry_run'] = dry_run if dry_run
|
47
48
|
json['notification'] = notification if notification
|
48
49
|
json['priority'] = priority_for_notification if priority
|
@@ -3,6 +3,13 @@ module Rpush
|
|
3
3
|
module ActiveModel
|
4
4
|
module Wns
|
5
5
|
module Notification
|
6
|
+
WNS_PRIORITY_HIGH = 1
|
7
|
+
WNS_PRIORITY_MEDIUM = 2
|
8
|
+
WNS_PRIORITY_LOW = 3
|
9
|
+
WNS_PRIORITY_VERY_LOW = 4
|
10
|
+
|
11
|
+
WNS_PRIORITIES = [WNS_PRIORITY_HIGH, WNS_PRIORITY_MEDIUM, WNS_PRIORITY_LOW, WNS_PRIORITY_VERY_LOW]
|
12
|
+
|
6
13
|
module InstanceMethods
|
7
14
|
def alert=(value)
|
8
15
|
return unless value
|
@@ -23,6 +30,7 @@ module Rpush
|
|
23
30
|
validates :uri, presence: true
|
24
31
|
validates :uri, format: { with: %r{https?://[\S]+} }
|
25
32
|
validates :data, presence: true, unless: :skip_data_validation?
|
33
|
+
validates :priority, inclusion: { in: WNS_PRIORITIES }, allow_nil: true
|
26
34
|
end
|
27
35
|
end
|
28
36
|
end
|
@@ -5,6 +5,7 @@ require 'rpush/client/active_model'
|
|
5
5
|
require 'rpush/client/active_record/notification'
|
6
6
|
require 'rpush/client/active_record/app'
|
7
7
|
|
8
|
+
require 'rpush/client/active_record/apns/active_record_serializable_notification'
|
8
9
|
require 'rpush/client/active_record/apns/notification'
|
9
10
|
require 'rpush/client/active_record/apns/feedback'
|
10
11
|
require 'rpush/client/active_record/apns/app'
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Rpush
|
2
|
+
module Client
|
3
|
+
module ActiveRecord
|
4
|
+
module Apns
|
5
|
+
module ActiveRecordSerializableNotification
|
6
|
+
def alert=(alert)
|
7
|
+
if alert.is_a?(Hash)
|
8
|
+
write_attribute(:alert, multi_json_dump(alert))
|
9
|
+
self.alert_is_json = true if has_attribute?(:alert_is_json)
|
10
|
+
else
|
11
|
+
write_attribute(:alert, alert)
|
12
|
+
self.alert_is_json = false if has_attribute?(:alert_is_json)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def alert
|
17
|
+
string_or_json = read_attribute(:alert)
|
18
|
+
|
19
|
+
if has_attribute?(:alert_is_json)
|
20
|
+
if alert_is_json?
|
21
|
+
multi_json_load(string_or_json)
|
22
|
+
else
|
23
|
+
string_or_json
|
24
|
+
end
|
25
|
+
else
|
26
|
+
begin
|
27
|
+
multi_json_load(string_or_json)
|
28
|
+
rescue StandardError
|
29
|
+
string_or_json
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def sound=(sound)
|
35
|
+
if sound.is_a?(Hash)
|
36
|
+
write_attribute(:sound, multi_json_dump(sound))
|
37
|
+
self.sound_is_json = true if has_attribute?(:sound_is_json)
|
38
|
+
else
|
39
|
+
write_attribute(:sound, sound)
|
40
|
+
self.sound_is_json = false if has_attribute?(:sound_is_json)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def sound
|
45
|
+
string_or_json = read_attribute(:sound)
|
46
|
+
|
47
|
+
if has_attribute?(:sound_is_json)
|
48
|
+
if sound_is_json?
|
49
|
+
multi_json_load(string_or_json)
|
50
|
+
else
|
51
|
+
string_or_json
|
52
|
+
end
|
53
|
+
else
|
54
|
+
begin
|
55
|
+
multi_json_load(string_or_json)
|
56
|
+
rescue StandardError
|
57
|
+
string_or_json
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|