pushing 0.1.0 → 0.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 562381d6f82d103cc6e5db2b3408ea36d28fdb7a
4
- data.tar.gz: 4df883a714c37d2a87f7555b75eb1cce48d5f370
2
+ SHA256:
3
+ metadata.gz: e6d63cb3c86db8e3be6c3335fb26e7e028ba5b25eb9ad13aa4b8febbf82d432c
4
+ data.tar.gz: 82d5cf8214b81355a1dbc1db23843525e492889af24f0750874d1ec626830767
5
5
  SHA512:
6
- metadata.gz: be1bde88cd14ce57d6196cffb630bcf228d89e47040c7cce38e3887b6291bc32ff0edf83ed93ce3532deb1b9f477ab9990f0fae094df5a9f1566ed4816524e42
7
- data.tar.gz: 060ca860f1f7960dfa264c4d5fd3ee6aa21fa11546cd6dcf6ce6cc87e6d879a16f0ab1211b9715925938fc64e38251cc14771767c5437a59d355f226ad44cce9
6
+ metadata.gz: 2f6c64a1574f61b456656018eb94fe6c73f3638745c8c26420f22098ef0de9188511e317a7f070ad2b683c58785650634fb03e2db9ccc6278f4e1280d7729e46
7
+ data.tar.gz: 5c31ab15a5ec3f68622167ea05fe89eaf9b43c563d65f02d903f3793e3a5c22674d90af97d631dfe79df086524dd2f85f873298bff5136443358dc6944687e14
data/.gitignore CHANGED
@@ -10,3 +10,4 @@
10
10
  gemfiles/*.lock
11
11
  certs/apns_example_production.pem
12
12
  gemfiles/.bundle/
13
+ certs/apns_auth_key_for_jwt_auth.p8
@@ -4,25 +4,35 @@ cache: bundler
4
4
  sudo: false
5
5
 
6
6
  before_install:
7
- 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
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.7
11
- - 2.3.4
12
- - 2.4.1
13
+ - 2.2.9
14
+ - 2.3.6
15
+ - 2.4.3
16
+ - 2.5.0
13
17
  - ruby-head
14
- - jruby-9.1.10.0
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.10.0
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 "rails_50" do
11
- gem "railties", '~> 5.0.0'
12
- gem "actionpack", '~> 5.0.0'
13
- gem "actionview", '~> 5.0.0'
14
- gem "activejob", '~> 5.0.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
@@ -5,7 +5,7 @@ gemspec
5
5
 
6
6
  # APNs
7
7
  gem 'houston', require: false
8
- gem 'apnotic', require: false
8
+ gem 'apnotic', '>= 1.2.0', require: false
9
9
  gem 'lowdown', require: false
10
10
 
11
11
  # FCM
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's APIs.
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's push notification implementation.
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', github: 'yuki24/pushing'
15
- gem 'jbuilder'
14
+ gem 'pushing'
15
+ gem 'jbuilder' # if you don't have it in your Gemfile
16
16
  ```
17
17
 
18
- As 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).
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 Client Gems
20
+ ### Supported Platforms
21
21
 
22
- Pushing itself doesn't make HTTP requests. Instead, it uses an adapter and let an underlaying gem do it. Currently, Pushing has support for the following client gems:
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 integration
37
- gem 'andpush' # FCM integration
36
+ gem 'apnotic' # APNs
37
+ gem 'andpush' # FCM
38
38
  ```
39
39
 
40
40
  ### Walkthrough to Writing a Notifier
41
41
 
42
- In this README, we'll use Twitter as an example. Suppose you'd like to send a push notification when a user receives a new direct message from other user. To get started, you can use Pushing's notifier generator:
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
- Notice that the `:apn` key takes a truthy string value while the `:fcm` key takes a boolean value. Also, Pushing only sends a notification for the platforms that are given a truthy value. For example, the call:
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 Push Notifications
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 the test environment, use the `:test` adapter instead of an actual adapter you'd like to use in development/production.
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 use the `#deliveries` method. Here is an example with [ActiveSupport::TestCase](http://api.rubyonrails.org/classes/ActiveSupport/TestCase.html):
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
@@ -3,7 +3,7 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "houston", require: false
6
- gem "apnotic", require: false
6
+ gem "apnotic", ">= 1.2.0", require: false
7
7
  gem "lowdown", require: false
8
8
  gem "andpush", require: false
9
9
  gem "fcm", require: false
@@ -3,7 +3,7 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "houston", require: false
6
- gem "apnotic", require: false
6
+ gem "apnotic", ">= 1.2.0", require: false
7
7
  gem "lowdown", require: false
8
8
  gem "andpush", require: false
9
9
  gem "fcm", require: false
@@ -3,7 +3,7 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "houston", require: false
6
- gem "apnotic", require: false
6
+ gem "apnotic", ">= 1.2.0", require: false
7
7
  gem "lowdown", require: false
8
8
  gem "andpush", require: false
9
9
  gem "fcm", require: false
@@ -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: "../"
@@ -10,7 +10,7 @@ git "git://github.com/rails/rails.git" do
10
10
  end
11
11
 
12
12
  gem "houston", require: false
13
- gem "apnotic", require: false
13
+ gem "apnotic", ">= 1.2.0", require: false
14
14
  gem "lowdown", require: false
15
15
  gem "andpush", require: false
16
16
  gem "fcm", require: false
@@ -1,10 +1,55 @@
1
1
  Pushing::Platforms.configure do |config|
2
- config.fcm.adapter = Rails.env.test? ? :test : :andpush
3
- config.fcm.server_key = 'YOUR_FCM_TEST_SERVER_KEY'
4
-
5
- config.apn.environment = Rails.env.production? ? :production : :development
6
- config.apn.adapter = Rails.env.test? ? :test : :apnotic
7
- config.apn.topic = 'com.awesomecompany.app'
8
- config.apn.certificate_path = '/config/your_certificate.pem'
9
- config.apn.certificate_password = 'PASSWORD_FOR_CERT'
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 :environment, :topic, :connection_pool
23
+ attr_reader :connection_pool
23
24
 
24
25
  def initialize(apn_settings)
25
- @environment = apn_settings.environment.to_sym
26
- @topic = apn_settings.topic
27
-
28
- options = {
29
- cert_path: apn_settings.certificate_path,
30
- cert_pass: apn_settings.certificate_password
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'] || 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 || environment].with {|connection| connection.push(message) }
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, :environment, :client
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 || environment].push(houston_notification)
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 :environment, :topic, :clients
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'] || topic
37
+ lowdown_notification.topic = notification.headers[:'apns-topic']
40
38
 
41
39
  response = nil
42
- clients[notification.environment || environment].group do |group|
40
+ clients[notification.environment].group do |group|
43
41
  group.send_notification(lowdown_notification) do |_response|
44
42
  response = _response
45
43
  end
@@ -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, options|
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?(options)
162
+ if payload_class.should_render?(headers[platform])
158
163
  json = render_json(platform, headers)
159
- payload[platform] = payload_class.new(json, options)
164
+ payload[platform] = payload_class.new(json, headers[platform], config)
160
165
  end
161
166
  end
162
167
 
@@ -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
- else options.is_a?(Hash)
32
- @device_token, @environment, @headers = options.values_at(:device_token, :environment, :headers)
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
- @payload = payload
36
- @headers ||= EMPTY_HASH
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
@@ -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!)
@@ -1,3 +1,3 @@
1
1
  module Pushing
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -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 = ["mail@yukinishijima.net"]
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.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuki Nishijima
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-28 00:00:00.000000000 Z
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
- - mail@yukinishijima.net
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.11
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.