apple_shove 1.0.1 → 1.0.2
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.
- data/README.md +76 -18
- data/apple_shove.gemspec +1 -1
- data/lib/apple_shove/version.rb +1 -1
- metadata +5 -5
data/README.md
CHANGED
@@ -2,30 +2,72 @@
|
|
2
2
|
|
3
3
|
APN Service Provider. More powerful than a push...
|
4
4
|
|
5
|
-
##
|
5
|
+
## Why?
|
6
6
|
|
7
|
-
|
7
|
+
A quick look at [The Ruby Toolbox](https://www.ruby-toolbox.com/search?utf8=✓&q=apns) reveals a ton of pre-existing APNS gems. Why recreate the wheel?
|
8
8
|
|
9
|
-
|
9
|
+
We needed an APNS package for use with a many-tenant MDM platform. Specifically, we needed the ability to quickly push many notifications to devices spanning across *many* push certificates.
|
10
10
|
|
11
|
-
|
11
|
+
### What about [arthurnn/apn_sender](https://github.com/arthurnn/apn_sender)?
|
12
12
|
|
13
|
-
|
13
|
+
We started here and eventually [forked](https://github.com/tboyko/apn_sender) and added MDM support. **apn_sender** keeps a persistent connection to Apple, which is great. It doesn't handle multiple certificates though, so that means we'd have to have a separate daemon process running for every single push certificate.
|
14
14
|
|
15
|
-
|
15
|
+
In fact, most APNS packages were eliminated for this reason: They weren't built with multiple-certificate handling in mind, meaning something costly would have to be instantiated for each certificate.
|
16
16
|
|
17
|
-
|
17
|
+
### What about [jeremytregunna/racoon](https://github.com/jeremytregunna/racoon)?
|
18
|
+
|
19
|
+
This gem sets out to solve multiple-certificate handling, but it fell short in two ways:
|
20
|
+
|
21
|
+
1. It requires the compilation and usage of a fork of ZMQMachine. We don't want to have to manually compile the gem and we don't want to depend on someone keeping a fork of a project maintained.
|
22
|
+
2. It assumes the bottleneck is in the building of the APNS message, not in the SSL connection setup/teardown with Apple. The gem instantiates many _workers_ for the activity of building the message to be pushed, but by default only runs a single _firehose_, which is responsible for connecting to Apple. We found the opposite to be true: the connection to Apple is the slowest part.
|
23
|
+
|
24
|
+
## How does AppleShove work?
|
25
|
+
|
26
|
+
In brief, AppleShove receives push requests from a Redis queue structure. These push requests include the APNS certificate and the payload to be pushed. A single thread called the _demultiplexer_ reads from this Redis queue and also manages a pool of connection threads to Apple. When a request is received, the _demultiplexer_ sends the request to the appropriate connection thread. If the connection thread doesn't already exist, it's created first. That's it!
|
27
|
+
|
28
|
+
For you concurrency fans out there, we are using the Actor concurrency pattern via [Celluloid](https://github.com/celluloid/celluloid).
|
29
|
+
|
30
|
+
This architecture accomplishes a few things:
|
31
|
+
|
32
|
+
1. "Caches" connections to Apple. If we've sent a notification with a particular certificate recently, we get to reuse the connection instead of having to re-establish it.
|
33
|
+
2. Allows notifications to be sent in parallel. We aren't waiting for a series of connections and disconnections to take place before we can send notification #n.
|
34
|
+
3. Simplifies our client implementation. Since each notification contains all of the information AppleShove needs to send it on it's way, we can request notifications via a single static method.
|
35
|
+
|
36
|
+
Willing to give it a try? Onward...
|
18
37
|
|
19
38
|
## Usage
|
20
39
|
|
40
|
+
### Sending Notifications
|
41
|
+
|
42
|
+
Sending a notification request looks like this:
|
43
|
+
|
44
|
+
apns_p12 = File.read('my_cert.p12')
|
45
|
+
token = '[device token string]'
|
46
|
+
payload = { mdm: '[push magic string]' } # this can also be an app notification
|
47
|
+
|
48
|
+
AppleShove.notify(apns_p12, token, payload)
|
49
|
+
|
50
|
+
Need it to be a sandbox notification?
|
51
|
+
|
52
|
+
sandbox = true
|
53
|
+
AppleShove.notify(apns_p12, token, payload, sandbox)
|
54
|
+
|
55
|
+
### Checking the Feedback Service
|
56
|
+
|
57
|
+
We also have a feedback mechanism in place:
|
58
|
+
|
59
|
+
tokens_array = AppleShove.feedback_tokens(apns_p12)
|
60
|
+
|
61
|
+
### Running the Service
|
62
|
+
|
21
63
|
# bundle exec rake -T
|
22
|
-
bundle exec rake apple_shove:run
|
23
|
-
bundle exec rake apple_shove:start
|
24
|
-
bundle exec rake apple_shove:stop
|
25
|
-
bundle exec rake apple_shove:status
|
26
|
-
bundle exec rake apple_shove:stats
|
64
|
+
bundle exec rake apple_shove:run # run in the foreground
|
65
|
+
bundle exec rake apple_shove:start # start as a daemon
|
66
|
+
bundle exec rake apple_shove:stop # stop the daemon
|
67
|
+
bundle exec rake apple_shove:status # see status of daemon
|
68
|
+
bundle exec rake apple_shove:stats # stats related to daemon
|
27
69
|
|
28
|
-
|
70
|
+
#### Optional Command Line Arguments
|
29
71
|
|
30
72
|
log_dir: specify an absolute path if you want to log
|
31
73
|
pid_dir: specify an absolute or relative path where the PID file
|
@@ -35,13 +77,29 @@ Or install it yourself as:
|
|
35
77
|
|
36
78
|
Example usage:
|
37
79
|
|
38
|
-
bundle exec rake apple_shove:start connection_limit=100 log_dir
|
80
|
+
bundle exec rake apple_shove:start connection_limit=100 log_dir=/var/log
|
81
|
+
|
82
|
+
## Installation
|
83
|
+
|
84
|
+
Add this line to your application's Gemfile:
|
85
|
+
|
86
|
+
gem 'apple_shove'
|
87
|
+
|
88
|
+
And then execute:
|
89
|
+
|
90
|
+
$ bundle
|
91
|
+
|
92
|
+
Or install it yourself as:
|
93
|
+
|
94
|
+
$ gem install apple_shove
|
95
|
+
|
96
|
+
## Additional Notes
|
39
97
|
|
40
|
-
|
98
|
+
### TCP Keep-Alives
|
41
99
|
|
42
|
-
|
100
|
+
AppleShove has the ability to maintain connections to Apple for long durations of time without sending a notification. These connections will generally stay open, however, intermediate NATs and firewalls may expire and close the connection prematurely.
|
43
101
|
|
44
|
-
To combat this,
|
102
|
+
To combat this, AppleShove enables keep-alive on all connections to Apple. AppleShove is not able to set the interval between keep-alives however, as this is generally managed by the operating system. If you are aware of a relatively short NAT or firewall timer, you can manually shorten your OS's keep-alive timer to be shorter than the timer. As this likely breaks the portability of your code, you can alternatively change the `AppleShove::CONFIG[:reconnect_timer]` to a value less than the NAT/firewall timer. This will force AppleShove to re-establish the SSL connection after enough idle time has passed.
|
45
103
|
|
46
104
|
For reference, we have observed the following keep-alive timeout values:
|
47
105
|
|
@@ -51,7 +109,7 @@ For reference, we have observed the following keep-alive timeout values:
|
|
51
109
|
|
52
110
|
Apple also seems to send a keep-alive packet if it sees the connection as idle for 10 minutes.
|
53
111
|
|
54
|
-
|
112
|
+
### Gotchas
|
55
113
|
|
56
114
|
Due to the TCP/IP stack, AppleShove will only know about a broken pipe to APNS after it writes two notifications to the socket. When this occurs, AppleShove will re-transmit the first as well as the second notification. Because time may have elapsed between the first and second notification writes, a non-trivial delay in the delivery of the first notification may occur.
|
57
115
|
|
data/apple_shove.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.email = ["tboyko@unwiredrevolution.com"]
|
11
11
|
spec.description = %q{APN Service Provider. More powerful than a push...}
|
12
12
|
spec.summary = %q{}
|
13
|
-
spec.homepage = ""
|
13
|
+
spec.homepage = "https://github.com/tboyko/apple_shove"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
16
|
spec.files = `git ls-files`.split($/)
|
data/lib/apple_shove/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apple_shove
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-05-
|
12
|
+
date: 2013-05-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -138,7 +138,7 @@ files:
|
|
138
138
|
- spec/notification_helper.rb
|
139
139
|
- spec/notification_queue_spec.rb
|
140
140
|
- spec/notification_spec.rb
|
141
|
-
homepage:
|
141
|
+
homepage: https://github.com/tboyko/apple_shove
|
142
142
|
licenses:
|
143
143
|
- MIT
|
144
144
|
post_install_message:
|
@@ -153,7 +153,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
153
153
|
version: '0'
|
154
154
|
segments:
|
155
155
|
- 0
|
156
|
-
hash:
|
156
|
+
hash: 3074046605150142324
|
157
157
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
158
158
|
none: false
|
159
159
|
requirements:
|
@@ -162,7 +162,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
162
162
|
version: '0'
|
163
163
|
segments:
|
164
164
|
- 0
|
165
|
-
hash:
|
165
|
+
hash: 3074046605150142324
|
166
166
|
requirements: []
|
167
167
|
rubyforge_project:
|
168
168
|
rubygems_version: 1.8.24
|