apple_shove 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|