apns_dispatch 0.1.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.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +20 -0
- data/README.md +54 -0
- data/Rakefile +10 -0
- data/apns_dispatch.gemspec +25 -0
- data/lib/apns_dispatch.rb +16 -0
- data/lib/apns_dispatch/apn_feedback.rb +30 -0
- data/lib/apns_dispatch/apn_notification.rb +43 -0
- data/lib/apns_dispatch/apns_connection.rb +100 -0
- data/lib/apns_dispatch/apns_connection_pool.rb +25 -0
- data/lib/apns_dispatch/null_apns_connection.rb +9 -0
- data/lib/apns_dispatch/version.rb +3 -0
- data/spec/apns_dispatch/apn_feedback_spec.rb +22 -0
- data/spec/apns_dispatch/apn_notification_spec.rb +20 -0
- data/spec/apns_dispatch/apns_connection_pool_spec.rb +34 -0
- data/spec/apns_dispatch/apns_connection_spec.rb +122 -0
- data/spec/spec_helper.rb +4 -0
- metadata +117 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2012 SCVNGR, Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# ApnsDispatch
|
2
|
+
|
3
|
+
A simple Ruby framework for sending push notifications and receiving feedback using the Apple Push Notification service
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'apns_dispatch'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install apns_dispatch
|
18
|
+
|
19
|
+
## Sending Notifications
|
20
|
+
|
21
|
+
connection = ApnsConnection.new(CERTIFICATE, production: true)
|
22
|
+
ApnNotification.new(connection, DEVICE_TOKEN, 'a message to a device').send_notification
|
23
|
+
|
24
|
+
## Checking the Feedback Service
|
25
|
+
|
26
|
+
[Apple recommends](https://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingWIthAPS/CommunicatingWIthAPS.html#//apple_ref/doc/uid/TP40008194-CH101-SW3)
|
27
|
+
periodically checking their feedback service for device tokens that have failed delivery. The feedback
|
28
|
+
service also returns the time of the failure. If a device token was registered before the failure time,
|
29
|
+
it should be removed from your system.
|
30
|
+
|
31
|
+
connection = ApnsConnection.new(CERTIFICATE, production: true, feedback: true)
|
32
|
+
ApnFeedback.new(connection).failed_device_tokens.each do |device_token, failure_time|
|
33
|
+
# Delete this device token from your system, if the registration time is before failure_time
|
34
|
+
end
|
35
|
+
|
36
|
+
## Connection Pooling
|
37
|
+
|
38
|
+
If notifications are sent frequently, latency will be improved by reusing connections to the Push
|
39
|
+
Notification service. ApnsDispatch also provides connection pooling:
|
40
|
+
|
41
|
+
# Initiates a new connection to the APNs
|
42
|
+
connection = ApnsConnectionPool.connection(CERTIFICATE, production: true)
|
43
|
+
|
44
|
+
# This will return the same connection, rather than initiating a new one
|
45
|
+
connection = ApnsConnectionPool.connection(CERTIFICATE, production: true)
|
46
|
+
|
47
|
+
## Requirements
|
48
|
+
|
49
|
+
`apns_dispatch` requires Ruby 1.9+.
|
50
|
+
|
51
|
+
## License
|
52
|
+
|
53
|
+
`apns_dispatch` is written by Costa Walcott, and is Copyright 2012 SCVNGR, Inc. It is free software,
|
54
|
+
and may be redistributed under the terms specified in the MIT-LICENSE file.
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'apns_dispatch/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = 'apns_dispatch'
|
8
|
+
gem.version = ApnsDispatch::VERSION
|
9
|
+
gem.authors = ['Costa Walcott']
|
10
|
+
gem.email = ['costa@scvngr.com']
|
11
|
+
gem.summary = 'A simple Ruby framework for communicating with the APNs'
|
12
|
+
gem.description = 'A simple Ruby framework for sending push notifications and receiving feedback using the Apple Push Notification service'
|
13
|
+
gem.homepage = 'http://github.com/TheLevelUp/apns_dispatch'
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
|
+
|
18
|
+
gem.add_dependency 'json', '~> 1.7.5'
|
19
|
+
|
20
|
+
gem.add_development_dependency 'rake'
|
21
|
+
gem.add_development_dependency 'rspec', '~> 2.0'
|
22
|
+
|
23
|
+
gem.required_ruby_version = Gem::Requirement.new('>= 1.9.2')
|
24
|
+
gem.require_paths = ["lib"]
|
25
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# This gem provides a simple Ruby wrapper for communicating with the Apple Push Notification service
|
2
|
+
# (APNs). It handles SSL, sending push notifications to APNs using Apple's binary protocol, and
|
3
|
+
# retriving failed device tokens using the APN feedback service. Both development and production
|
4
|
+
# certificates are handled.
|
5
|
+
#
|
6
|
+
# Author:: Costa Walcott (mailto:costa@scvngr.com)
|
7
|
+
# Copyright:: Copyright (c) 2012 SCVNGR, Inc.
|
8
|
+
# License:: MIT
|
9
|
+
|
10
|
+
require 'json'
|
11
|
+
|
12
|
+
require 'apns_dispatch/apn_feedback'
|
13
|
+
require 'apns_dispatch/apn_notification'
|
14
|
+
require 'apns_dispatch/apns_connection'
|
15
|
+
require 'apns_dispatch/apns_connection_pool'
|
16
|
+
require 'apns_dispatch/version'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ApnsDispatch
|
2
|
+
# Retrieves and returns failed device tokens from production and development APNs connections.
|
3
|
+
|
4
|
+
class ApnFeedback
|
5
|
+
# Constants
|
6
|
+
FEEDBACK_PACKET_FORMAT = 'N1n1H140'
|
7
|
+
FEEDBACK_PACKET_LENGTH = 38
|
8
|
+
|
9
|
+
def initialize(connection)
|
10
|
+
@connection = connection
|
11
|
+
end
|
12
|
+
|
13
|
+
def failed_device_tokens
|
14
|
+
apns_feedback = []
|
15
|
+
|
16
|
+
while line = @connection.read(FEEDBACK_PACKET_LENGTH)
|
17
|
+
apns_feedback << unpackage(line)
|
18
|
+
end
|
19
|
+
|
20
|
+
apns_feedback
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def unpackage(line)
|
26
|
+
feedback = line.unpack(FEEDBACK_PACKET_FORMAT)
|
27
|
+
[feedback[2], Time.at(feedback[0])]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module ApnsDispatch
|
2
|
+
# Creates a packaged notification for the APNs. Based on code from https://github.com/jpoz/APNS.
|
3
|
+
|
4
|
+
class ApnNotification
|
5
|
+
def initialize(connection, token, message, options = {})
|
6
|
+
@connection = connection
|
7
|
+
@token = token
|
8
|
+
@message = message
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def send_notification
|
13
|
+
@connection.write notification_packet
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def binary_token
|
19
|
+
[@token].pack 'H*'
|
20
|
+
end
|
21
|
+
|
22
|
+
def command
|
23
|
+
0
|
24
|
+
end
|
25
|
+
|
26
|
+
def message_information
|
27
|
+
{
|
28
|
+
aps: {
|
29
|
+
alert: @message,
|
30
|
+
sound: 'default'
|
31
|
+
}
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def notification_packet
|
36
|
+
[command, binary_token.bytesize, binary_token, payload.bytesize, payload].pack 'cna*na*'
|
37
|
+
end
|
38
|
+
|
39
|
+
def payload
|
40
|
+
message_information.merge(@options).to_json
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
module ApnsDispatch
|
5
|
+
# Handles communication with the Apple Push Notification service (APNs).
|
6
|
+
# Based on code from https://github.com/itspriddle/apnd.
|
7
|
+
|
8
|
+
class ApnsConnection
|
9
|
+
# Constants
|
10
|
+
FEEDBACK_PORT = 2196
|
11
|
+
GATEWAY_PORT = 2195
|
12
|
+
PRODUCTION_FEEDBACK_HOST = 'feedback.push.apple.com'
|
13
|
+
PRODUCTION_GATEWAY_HOST = 'gateway.push.apple.com'
|
14
|
+
SANDBOX_FEEDBACK_HOST = 'feedback.sandbox.push.apple.com'
|
15
|
+
SANDBOX_GATEWAY_HOST = 'gateway.sandbox.push.apple.com'
|
16
|
+
|
17
|
+
# Attributes
|
18
|
+
attr_reader :certificate, :host, :options, :port
|
19
|
+
|
20
|
+
def initialize(certificate, options={})
|
21
|
+
if options[:feedback]
|
22
|
+
@port = FEEDBACK_PORT
|
23
|
+
|
24
|
+
if options[:production]
|
25
|
+
@host = PRODUCTION_FEEDBACK_HOST
|
26
|
+
else
|
27
|
+
@host = SANDBOX_FEEDBACK_HOST
|
28
|
+
end
|
29
|
+
else
|
30
|
+
@port = GATEWAY_PORT
|
31
|
+
|
32
|
+
if options[:production]
|
33
|
+
@host = PRODUCTION_GATEWAY_HOST
|
34
|
+
else
|
35
|
+
@host = SANDBOX_GATEWAY_HOST
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
@certificate = certificate
|
40
|
+
@options = options
|
41
|
+
end
|
42
|
+
|
43
|
+
def read(length)
|
44
|
+
with_connection { @ssl.read(length) }
|
45
|
+
end
|
46
|
+
|
47
|
+
def write(message)
|
48
|
+
with_connection { @ssl.write(message) }
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def connect!
|
54
|
+
context = OpenSSL::SSL::SSLContext.new
|
55
|
+
context.cert = OpenSSL::X509::Certificate.new(@certificate)
|
56
|
+
context.key = OpenSSL::PKey::RSA.new(@certificate)
|
57
|
+
|
58
|
+
@sock = TCPSocket.new(host, port)
|
59
|
+
@ssl = OpenSSL::SSL::SSLSocket.new(@sock, context)
|
60
|
+
@ssl.sync = true
|
61
|
+
@ssl.connect
|
62
|
+
end
|
63
|
+
|
64
|
+
def connected?
|
65
|
+
!@ssl.nil?
|
66
|
+
end
|
67
|
+
|
68
|
+
def disconnect!
|
69
|
+
@ssl.close
|
70
|
+
@sock.close
|
71
|
+
@ssl = nil
|
72
|
+
@sock = nil
|
73
|
+
end
|
74
|
+
|
75
|
+
def reconnect!
|
76
|
+
disconnect!
|
77
|
+
connect!
|
78
|
+
end
|
79
|
+
|
80
|
+
def with_connection
|
81
|
+
unless connected?
|
82
|
+
connect!
|
83
|
+
end
|
84
|
+
|
85
|
+
attempted = false
|
86
|
+
|
87
|
+
begin
|
88
|
+
if block_given?
|
89
|
+
yield
|
90
|
+
end
|
91
|
+
rescue Errno::EPIPE, OpenSSL::SSL::SSLError
|
92
|
+
unless attempted
|
93
|
+
reconnect!
|
94
|
+
attempted = true
|
95
|
+
retry
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
require 'apns_dispatch/null_apns_connection'
|
3
|
+
|
4
|
+
module ApnsDispatch
|
5
|
+
# Caches and returns individual unique ApnsConnections in memory.
|
6
|
+
|
7
|
+
class ApnsConnectionPool
|
8
|
+
def self.connection(certificate, options={})
|
9
|
+
if certificate
|
10
|
+
cache_key = cache_key(certificate, options)
|
11
|
+
|
12
|
+
@connections ||= {}
|
13
|
+
@connections[cache_key] ||= ApnsDispatch::ApnsConnection.new(certificate, options)
|
14
|
+
else
|
15
|
+
ApnsDispatch::NullApnsConnection.new
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def self.cache_key(certificate, options)
|
22
|
+
[Digest::MD5.hexdigest(certificate), options.hash]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ApnsDispatch::ApnFeedback do
|
4
|
+
# Helpers
|
5
|
+
def packed_feedback(feedback)
|
6
|
+
[feedback[1].to_i, 140, feedback[0]].pack 'N1n1H*'
|
7
|
+
end
|
8
|
+
|
9
|
+
before do
|
10
|
+
@failed_token = ['ced238e503ece0f6d664e1b8bdae7d9dffc39c2303bf7466cd83cb2783ad40b2',
|
11
|
+
Time.new(2012, 9, 1)]
|
12
|
+
|
13
|
+
apn_connection = stub
|
14
|
+
apn_connection.stub(:read).with(38).and_return packed_feedback(@failed_token), nil
|
15
|
+
|
16
|
+
@apn_feedback = ApnsDispatch::ApnFeedback.new(apn_connection)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'returns the failed tokens' do
|
20
|
+
[@failed_token].should == @apn_feedback.failed_device_tokens
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ApnsDispatch::ApnNotification do
|
4
|
+
before do
|
5
|
+
token = '7307dea69c58e9625250aabb040594e1a031f574dba5d97549fbe211327aff4c'
|
6
|
+
message = 'test message'
|
7
|
+
options = { order_id: 12345 }
|
8
|
+
@connection = stub
|
9
|
+
@apn_notificiation = ApnsDispatch::ApnNotification.new(@connection, token, message, options)
|
10
|
+
|
11
|
+
payload = { aps: { alert: message, sound: 'default'} }.merge(options).to_json
|
12
|
+
@packet = [0, 32, [token].pack('H*'), payload.bytesize, payload].pack('cna*na*')
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'sends a notification packet to the connection' do
|
16
|
+
@connection.should_receive(:write).with(@packet)
|
17
|
+
|
18
|
+
@apn_notificiation.send_notification
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ApnsDispatch::ApnsConnectionPool do
|
4
|
+
before do
|
5
|
+
@options = { production: true }
|
6
|
+
end
|
7
|
+
|
8
|
+
context 'when a certificate is given' do
|
9
|
+
before do
|
10
|
+
@certificate = 'test-certificate'
|
11
|
+
@connection = ApnsDispatch::ApnsConnectionPool.connection(@certificate, @options)
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when called for the first time' do
|
15
|
+
it 'returns a new ApnsConnection with the correct values' do
|
16
|
+
@connection.certificate.should == @certificate
|
17
|
+
@connection.options.should == @options
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'when called after the first time' do
|
22
|
+
it 'returns the same connection' do
|
23
|
+
ApnsDispatch::ApnsConnectionPool.connection(@certificate, @options).should == @connection
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when a nil certificate is given' do
|
29
|
+
it 'returns a null connection' do
|
30
|
+
result = ApnsDispatch::ApnsConnectionPool.connection(nil)
|
31
|
+
result.should be_kind_of(ApnsDispatch::NullApnsConnection)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ApnsDispatch::ApnsConnection do
|
4
|
+
# Helpers
|
5
|
+
def self.should_run_command_with_connection(command, argument)
|
6
|
+
before do
|
7
|
+
TCPSocket.stub new: stub(close: true)
|
8
|
+
|
9
|
+
certificate = 'test-certificate'
|
10
|
+
@ssl = stub(close: true, connect: true, read: true, 'sync=' => true, write: true)
|
11
|
+
OpenSSL::SSL::SSLSocket.stub new: @ssl
|
12
|
+
OpenSSL::X509::Certificate.stub new: certificate
|
13
|
+
OpenSSL::PKey::RSA.stub new: certificate
|
14
|
+
|
15
|
+
@apns_connection = ApnsDispatch::ApnsConnection.new(certificate)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'runs the given block' do
|
19
|
+
@ssl.should_receive(command).with(argument)
|
20
|
+
|
21
|
+
@apns_connection.send command, argument
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'retries once' do
|
25
|
+
@ssl.should_receive(command).with(argument).twice.and_return do
|
26
|
+
unless @run
|
27
|
+
@run = true
|
28
|
+
raise OpenSSL::SSL::SSLError
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
@apns_connection.send command, argument
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'uses the correct host and port' do
|
36
|
+
TCPSocket.should_receive(:new).with(@apns_connection.host, @apns_connection.port)
|
37
|
+
|
38
|
+
@apns_connection.send command, argument
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when there is no connection' do
|
42
|
+
it 'initiates a connection' do
|
43
|
+
@ssl.should_receive :connect
|
44
|
+
|
45
|
+
@apns_connection.send command, argument
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when there is already a connection' do
|
50
|
+
before do
|
51
|
+
@apns_connection.instance_variable_set :@ssl, @ssl
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'does not reconnect' do
|
55
|
+
@ssl.should_receive(:connect).never
|
56
|
+
|
57
|
+
@apns_connection.send command, argument
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'has the correct APNs hosts and ports' do
|
63
|
+
ApnsDispatch::ApnsConnection::FEEDBACK_PORT.should == 2196
|
64
|
+
ApnsDispatch::ApnsConnection::GATEWAY_PORT.should == 2195
|
65
|
+
ApnsDispatch::ApnsConnection::PRODUCTION_FEEDBACK_HOST.should == 'feedback.push.apple.com'
|
66
|
+
ApnsDispatch::ApnsConnection::PRODUCTION_GATEWAY_HOST.should == 'gateway.push.apple.com'
|
67
|
+
ApnsDispatch::ApnsConnection::SANDBOX_FEEDBACK_HOST.should == 'feedback.sandbox.push.apple.com'
|
68
|
+
ApnsDispatch::ApnsConnection::SANDBOX_GATEWAY_HOST.should == 'gateway.sandbox.push.apple.com'
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'with :feedback option and :production option' do
|
72
|
+
before do
|
73
|
+
@connection = ApnsDispatch::ApnsConnection.new('test', feedback: true, production: true)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'uses the production feedback host and feedback port' do
|
77
|
+
@connection.host.should == ApnsDispatch::ApnsConnection::PRODUCTION_FEEDBACK_HOST
|
78
|
+
@connection.port.should == ApnsDispatch::ApnsConnection::FEEDBACK_PORT
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'with :feedback option only' do
|
83
|
+
before do
|
84
|
+
@connection = ApnsDispatch::ApnsConnection.new('test', feedback: true)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'uses the sandbox feedback host and feedback port' do
|
88
|
+
@connection.host.should == ApnsDispatch::ApnsConnection::SANDBOX_FEEDBACK_HOST
|
89
|
+
@connection.port.should == ApnsDispatch::ApnsConnection::FEEDBACK_PORT
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'with :production option only' do
|
94
|
+
before do
|
95
|
+
@connection = ApnsDispatch::ApnsConnection.new('test', production: true)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'uses the production gateway host and gateway port' do
|
99
|
+
@connection.host.should == ApnsDispatch::ApnsConnection::PRODUCTION_GATEWAY_HOST
|
100
|
+
@connection.port.should == ApnsDispatch::ApnsConnection::GATEWAY_PORT
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'with no options' do
|
105
|
+
before do
|
106
|
+
@connection = ApnsDispatch::ApnsConnection.new('test')
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'uses the sandbox gateway host and gateway port' do
|
110
|
+
@connection.host.should == ApnsDispatch::ApnsConnection::SANDBOX_GATEWAY_HOST
|
111
|
+
@connection.port.should == ApnsDispatch::ApnsConnection::GATEWAY_PORT
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'with read command' do
|
116
|
+
should_run_command_with_connection :read, 10
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'with write command' do
|
120
|
+
should_run_command_with_connection :write, 'test message'
|
121
|
+
end
|
122
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: apns_dispatch
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Costa Walcott
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-05 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: json
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.7.5
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.7.5
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '2.0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.0'
|
62
|
+
description: A simple Ruby framework for sending push notifications and receiving
|
63
|
+
feedback using the Apple Push Notification service
|
64
|
+
email:
|
65
|
+
- costa@scvngr.com
|
66
|
+
executables: []
|
67
|
+
extensions: []
|
68
|
+
extra_rdoc_files: []
|
69
|
+
files:
|
70
|
+
- .gitignore
|
71
|
+
- Gemfile
|
72
|
+
- MIT-LICENSE
|
73
|
+
- README.md
|
74
|
+
- Rakefile
|
75
|
+
- apns_dispatch.gemspec
|
76
|
+
- lib/apns_dispatch.rb
|
77
|
+
- lib/apns_dispatch/apn_feedback.rb
|
78
|
+
- lib/apns_dispatch/apn_notification.rb
|
79
|
+
- lib/apns_dispatch/apns_connection.rb
|
80
|
+
- lib/apns_dispatch/apns_connection_pool.rb
|
81
|
+
- lib/apns_dispatch/null_apns_connection.rb
|
82
|
+
- lib/apns_dispatch/version.rb
|
83
|
+
- spec/apns_dispatch/apn_feedback_spec.rb
|
84
|
+
- spec/apns_dispatch/apn_notification_spec.rb
|
85
|
+
- spec/apns_dispatch/apns_connection_pool_spec.rb
|
86
|
+
- spec/apns_dispatch/apns_connection_spec.rb
|
87
|
+
- spec/spec_helper.rb
|
88
|
+
homepage: http://github.com/TheLevelUp/apns_dispatch
|
89
|
+
licenses: []
|
90
|
+
post_install_message:
|
91
|
+
rdoc_options: []
|
92
|
+
require_paths:
|
93
|
+
- lib
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ! '>='
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: 1.9.2
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - ! '>='
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
requirements: []
|
107
|
+
rubyforge_project:
|
108
|
+
rubygems_version: 1.8.24
|
109
|
+
signing_key:
|
110
|
+
specification_version: 3
|
111
|
+
summary: A simple Ruby framework for communicating with the APNs
|
112
|
+
test_files:
|
113
|
+
- spec/apns_dispatch/apn_feedback_spec.rb
|
114
|
+
- spec/apns_dispatch/apn_notification_spec.rb
|
115
|
+
- spec/apns_dispatch/apns_connection_pool_spec.rb
|
116
|
+
- spec/apns_dispatch/apns_connection_spec.rb
|
117
|
+
- spec/spec_helper.rb
|