pushing 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.travis.yml +16 -6
- data/Appraisals +12 -5
- data/Gemfile +1 -1
- data/README.md +130 -36
- data/certs/apns_auth_key_for_jwt_auth.p8.enc +0 -0
- data/certs/apns_example_production.pem.enc +0 -0
- data/gemfiles/rails_42.gemfile +1 -1
- data/gemfiles/rails_50.gemfile +1 -1
- data/gemfiles/rails_51.gemfile +1 -1
- data/gemfiles/rails_52.gemfile +17 -0
- data/gemfiles/rails_edge.gemfile +1 -1
- data/lib/generators/pushing/templates/initializer.rb +53 -8
- data/lib/pushing/adapters/apn/apnotic_adapter.rb +22 -11
- data/lib/pushing/adapters/apn/houston_adapter.rb +3 -4
- data/lib/pushing/adapters/apn/lowdown_adapter.rb +4 -6
- data/lib/pushing/base.rb +8 -3
- data/lib/pushing/platforms.rb +26 -6
- data/lib/pushing/railtie.rb +25 -0
- data/lib/pushing/version.rb +1 -1
- data/pushing.gemspec +1 -3
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e6d63cb3c86db8e3be6c3335fb26e7e028ba5b25eb9ad13aa4b8febbf82d432c
|
4
|
+
data.tar.gz: 82d5cf8214b81355a1dbc1db23843525e492889af24f0750874d1ec626830767
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f6c64a1574f61b456656018eb94fe6c73f3638745c8c26420f22098ef0de9188511e317a7f070ad2b683c58785650634fb03e2db9ccc6278f4e1280d7729e46
|
7
|
+
data.tar.gz: 5c31ab15a5ec3f68622167ea05fe89eaf9b43c563d65f02d903f3793e3a5c22674d90af97d631dfe79df086524dd2f85f873298bff5136443358dc6944687e14
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -4,25 +4,35 @@ cache: bundler
|
|
4
4
|
sudo: false
|
5
5
|
|
6
6
|
before_install:
|
7
|
-
|
7
|
+
- gem update --system
|
8
|
+
- gem pristine bundler
|
9
|
+
- openssl aes-256-cbc -K $encrypted_86ed69f44076_key -iv $encrypted_86ed69f44076_iv -in ./certs/apns_auth_key_for_jwt_auth.p8.enc -out certs/apns_auth_key_for_jwt_auth.p8 -d
|
10
|
+
- openssl aes-256-cbc -K $encrypted_86ed69f44076_key -iv $encrypted_86ed69f44076_iv -in ./certs/apns_example_production.pem.enc -out certs/apns_example_production.pem -d
|
8
11
|
|
9
12
|
rvm:
|
10
|
-
- 2.2.
|
11
|
-
- 2.3.
|
12
|
-
- 2.4.
|
13
|
+
- 2.2.9
|
14
|
+
- 2.3.6
|
15
|
+
- 2.4.3
|
16
|
+
- 2.5.0
|
13
17
|
- ruby-head
|
14
|
-
- jruby-9.1.
|
18
|
+
- jruby-9.1.16.0
|
15
19
|
- jruby-head
|
16
20
|
|
17
21
|
gemfile:
|
18
22
|
- gemfiles/rails_42.gemfile
|
19
23
|
- gemfiles/rails_50.gemfile
|
20
24
|
- gemfiles/rails_51.gemfile
|
25
|
+
- gemfiles/rails_52.gemfile
|
21
26
|
- gemfiles/rails_edge.gemfile
|
22
27
|
|
23
28
|
matrix:
|
24
29
|
allow_failures:
|
25
30
|
- rvm: ruby-head
|
26
|
-
- rvm: jruby-9.1.
|
31
|
+
- rvm: jruby-9.1.16.0
|
27
32
|
- rvm: jruby-head
|
28
33
|
- gemfile: gemfiles/rails_edge.gemfile
|
34
|
+
exclude:
|
35
|
+
- rvm: 2.3.6
|
36
|
+
gemfile: gemfiles/rails_edge.gemfile
|
37
|
+
- rvm: 2.2.9
|
38
|
+
gemfile: gemfiles/rails_edge.gemfile
|
data/Appraisals
CHANGED
@@ -7,11 +7,11 @@ appraise "rails_edge" do
|
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
-
appraise "
|
11
|
-
gem "railties", '~> 5.0.
|
12
|
-
gem "actionpack", '~> 5.0.
|
13
|
-
gem "actionview", '~> 5.0.
|
14
|
-
gem "activejob", '~> 5.0.
|
10
|
+
appraise "rails_52" do
|
11
|
+
gem "railties", '~> 5.2.0.rc1'
|
12
|
+
gem "actionpack", '~> 5.2.0.rc1'
|
13
|
+
gem "actionview", '~> 5.2.0.rc1'
|
14
|
+
gem "activejob", '~> 5.2.0.rc1'
|
15
15
|
end
|
16
16
|
|
17
17
|
appraise "rails_51" do
|
@@ -21,6 +21,13 @@ appraise "rails_51" do
|
|
21
21
|
gem "activejob", '~> 5.1.0'
|
22
22
|
end
|
23
23
|
|
24
|
+
appraise "rails_50" do
|
25
|
+
gem "railties", '~> 5.0.0'
|
26
|
+
gem "actionpack", '~> 5.0.0'
|
27
|
+
gem "actionview", '~> 5.0.0'
|
28
|
+
gem "activejob", '~> 5.0.0'
|
29
|
+
end
|
30
|
+
|
24
31
|
appraise "rails_42" do
|
25
32
|
gem "rails", '~> 4.2.0'
|
26
33
|
gem "actionpack", '~> 4.2.0'
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
# Pushing [![Build Status](https://travis-ci.org/yuki24/pushing.svg?branch=master)](https://travis-ci.org/yuki24/pushing)
|
1
|
+
# Pushing: ActionMailer for Push Notifications [![Build Status](https://travis-ci.org/yuki24/pushing.svg?branch=master)](https://travis-ci.org/yuki24/pushing)
|
2
2
|
|
3
|
-
Pushing is a push notification framework that implements interfaces similar to ActionMailer
|
3
|
+
Pushing is a push notification framework that implements interfaces similar to ActionMailer.
|
4
4
|
|
5
|
-
* **Convention over Configuration**: Pushing brings Convention over Configuration to your app
|
5
|
+
* **Convention over Configuration**: Pushing brings Convention over Configuration to your app for organizing your push notification implementations.
|
6
6
|
* **Extremely Easy to Learn**: If you know how to use ActionMailer, you already know how to use Pushing. Send notifications asynchronously with ActiveJob at no learning cost.
|
7
7
|
* **Testability**: First-class support for push notification. No more hassle writing custom code or stubs/mocks for your tests.
|
8
8
|
|
@@ -11,44 +11,40 @@ Pushing is a push notification framework that implements interfaces similar to A
|
|
11
11
|
Add this line to your application's Gemfile:
|
12
12
|
|
13
13
|
```ruby
|
14
|
-
gem 'pushing'
|
15
|
-
gem 'jbuilder'
|
14
|
+
gem 'pushing'
|
15
|
+
gem 'jbuilder' # if you don't have it in your Gemfile
|
16
16
|
```
|
17
17
|
|
18
|
-
|
18
|
+
At the time of writing, Pushing only has support for [jbuilder](https://github.com/rails/jbuilder) (Rails' default JSON constructor), but there are plans to add support for [jb](https://github.com/amatsuda/jb) and [rabl](https://github.com/nesquena/rabl).
|
19
19
|
|
20
|
-
### Supported
|
20
|
+
### Supported Platforms
|
21
21
|
|
22
|
-
Pushing itself doesn't make HTTP requests. Instead, it uses an adapter
|
22
|
+
Pushing itself doesn't make HTTP requests. Instead, it uses an adapter to make actual calls. Currently, Pushing has support for the following client gems:
|
23
23
|
|
24
|
-
* [APNs](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1):
|
24
|
+
* [APNs](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1) (iOS):
|
25
25
|
* [anpotic](https://github.com/ostinelli/apnotic) (recommended)
|
26
26
|
* [lowdown](https://github.com/alloy/lowdown)
|
27
27
|
* [houston](https://github.com/nomad/houston)
|
28
28
|
|
29
|
-
* [FCM](https://firebase.google.com/docs/cloud-messaging/):
|
29
|
+
* [FCM](https://firebase.google.com/docs/cloud-messaging/) (Android):
|
30
30
|
* [andpush](https://github.com/yuki24/andpush) (recommended)
|
31
31
|
* [fcm](https://github.com/spacialdb/fcm)
|
32
32
|
|
33
33
|
If you are starting from scratch, it is recommended using [anpotic](https://github.com/ostinelli/apnotic) for APNs and [andpush](https://github.com/yuki24/andpush) for FCM due to their reliability and performance:
|
34
34
|
|
35
35
|
```ruby
|
36
|
-
gem 'apnotic' # APNs
|
37
|
-
gem 'andpush' # FCM
|
36
|
+
gem 'apnotic' # APNs
|
37
|
+
gem 'andpush' # FCM
|
38
38
|
```
|
39
39
|
|
40
40
|
### Walkthrough to Writing a Notifier
|
41
41
|
|
42
|
-
|
42
|
+
#### Generate a new notifier:
|
43
43
|
|
44
44
|
```sh
|
45
45
|
$ rails g pushing:notifier TweetNotifier new_direct_message
|
46
46
|
```
|
47
47
|
|
48
|
-
#### Edit the Notifier
|
49
|
-
|
50
|
-
Let's say there are `direct_messages` and `device_tokens` tables where we store actual messages and device tokens (a.k.a registration ids in FCM) given by APNs or FCM.
|
51
|
-
|
52
48
|
```ruby
|
53
49
|
# app/notifiers/tweet_notifier.rb
|
54
50
|
class TweetNotifier < ApplicationNotifier
|
@@ -61,18 +57,7 @@ class TweetNotifier < ApplicationNotifier
|
|
61
57
|
end
|
62
58
|
```
|
63
59
|
|
64
|
-
|
65
|
-
|
66
|
-
```ruby
|
67
|
-
# only sends a push notification to FCM
|
68
|
-
push apn: false, fcm: @token.registration_id
|
69
|
-
```
|
70
|
-
|
71
|
-
will only send a notification to the FCM service.
|
72
|
-
|
73
|
-
#### Edit the Push Notification Payload
|
74
|
-
|
75
|
-
Next, let's modify the templates to generate JSON that contains message data. Like controllers, you can use all the instance variables initialized in the action.
|
60
|
+
#### Edit the push notification payload:
|
76
61
|
|
77
62
|
APNs:
|
78
63
|
|
@@ -104,9 +89,7 @@ json.notification do
|
|
104
89
|
end
|
105
90
|
```
|
106
91
|
|
107
|
-
### Deliver the
|
108
|
-
|
109
|
-
Finally, send a push notification to the user. You can call the `#deliver_now!` method to immediately send a notification, or the `#deliver_later!` method if you have ActiveJob set up.
|
92
|
+
### Deliver the push notifications:
|
110
93
|
|
111
94
|
```ruby
|
112
95
|
TweetNotifier.new_direct_message(message_id, device_token.id).deliver_now!
|
@@ -116,6 +99,57 @@ TweetNotifier.new_direct_message(message_id, device_token.id).deliver_later!
|
|
116
99
|
# => enqueues a job that sends a push notification later
|
117
100
|
```
|
118
101
|
|
102
|
+
## Advanced Usage
|
103
|
+
|
104
|
+
### Pushing only to one platform
|
105
|
+
|
106
|
+
Pushing only sends a notification for the platforms that are given a truthy value. For example, give the following code:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
push apn: @token.device_token, fcm: false
|
110
|
+
# => only sends a push notification to APNs
|
111
|
+
|
112
|
+
push apn: @token.device_token
|
113
|
+
# => same as above but without the `:fcm` key, only sends a push notification to APNs
|
114
|
+
```
|
115
|
+
|
116
|
+
This will only send a push notification to APNs and skip the call to FCM.
|
117
|
+
|
118
|
+
### APNs
|
119
|
+
|
120
|
+
It is often necessary to switch the environment endpoint or adjust the request headers depending on the notification you want to send. Pushing's `#push` method allows for overriding APNs request headers on a delivery-basis:
|
121
|
+
|
122
|
+
#### Overriding the default environment:
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
push apn: { device_token: @token.device_token, environment: @token.apn_environment }
|
126
|
+
```
|
127
|
+
|
128
|
+
#### Overriding the default APN topic:
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
push apn: { device_token: @token.device_token, headers: { apns_topic: 'your.otherapp.ios' } }
|
132
|
+
```
|
133
|
+
|
134
|
+
#### Or all of the above:
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
push fcm: @token.fcm?,
|
138
|
+
apn: {
|
139
|
+
device_token: @token.apn? && @token.device_token,
|
140
|
+
environment: @token.apn_environment,
|
141
|
+
headers: {
|
142
|
+
apns_id: uuid,
|
143
|
+
apns_expiration: 7.days.from_now,
|
144
|
+
apns_priority: 5,
|
145
|
+
apns_topic: 'your.otherapp.ios',
|
146
|
+
apns_collapse_id: 'not-so-important-notification'
|
147
|
+
}
|
148
|
+
}
|
149
|
+
```
|
150
|
+
|
151
|
+
The `:fcm` key, on the other hand, doesn't have any options as everything's configurable through the request body.
|
152
|
+
|
119
153
|
## Error Handling
|
120
154
|
|
121
155
|
Like ActionMailer, you can use the `rescue_from` hook to handle exceptions. A common use-case would be to handle a **'BadDeviceToken'** response from APNs or a response with a **'Retry-After'** header from FCM.
|
@@ -129,8 +163,9 @@ class ApplicationNotifier < Pushing::Base
|
|
129
163
|
|
130
164
|
if response.status == 410 || (response.status == 400 && response.json[:reason] == 'BadDeviceToken')
|
131
165
|
token = error.notification.device_token
|
166
|
+
Rails.logger.info("APN device token #{token} has been expired and will be removed.")
|
132
167
|
|
133
|
-
# delete device token accordingly
|
168
|
+
# delete or expire device token accordingly
|
134
169
|
else
|
135
170
|
raise # Make sure to raise any other types of error to re-enqueue the job
|
136
171
|
end
|
@@ -180,11 +215,70 @@ end
|
|
180
215
|
|
181
216
|
## Configuration
|
182
217
|
|
183
|
-
TODO
|
218
|
+
##### TODO: Make this section more helpful
|
219
|
+
|
220
|
+
```ruby
|
221
|
+
Pushing::Platforms.configure do |config|
|
222
|
+
# Adapter that is used to send push notifications through FCM
|
223
|
+
config.fcm.adapter = Rails.env.test? ? :test : :andpush
|
224
|
+
|
225
|
+
# Your FCM servery key that can be found here: https://console.firebase.google.com/project/_/settings/cloudmessaging
|
226
|
+
config.fcm.server_key = 'YOUR_FCM_SERVER_KEY'
|
227
|
+
|
228
|
+
# Adapter that is used to send push notifications through APNs
|
229
|
+
config.apn.adapter = Rails.env.test? ? :test : :apnotic
|
230
|
+
|
231
|
+
# The environment that is used by default to send push notifications through APNs
|
232
|
+
config.apn.environment = Rails.env.production? ? :production : :development
|
233
|
+
|
234
|
+
# The scheme that is used for negotiating connection trust between your provider
|
235
|
+
# servers and Apple Push Notification service. As documented in the offitial doc,
|
236
|
+
# there are two schemes available:
|
237
|
+
#
|
238
|
+
# :token - Token-based provider connection trust (default)
|
239
|
+
# :certificate - Certificate-based provider connection trust
|
240
|
+
#
|
241
|
+
# This option is only applied when using an adapter that uses the HTTP/2-based
|
242
|
+
# API.
|
243
|
+
config.apn.connection_scheme = :token
|
244
|
+
|
245
|
+
# Path to the certificate or auth key for establishing a connection to APNs.
|
246
|
+
#
|
247
|
+
# This config is always required.
|
248
|
+
config.apn.certificate_path = 'path/to/your/certificate'
|
249
|
+
|
250
|
+
# Password for the certificate specified above if there's any.
|
251
|
+
# config.apn.certificate_password = 'passphrase'
|
252
|
+
|
253
|
+
# A 10-character key identifier (kid) key, obtained from your developer account.
|
254
|
+
# If you haven't created an Auth Key for your app, create a new one at:
|
255
|
+
# https://developer.apple.com/account/ios/authkey/
|
256
|
+
#
|
257
|
+
# Required if the +connection_scheme+ is set to +:token+.
|
258
|
+
config.apn.key_id = 'DEF123GHIJ'
|
259
|
+
|
260
|
+
# The issuer (iss) registered claim key, whose value is your 10-character Team ID,
|
261
|
+
# obtained from your developer account. Your team id could be found at:
|
262
|
+
# https://developer.apple.com/account/#/membership
|
263
|
+
#
|
264
|
+
# Required if the +connection_scheme+ is set to +:token+.
|
265
|
+
config.apn.team_id = 'ABC123DEFG'
|
266
|
+
|
267
|
+
# Header values that are added to every request to APNs. documentation for the
|
268
|
+
# headers available can be found here:
|
269
|
+
# https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html#//apple_ref/doc/uid/TP40008194-CH11-SW13
|
270
|
+
config.apn.default_headers = {
|
271
|
+
apns_priority: 10,
|
272
|
+
apns_topic: 'your.awesomeapp.ios',
|
273
|
+
apns_collapse_id: 'wrong.topicname.com'
|
274
|
+
}
|
275
|
+
end
|
276
|
+
|
277
|
+
```
|
184
278
|
|
185
279
|
## Testing
|
186
280
|
|
187
|
-
Pushing provides first-class support for testing. In
|
281
|
+
Pushing provides first-class support for testing. In order to test your notifier, use the `:test` adapter in the test environment instead of an actual adapter in development/production.
|
188
282
|
|
189
283
|
```ruby
|
190
284
|
# config/initializers/pushing.rb
|
@@ -194,7 +288,7 @@ Pushing::Platforms.configure do |config|
|
|
194
288
|
end
|
195
289
|
```
|
196
290
|
|
197
|
-
Now you can
|
291
|
+
Now you can call the `#deliveries` method on the notifier. Here is an example with [ActiveSupport::TestCase](http://api.rubyonrails.org/classes/ActiveSupport/TestCase.html):
|
198
292
|
|
199
293
|
```ruby
|
200
294
|
TweetNotifier.deliveries.clear # => clears the test inbox
|
Binary file
|
Binary file
|
data/gemfiles/rails_42.gemfile
CHANGED
data/gemfiles/rails_50.gemfile
CHANGED
data/gemfiles/rails_51.gemfile
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "houston", require: false
|
6
|
+
gem "apnotic", ">= 1.2.0", require: false
|
7
|
+
gem "lowdown", require: false
|
8
|
+
gem "andpush", require: false
|
9
|
+
gem "fcm", require: false
|
10
|
+
gem "pry"
|
11
|
+
gem "pry-byebug", platforms: :mri
|
12
|
+
gem "railties", "~> 5.2.0.rc1"
|
13
|
+
gem "actionpack", "~> 5.2.0.rc1"
|
14
|
+
gem "actionview", "~> 5.2.0.rc1"
|
15
|
+
gem "activejob", "~> 5.2.0.rc1"
|
16
|
+
|
17
|
+
gemspec path: "../"
|
data/gemfiles/rails_edge.gemfile
CHANGED
@@ -1,10 +1,55 @@
|
|
1
1
|
Pushing::Platforms.configure do |config|
|
2
|
-
|
3
|
-
config.fcm.
|
4
|
-
|
5
|
-
|
6
|
-
config.
|
7
|
-
|
8
|
-
|
9
|
-
config.apn.
|
2
|
+
# Adapter that is used to send push notifications through FCM
|
3
|
+
config.fcm.adapter = Rails.env.test? ? :test : :andpush
|
4
|
+
|
5
|
+
# Your FCM servery key that can be found here: https://console.firebase.google.com/project/_/settings/cloudmessaging
|
6
|
+
config.fcm.server_key = 'YOUR_FCM_SERVER_KEY'
|
7
|
+
|
8
|
+
# Adapter that is used to send push notifications through APNs
|
9
|
+
config.apn.adapter = Rails.env.test? ? :test : :apnotic
|
10
|
+
|
11
|
+
# The environment that is used by default to send push notifications through APNs
|
12
|
+
config.apn.environment = Rails.env.production? ? :production : :development
|
13
|
+
|
14
|
+
# The scheme that is used for negotiating connection trust between your provider
|
15
|
+
# servers and Apple Push Notification service. As documented in the offitial doc,
|
16
|
+
# there are two schemes available:
|
17
|
+
#
|
18
|
+
# :token - Token-based provider connection trust (default)
|
19
|
+
# :certificate - Certificate-based provider connection trust
|
20
|
+
#
|
21
|
+
# This option is only applied when using an adapter that uses the HTTP/2-based
|
22
|
+
# API.
|
23
|
+
config.apn.connection_scheme = :token
|
24
|
+
|
25
|
+
# Path to the certificate or auth key for establishing a connection to APNs.
|
26
|
+
#
|
27
|
+
# This config is always required.
|
28
|
+
config.apn.certificate_path = 'path/to/your/certificate'
|
29
|
+
|
30
|
+
# Password for the certificate specified above if there's any.
|
31
|
+
# config.apn.certificate_password = 'passphrase'
|
32
|
+
|
33
|
+
# A 10-character key identifier (kid) key, obtained from your developer account.
|
34
|
+
# If you haven't created an Auth Key for your app, create a new one at:
|
35
|
+
# https://developer.apple.com/account/ios/authkey/
|
36
|
+
#
|
37
|
+
# Required if the +connection_scheme+ is set to +:token+.
|
38
|
+
config.apn.key_id = 'DEF123GHIJ'
|
39
|
+
|
40
|
+
# The issuer (iss) registered claim key, whose value is your 10-character Team ID,
|
41
|
+
# obtained from your developer account. Your team id could be found at:
|
42
|
+
# https://developer.apple.com/account/#/membership
|
43
|
+
#
|
44
|
+
# Required if the +connection_scheme+ is set to +:token+.
|
45
|
+
config.apn.team_id = 'ABC123DEFG'
|
46
|
+
|
47
|
+
# Header values that are added to every request to APNs. documentation for the
|
48
|
+
# headers available can be found here:
|
49
|
+
# https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html#//apple_ref/doc/uid/TP40008194-CH11-SW13
|
50
|
+
config.apn.default_headers = {
|
51
|
+
apns_priority: 10,
|
52
|
+
apns_topic: 'your.awesomeapp.ios',
|
53
|
+
apns_collapse_id: 'wrong.topicname.com'
|
54
|
+
}
|
10
55
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
3
|
require 'apnotic'
|
4
|
+
require 'active_support/core_ext/hash/keys'
|
4
5
|
|
5
6
|
module Pushing
|
6
7
|
module Adapters
|
@@ -19,16 +20,26 @@ module Pushing
|
|
19
20
|
size: Process.getrlimit(Process::RLIMIT_NOFILE).first / 8
|
20
21
|
}.freeze
|
21
22
|
|
22
|
-
attr_reader :
|
23
|
+
attr_reader :connection_pool
|
23
24
|
|
24
25
|
def initialize(apn_settings)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
26
|
+
options = case apn_settings.connection_scheme.to_sym
|
27
|
+
when :token
|
28
|
+
{
|
29
|
+
auth_method: :token,
|
30
|
+
cert_path: apn_settings.certificate_path,
|
31
|
+
key_id: apn_settings.key_id,
|
32
|
+
team_id: apn_settings.team_id
|
33
|
+
}
|
34
|
+
when :certificate
|
35
|
+
{
|
36
|
+
cert_path: apn_settings.certificate_path,
|
37
|
+
cert_pass: apn_settings.certificate_password
|
38
|
+
}
|
39
|
+
else
|
40
|
+
raise "Unknown connection scheme #{apn_settings.connection_scheme.inspect}. " \
|
41
|
+
"The connection scheme should either be :token or :certificate."
|
42
|
+
end
|
32
43
|
|
33
44
|
@connection_pool = {
|
34
45
|
development: Apnotic::ConnectionPool.development(options, DEFAULT_ADAPTER_OPTIONS),
|
@@ -38,7 +49,7 @@ module Pushing
|
|
38
49
|
|
39
50
|
def push!(notification)
|
40
51
|
message = Apnotic::Notification.new(notification.device_token)
|
41
|
-
json = notification.payload
|
52
|
+
json = notification.payload.dup
|
42
53
|
|
43
54
|
if aps = json.delete(:aps)
|
44
55
|
APS_DICTIONARY_KEYS.each {|key| message.instance_variable_set(:"@#{key}", aps[key]) }
|
@@ -49,10 +60,10 @@ module Pushing
|
|
49
60
|
message.apns_id = notification.headers[:'apns-id'] || message.apns_id
|
50
61
|
message.expiration = notification.headers[:'apns-expiration'].to_i
|
51
62
|
message.priority = notification.headers[:'apns-priority']
|
52
|
-
message.topic = notification.headers[:'apns-topic']
|
63
|
+
message.topic = notification.headers[:'apns-topic']
|
53
64
|
message.apns_collapse_id = notification.headers[:'apns-collapse-id']
|
54
65
|
|
55
|
-
response = connection_pool[notification.environment
|
66
|
+
response = connection_pool[notification.environment].with {|connection| connection.push(message) }
|
56
67
|
|
57
68
|
if !response
|
58
69
|
raise "Timeout sending a push notification"
|
@@ -3,11 +3,10 @@ require 'houston'
|
|
3
3
|
module Pushing
|
4
4
|
module Adapters
|
5
5
|
class HoustonAdapter
|
6
|
-
attr_reader :certificate_path, :
|
6
|
+
attr_reader :certificate_path, :client
|
7
7
|
|
8
8
|
def initialize(apn_settings)
|
9
9
|
@certificate_path = apn_settings.certificate_path
|
10
|
-
@environment = apn_settings.environment
|
11
10
|
|
12
11
|
@client = {
|
13
12
|
production: Houston::Client.production,
|
@@ -17,12 +16,12 @@ module Pushing
|
|
17
16
|
end
|
18
17
|
|
19
18
|
def push!(notification)
|
20
|
-
payload = notification.payload
|
19
|
+
payload = notification.payload.dup
|
21
20
|
aps = payload.delete(:aps)
|
22
21
|
aps[:device] = notification.device_token
|
23
22
|
|
24
23
|
houston_notification = Houston::Notification.new(payload.merge(aps))
|
25
|
-
client[notification.environment
|
24
|
+
client[notification.environment].push(houston_notification)
|
26
25
|
rescue => cause
|
27
26
|
error = Pushing::ApnDeliveryError.new("Error while trying to send push notification: #{cause.message}", nil, notification)
|
28
27
|
|
@@ -1,16 +1,14 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
3
|
require 'json'
|
4
|
+
require 'delegate'
|
4
5
|
|
5
6
|
module Pushing
|
6
7
|
module Adapters
|
7
8
|
class LowdownAdapter
|
8
|
-
attr_reader :
|
9
|
+
attr_reader :clients
|
9
10
|
|
10
11
|
def initialize(apn_settings)
|
11
|
-
@environment = apn_settings.environment.to_sym
|
12
|
-
@topic = apn_settings.topic
|
13
|
-
|
14
12
|
# Don't load lowdown earlier as it may load Celluloid (and start it)
|
15
13
|
# before daemonizing the workers spun up by a gem (e,g, delayed_job).
|
16
14
|
require 'lowdown' unless defined?(Lodwown)
|
@@ -36,10 +34,10 @@ module Pushing
|
|
36
34
|
|
37
35
|
lowdown_notification.expiration = notification.headers[:'apns-expiration'].to_i if notification.headers[:'apns-expiration']
|
38
36
|
lowdown_notification.priority = notification.headers[:'apns-priority']
|
39
|
-
lowdown_notification.topic = notification.headers[:'apns-topic']
|
37
|
+
lowdown_notification.topic = notification.headers[:'apns-topic']
|
40
38
|
|
41
39
|
response = nil
|
42
|
-
clients[notification.environment
|
40
|
+
clients[notification.environment].group do |group|
|
43
41
|
group.send_notification(lowdown_notification) do |_response|
|
44
42
|
response = _response
|
45
43
|
end
|
data/lib/pushing/base.rb
CHANGED
@@ -102,6 +102,11 @@ module Pushing
|
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
|
+
# Push notifications do not support relative path links.
|
106
|
+
def supports_path? # :doc:
|
107
|
+
false
|
108
|
+
end
|
109
|
+
|
105
110
|
private
|
106
111
|
|
107
112
|
def set_payload_for_notification(payload, notification)
|
@@ -151,12 +156,12 @@ module Pushing
|
|
151
156
|
return notification if notification && headers.blank?
|
152
157
|
|
153
158
|
payload = {}
|
154
|
-
headers.each do |platform,
|
159
|
+
::Pushing::Platforms.config.select {|platform, _| headers[platform] }.each do |platform, config|
|
155
160
|
payload_class = ::Pushing::Platforms.lookup(platform)
|
156
161
|
|
157
|
-
if payload_class.should_render?(
|
162
|
+
if payload_class.should_render?(headers[platform])
|
158
163
|
json = render_json(platform, headers)
|
159
|
-
payload[platform] = payload_class.new(json,
|
164
|
+
payload[platform] = payload_class.new(json, headers[platform], config)
|
160
165
|
end
|
161
166
|
end
|
162
167
|
|
data/lib/pushing/platforms.rb
CHANGED
@@ -25,19 +25,39 @@ module Pushing
|
|
25
25
|
options.is_a?(Hash) ? options[:device_token].present? : options.present?
|
26
26
|
end
|
27
27
|
|
28
|
-
def initialize(payload, options)
|
28
|
+
def initialize(payload, options, config = EMPTY_HASH)
|
29
|
+
@payload = payload
|
30
|
+
@environment = config[:environment]
|
31
|
+
@headers = config[:default_headers] || {}
|
32
|
+
|
33
|
+
if config[:topic]
|
34
|
+
ActiveSupport::Deprecation.warn "`config.apn.topic' is deprecated and will be removed in 0.3.0. " \
|
35
|
+
"Please use `config.apn.default_headers' instead:\n\n" \
|
36
|
+
" config.apn.default_headers = {\n" \
|
37
|
+
" apns_topic: '#{config[:topic]}'\n" \
|
38
|
+
" }", caller
|
39
|
+
|
40
|
+
@headers['apns-topic'] ||= config[:topic]
|
41
|
+
end
|
42
|
+
|
29
43
|
if options.is_a?(String)
|
30
44
|
@device_token = options
|
31
|
-
|
32
|
-
@device_token
|
45
|
+
elsif options.is_a?(Hash)
|
46
|
+
@device_token = options[:device_token]
|
47
|
+
@environment = options[:environment] || @environment
|
48
|
+
@headers = @headers.merge(options[:headers] || EMPTY_HASH)
|
49
|
+
else
|
50
|
+
raise TypeError, "The :apn key only takes a device token as a string or a hash that has `device_token: \"...\"'."
|
33
51
|
end
|
34
52
|
|
35
|
-
|
36
|
-
|
53
|
+
# raise("APNs environment is required.") if @environment.nil?
|
54
|
+
# raise("APNs device token is required.") if @device_token.nil?
|
55
|
+
|
56
|
+
@environment = @environment.to_sym
|
37
57
|
end
|
38
58
|
|
39
59
|
def recipients
|
40
|
-
Array(@device_token)
|
60
|
+
Array("#{@environment}/#{@device_token}")
|
41
61
|
end
|
42
62
|
|
43
63
|
def headers
|
data/lib/pushing/railtie.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "active_job/railtie"
|
2
2
|
require "rails"
|
3
|
+
require "abstract_controller/railties/routes_helpers"
|
3
4
|
|
4
5
|
module Pushing
|
5
6
|
class Railtie < Rails::Railtie # :nodoc:
|
@@ -16,6 +17,30 @@ module Pushing
|
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
20
|
+
initializer "pushing.set_configs" do |app|
|
21
|
+
paths = app.config.paths
|
22
|
+
options = ActiveSupport::OrderedOptions.new
|
23
|
+
|
24
|
+
if app.config.force_ssl
|
25
|
+
options.default_url_options ||= {}
|
26
|
+
options.default_url_options[:protocol] ||= "https"
|
27
|
+
end
|
28
|
+
|
29
|
+
options.assets_dir ||= paths["public"].first
|
30
|
+
|
31
|
+
# make sure readers methods get compiled
|
32
|
+
options.asset_host ||= app.config.asset_host
|
33
|
+
options.relative_url_root ||= app.config.relative_url_root
|
34
|
+
|
35
|
+
ActiveSupport.on_load(:pushing) do
|
36
|
+
include AbstractController::UrlFor
|
37
|
+
extend ::AbstractController::Railties::RoutesHelpers.with(app.routes, false)
|
38
|
+
include app.routes.mounted_helpers
|
39
|
+
|
40
|
+
options.each { |k, v| send("#{k}=", v) }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
19
44
|
initializer "pushing.compile_config_methods" do
|
20
45
|
ActiveSupport.on_load(:pushing) do
|
21
46
|
config.compile_methods! if config.respond_to?(:compile_methods!)
|
data/lib/pushing/version.rb
CHANGED
data/pushing.gemspec
CHANGED
@@ -7,14 +7,12 @@ Gem::Specification.new do |spec|
|
|
7
7
|
spec.name = "pushing"
|
8
8
|
spec.version = Pushing::VERSION
|
9
9
|
spec.authors = ["Yuki Nishijima"]
|
10
|
-
spec.email = ["
|
10
|
+
spec.email = ["yk.nishijima@gmail.com"]
|
11
11
|
spec.summary = %q{Push notification framework that does not hurt. finally.}
|
12
12
|
spec.description = %q{Pushing is like ActionMailer, but for sending push notifications.}
|
13
13
|
spec.homepage = "https://github.com/yuki24/pushing"
|
14
14
|
spec.license = "MIT"
|
15
15
|
spec.files = `git ls-files -z`.split("\x0").reject {|f| f.match(%r{^(test)/}) }
|
16
|
-
spec.bindir = "exe"
|
17
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
16
|
spec.require_paths = ["lib"]
|
19
17
|
|
20
18
|
spec.add_dependency "actionpack", ">= 4.2.0"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pushing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yuki Nishijima
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|
@@ -138,7 +138,7 @@ dependencies:
|
|
138
138
|
version: '0'
|
139
139
|
description: Pushing is like ActionMailer, but for sending push notifications.
|
140
140
|
email:
|
141
|
-
-
|
141
|
+
- yk.nishijima@gmail.com
|
142
142
|
executables: []
|
143
143
|
extensions: []
|
144
144
|
extra_rdoc_files: []
|
@@ -153,10 +153,12 @@ files:
|
|
153
153
|
- Rakefile
|
154
154
|
- bin/console
|
155
155
|
- bin/setup
|
156
|
+
- certs/apns_auth_key_for_jwt_auth.p8.enc
|
156
157
|
- certs/apns_example_production.pem.enc
|
157
158
|
- gemfiles/rails_42.gemfile
|
158
159
|
- gemfiles/rails_50.gemfile
|
159
160
|
- gemfiles/rails_51.gemfile
|
161
|
+
- gemfiles/rails_52.gemfile
|
160
162
|
- gemfiles/rails_edge.gemfile
|
161
163
|
- lib/generators/pushing/USAGE
|
162
164
|
- lib/generators/pushing/notifier_generator.rb
|
@@ -204,7 +206,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
204
206
|
version: '0'
|
205
207
|
requirements: []
|
206
208
|
rubyforge_project:
|
207
|
-
rubygems_version: 2.6
|
209
|
+
rubygems_version: 2.7.6
|
208
210
|
signing_key:
|
209
211
|
specification_version: 4
|
210
212
|
summary: Push notification framework that does not hurt. finally.
|