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 CHANGED
@@ -2,30 +2,72 @@
2
2
 
3
3
  APN Service Provider. More powerful than a push...
4
4
 
5
- ## Installation
5
+ ## Why?
6
6
 
7
- Add this line to your application's Gemfile:
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
- gem 'apple_shove'
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
- And then execute:
11
+ ### What about [arthurnn/apn_sender](https://github.com/arthurnn/apn_sender)?
12
12
 
13
- $ bundle
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
- Or install it yourself as:
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
- $ gem install apple_shove
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
- ### Optional Command Line Arguments
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=log
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
- ## TCP Keep-Alives
98
+ ### TCP Keep-Alives
41
99
 
42
- Apple Shove 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.
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, Apple Shove enables keep-alive on all connections to Apple. Apple Shove 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 either 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 Apple Shove to re-establish the SSL connection after enough idle time has passed.
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
- ## Gotchas
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($/)
@@ -1,3 +1,3 @@
1
1
  module AppleShove
2
- VERSION = "1.0.1"
2
+ VERSION = "1.0.2"
3
3
  end
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.1
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-07 00:00:00.000000000 Z
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: -1646100289206665010
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: -1646100289206665010
165
+ hash: 3074046605150142324
166
166
  requirements: []
167
167
  rubyforge_project:
168
168
  rubygems_version: 1.8.24