apnotic 0.9.2 → 0.10.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 +4 -4
- data/.ruby-version +1 -1
- data/README.md +81 -0
- data/apnotic.gemspec +1 -1
- data/lib/apnotic.rb +1 -0
- data/lib/apnotic/connection.rb +20 -3
- data/lib/apnotic/notification.rb +2 -1
- data/lib/apnotic/push.rb +38 -0
- data/lib/apnotic/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9493fd00daf33a8bd13d087bcd119929b236372e
|
4
|
+
data.tar.gz: 68215cff5cfc93dd0aafdccf2188da4f6fe9b085
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5bad7e789438d5e5710a433501dff4e41fa50633f22fe0eb9814653919b41a8ea34a84747854c17a0ccdb850e84f720cf9d31f293a79e6a5b5c82ba2b80d7b77
|
7
|
+
data.tar.gz: 54014458ff59af3703d94b00ffe61a3074c05ba962b60c8183f084a89a113d5051f50235c0d43b0e8c8c4a8db850ab504382b7dab8432940b8a8a4ea1762b0dd
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-2.3.
|
1
|
+
ruby-2.3.1
|
data/README.md
CHANGED
@@ -28,6 +28,10 @@ gem 'apnotic'
|
|
28
28
|
## Usage
|
29
29
|
|
30
30
|
### Standalone
|
31
|
+
|
32
|
+
#### Sync pushes
|
33
|
+
Sync pushes are blocking calls that will wait for an APNs response before proceeding.
|
34
|
+
|
31
35
|
```ruby
|
32
36
|
require 'apnotic'
|
33
37
|
|
@@ -53,6 +57,42 @@ response.body # => ""
|
|
53
57
|
connection.close
|
54
58
|
```
|
55
59
|
|
60
|
+
#### Async pushes
|
61
|
+
If you are sending out a considerable amount of push notifications, you may consider using async pushes to send out multiple requests in non-blocking calls. This allows to take full advantage of HTTP/2 streams.
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
require 'apnotic'
|
65
|
+
|
66
|
+
# create a persistent connection
|
67
|
+
connection = Apnotic::Connection.new(cert_path: "apns_certificate.pem", cert_pass: "pass")
|
68
|
+
|
69
|
+
# create a notification for a specific device token
|
70
|
+
token = "6c267f26b173cd9595ae2f6702b1ab560371a60e7c8a9e27419bd0fa4a42e58f"
|
71
|
+
|
72
|
+
notification = Apnotic::Notification.new(token)
|
73
|
+
notification.alert = "Notification from Apnotic!"
|
74
|
+
|
75
|
+
# prepare push
|
76
|
+
push = connection.prepare_push(notification)
|
77
|
+
push.on(:response) do |response|
|
78
|
+
# read the response
|
79
|
+
response.ok? # => true
|
80
|
+
response.status # => '200'
|
81
|
+
response.headers # => {":status"=>"200", "apns-id"=>"6f2cd350-bfad-4af0-a8bc-0d501e9e1799"}
|
82
|
+
response.body # => ""
|
83
|
+
end
|
84
|
+
|
85
|
+
# send
|
86
|
+
connection.push_async(push)
|
87
|
+
|
88
|
+
# wait for all requests to be completed
|
89
|
+
connection.join
|
90
|
+
|
91
|
+
# close the connection
|
92
|
+
connection.close
|
93
|
+
```
|
94
|
+
|
95
|
+
|
56
96
|
### With Sidekiq / Rescue / ...
|
57
97
|
A practical usage of a Sidekiq / Rescue worker probably has to:
|
58
98
|
|
@@ -93,6 +133,7 @@ end
|
|
93
133
|
|
94
134
|
> The official [APNs Provider API documentation](https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/APNsProviderAPI.html) explains how to interpret the responses given by the APNS.
|
95
135
|
|
136
|
+
You may also consider using async pushes instead in a Sidekiq / Rescue worker.
|
96
137
|
|
97
138
|
|
98
139
|
## Objects
|
@@ -129,10 +170,26 @@ Apnotic::Connection.development(options)
|
|
129
170
|
|
130
171
|
Returns the path to the certificate
|
131
172
|
|
173
|
+
##### Blocking calls
|
174
|
+
|
132
175
|
* **push(notification, timeout: 30)** → **`Apnotic::Response` or `nil`**
|
133
176
|
|
134
177
|
Sends a notification. Returns `nil` in case a timeout occurs.
|
135
178
|
|
179
|
+
##### Non-blocking calls
|
180
|
+
|
181
|
+
* **prepare_push(notification)** → **`Apnotic::Push`**
|
182
|
+
|
183
|
+
Prepares an async push.
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
push = client.prepare_push(notification)
|
187
|
+
```
|
188
|
+
|
189
|
+
* **push_async(push)**
|
190
|
+
|
191
|
+
Sends the push asynchronously.
|
192
|
+
|
136
193
|
|
137
194
|
### `Apnotic::ConnectionPool`
|
138
195
|
For your convenience, a wrapper around the [Connection Pool](https://github.com/mperham/connection_pool) gem is here for you. To create a new connection pool:
|
@@ -172,6 +229,7 @@ These are all Accessor attributes.
|
|
172
229
|
| `priority` | "
|
173
230
|
| `topic` | "
|
174
231
|
| `url_args` | Values for [Safari push notifications](https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/NotificationProgrammingGuideForWebsites/PushNotifications/PushNotifications.html#//apple_ref/doc/uid/TP40013225-CH3-SW12).
|
232
|
+
| `mutable_content` | Key for [UNNotificationServiceExtension](https://developer.apple.com/reference/usernotifications/unnotificationserviceextension).
|
175
233
|
|
176
234
|
For example:
|
177
235
|
|
@@ -218,6 +276,29 @@ The response to a call to `connection.push`.
|
|
218
276
|
Returns the body of the response in Hash format if a valid JSON was returned, otherwise just the RAW body.
|
219
277
|
|
220
278
|
|
279
|
+
### `Apnotic::Push`
|
280
|
+
The push object to be sent in an async call.
|
281
|
+
|
282
|
+
#### Methods
|
283
|
+
|
284
|
+
* **on(event, &block)**
|
285
|
+
|
286
|
+
Allows to set a callback for the request. Available events are:
|
287
|
+
|
288
|
+
* `:response`: triggered when a response is fully received (called once).
|
289
|
+
|
290
|
+
Even if Apnotic is thread-safe, the async callbacks will be executed in a different thread, so ensure that your code in the callbacks is thread-safe.
|
291
|
+
|
292
|
+
```ruby
|
293
|
+
push.on(:response) { |response| p response.headers }
|
294
|
+
```
|
295
|
+
|
296
|
+
* **http2_request** → **`NetHttp2::Request`**
|
297
|
+
|
298
|
+
Returns the HTTP/2 request of the push.
|
299
|
+
|
300
|
+
|
301
|
+
|
221
302
|
## Getting Your APNs Certificate
|
222
303
|
|
223
304
|
> These instructions come from another great gem, [apn_on_rails](https://github.com/PRX/apn_on_rails).
|
data/apnotic.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency "net-http2", "~> 0.
|
21
|
+
spec.add_dependency "net-http2", "~> 0.12.0"
|
22
22
|
spec.add_dependency "connection_pool", "~> 2.0"
|
23
23
|
|
24
24
|
spec.add_development_dependency "bundler", "~> 1.3"
|
data/lib/apnotic.rb
CHANGED
data/lib/apnotic/connection.rb
CHANGED
@@ -17,9 +17,9 @@ module Apnotic
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def initialize(options={})
|
20
|
-
@url
|
21
|
-
@cert_path
|
22
|
-
@cert_pass
|
20
|
+
@url = options[:url] || APPLE_PRODUCTION_SERVER_URL
|
21
|
+
@cert_path = options[:cert_path]
|
22
|
+
@cert_pass = options[:cert_pass]
|
23
23
|
@connect_timeout = options[:connect_timeout] || 30
|
24
24
|
|
25
25
|
raise "Cert file not found: #{@cert_path}" unless @cert_path && (@cert_path.respond_to?(:read) || File.exist?(@cert_path))
|
@@ -37,10 +37,27 @@ module Apnotic
|
|
37
37
|
Apnotic::Response.new(headers: response.headers, body: response.body) if response
|
38
38
|
end
|
39
39
|
|
40
|
+
def push_async(push)
|
41
|
+
@client.call_async(push.http2_request)
|
42
|
+
end
|
43
|
+
|
44
|
+
def prepare_push(notification)
|
45
|
+
request = Apnotic::Request.new(notification)
|
46
|
+
http2_request = @client.prepare_request(:post, request.path,
|
47
|
+
body: request.body,
|
48
|
+
headers: request.headers
|
49
|
+
)
|
50
|
+
Apnotic::Push.new(http2_request)
|
51
|
+
end
|
52
|
+
|
40
53
|
def close
|
41
54
|
@client.close
|
42
55
|
end
|
43
56
|
|
57
|
+
def join
|
58
|
+
@client.join
|
59
|
+
end
|
60
|
+
|
44
61
|
private
|
45
62
|
|
46
63
|
def ssl_context
|
data/lib/apnotic/notification.rb
CHANGED
@@ -5,7 +5,7 @@ module Apnotic
|
|
5
5
|
|
6
6
|
class Notification
|
7
7
|
attr_reader :token
|
8
|
-
attr_accessor :alert, :badge, :sound, :content_available, :category, :custom_payload, :url_args
|
8
|
+
attr_accessor :alert, :badge, :sound, :content_available, :category, :custom_payload, :url_args, :mutable_content
|
9
9
|
attr_accessor :apns_id, :expiration, :priority, :topic
|
10
10
|
|
11
11
|
def initialize(token)
|
@@ -28,6 +28,7 @@ module Apnotic
|
|
28
28
|
aps.merge!(category: category) if category
|
29
29
|
aps.merge!('content-available' => content_available) if content_available
|
30
30
|
aps.merge!('url-args' => url_args) if url_args
|
31
|
+
aps.merge!('mutable-content' => mutable_content) if mutable_content
|
31
32
|
|
32
33
|
n = { aps: aps }
|
33
34
|
n.merge!(custom_payload) if custom_payload
|
data/lib/apnotic/push.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module Apnotic
|
2
|
+
|
3
|
+
class Push
|
4
|
+
attr_reader :http2_request
|
5
|
+
|
6
|
+
def initialize(http2_request)
|
7
|
+
@http2_request = http2_request
|
8
|
+
@headers = {}
|
9
|
+
@data = ''
|
10
|
+
@events = {}
|
11
|
+
|
12
|
+
listen_for_http2_events
|
13
|
+
end
|
14
|
+
|
15
|
+
def on(event, &block)
|
16
|
+
raise ArgumentError, 'on event must provide a block' unless block_given?
|
17
|
+
|
18
|
+
@events[event] ||= []
|
19
|
+
@events[event] << block
|
20
|
+
end
|
21
|
+
|
22
|
+
def emit(event, arg)
|
23
|
+
return unless @events[event]
|
24
|
+
@events[event].each { |b| b.call(arg) }
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def listen_for_http2_events
|
30
|
+
@http2_request.on(:headers) { |headers| @headers.merge!(headers) }
|
31
|
+
@http2_request.on(:body_chunk) { |chunk| @data << chunk }
|
32
|
+
@http2_request.on(:close) do
|
33
|
+
response = Apnotic::Response.new(headers: @headers, body: @data)
|
34
|
+
emit(:response, response)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/apnotic/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apnotic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roberto Ostinelli
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-06-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: net-http2
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.12.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.12.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: connection_pool
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -103,6 +103,7 @@ files:
|
|
103
103
|
- lib/apnotic/connection.rb
|
104
104
|
- lib/apnotic/connection_pool.rb
|
105
105
|
- lib/apnotic/notification.rb
|
106
|
+
- lib/apnotic/push.rb
|
106
107
|
- lib/apnotic/request.rb
|
107
108
|
- lib/apnotic/response.rb
|
108
109
|
- lib/apnotic/version.rb
|