rapns 2.0.5.rc1 → 2.0.5
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/CHANGELOG.md +6 -1
- data/README.md +2 -1
- data/bin/rapns +2 -7
- data/lib/rapns/app.rb +19 -1
- data/lib/rapns/config.rb +55 -0
- data/lib/rapns/daemon/feedback_receiver.rb +6 -1
- data/lib/rapns/daemon/logger.rb +2 -2
- data/lib/rapns/notification.rb +19 -5
- data/lib/rapns/version.rb +1 -1
- data/lib/rapns.rb +1 -0
- data/spec/rapns/app_spec.rb +89 -0
- data/spec/rapns/daemon/feedback_receiver_spec.rb +46 -20
- data/spec/rapns/daemon/logger_spec.rb +2 -2
- data/spec/rapns/feedback_spec.rb +3 -3
- data/spec/rapns/notification_spec.rb +18 -0
- metadata +8 -5
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
## 2.0.5 (Nov 4, 2012) ##
|
2
|
+
* Support content-available (#68).
|
3
|
+
* Append to log files.
|
4
|
+
* Fire a callback when Feedback is received.
|
5
|
+
|
1
6
|
## 2.0.5.rc1 (Oct 5, 2012) ##
|
2
7
|
* Release db connections back into the pool after use (#72).
|
3
8
|
* Continue to start daemon if a connection cannot be made during startup (#62) (@mattconnolly).
|
@@ -23,4 +28,4 @@
|
|
23
28
|
* Hot Updates - add/remove apps without restart.
|
24
29
|
* MDM support.
|
25
30
|
* Removed rapns.yml in favour of command line options.
|
26
|
-
* Started the changelog!
|
31
|
+
* Started the changelog!
|
data/README.md
CHANGED
@@ -15,7 +15,7 @@
|
|
15
15
|
|
16
16
|
### Who uses rapns?
|
17
17
|
|
18
|
-
[GateGuru](http://gateguruapp.com), among others!
|
18
|
+
[GateGuru](http://gateguruapp.com) and [Desk.com](http://desk.com), among others!
|
19
19
|
|
20
20
|
*I'd love to hear if you use rapns - @ileitch on twitter.*
|
21
21
|
|
@@ -166,3 +166,4 @@ Thank you to the following wonderful people for contributing to rapns:
|
|
166
166
|
* [@dei79](https://github.com/dei79)
|
167
167
|
* [@adorr](https://github.com/adorr)
|
168
168
|
* [@mattconnolly](https://github.com/mattconnolly)
|
169
|
+
* [@emeitch](https://github.com/emeitch)
|
data/bin/rapns
CHANGED
@@ -5,13 +5,7 @@ require 'rapns'
|
|
5
5
|
|
6
6
|
environment = ARGV[0]
|
7
7
|
|
8
|
-
config =
|
9
|
-
config.foreground = false
|
10
|
-
config.push_poll = 2
|
11
|
-
config.feedback_poll = 60
|
12
|
-
config.airbrake_notify = true
|
13
|
-
config.check_for_errors = true
|
14
|
-
config.batch_size = 5000
|
8
|
+
config = Rapns.configuration
|
15
9
|
|
16
10
|
banner = 'Usage: rapns <Rails environment> [options]'
|
17
11
|
ARGV.options do |opts|
|
@@ -35,6 +29,7 @@ end
|
|
35
29
|
|
36
30
|
ENV['RAILS_ENV'] = environment
|
37
31
|
load 'config/environment.rb'
|
32
|
+
load 'config/initializers/rapns.rb' if File.exist?('config/initializers/rapns.rb')
|
38
33
|
|
39
34
|
require 'rapns/daemon'
|
40
35
|
require 'rapns/patches'
|
data/lib/rapns/app.rb
CHANGED
@@ -8,5 +8,23 @@ module Rapns
|
|
8
8
|
validates :environment, :presence => true, :inclusion => { :in => %w(development production) }
|
9
9
|
validates :certificate, :presence => true
|
10
10
|
validates_numericality_of :connections, :greater_than => 0, :only_integer => true
|
11
|
+
|
12
|
+
validate :certificate_has_matching_private_key
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def certificate_has_matching_private_key
|
17
|
+
result = false
|
18
|
+
if certificate.present?
|
19
|
+
x509 = OpenSSL::X509::Certificate.new certificate rescue nil
|
20
|
+
pkey = OpenSSL::PKey::RSA.new certificate rescue nil
|
21
|
+
result = !x509.nil? && !pkey.nil?
|
22
|
+
unless result
|
23
|
+
errors.add :certificate, "Certificate value must contain a certificate and a private key"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
result
|
27
|
+
end
|
11
28
|
end
|
12
|
-
end
|
29
|
+
end
|
30
|
+
|
data/lib/rapns/config.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module Rapns
|
2
|
+
|
3
|
+
# A globally accessible instance of Rapns::Config
|
4
|
+
def self.configuration
|
5
|
+
@configuration ||= Rapns::Config.new
|
6
|
+
end
|
7
|
+
|
8
|
+
# Call the given block yielding to it the global Rapns::Config instance for setting
|
9
|
+
# configuration values / callbacks.
|
10
|
+
#
|
11
|
+
# Typically this would be used in your Rails application's config/initializers/rapns.rb file
|
12
|
+
def self.configure
|
13
|
+
yield configuration if block_given?
|
14
|
+
end
|
15
|
+
|
16
|
+
# A class to hold Rapns configuration settings and callbacks.
|
17
|
+
class Config < Struct.new(:foreground, :push_poll, :feedback_poll, :airbrake_notify, :check_for_errors, :pid_file, :batch_size)
|
18
|
+
|
19
|
+
attr_accessor :feedback_callback
|
20
|
+
|
21
|
+
# Initialize the Config with default values
|
22
|
+
def initialize
|
23
|
+
super
|
24
|
+
|
25
|
+
# defaults:
|
26
|
+
self.foreground = false
|
27
|
+
self.push_poll = 2
|
28
|
+
self.feedback_poll = 60
|
29
|
+
self.airbrake_notify = true
|
30
|
+
self.check_for_errors = true
|
31
|
+
self.batch_size = 5000
|
32
|
+
end
|
33
|
+
|
34
|
+
# Define a block that will be executed with a Rapns::Feedback instance when feedback has been received from the
|
35
|
+
# push notification servers that a notification has failed to be delivered. Further notifications should not
|
36
|
+
# be sent to this device token.
|
37
|
+
#
|
38
|
+
# Example usage (in config/initializers/rapns.rb):
|
39
|
+
#
|
40
|
+
# Rapns.configure do |config|
|
41
|
+
# config.on_feedback do |feedback|
|
42
|
+
# device = Device.find_by_device_token feedback.device_token
|
43
|
+
# if device
|
44
|
+
# device.active = false
|
45
|
+
# device.save
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# Where `Device` is a model specific to your Rails app that has a `device_token` field.
|
51
|
+
def on_feedback(&block)
|
52
|
+
self.feedback_callback = block
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -69,7 +69,12 @@ module Rapns
|
|
69
69
|
formatted_failed_at = failed_at.strftime("%Y-%m-%d %H:%M:%S UTC")
|
70
70
|
with_database_reconnect_and_retry do
|
71
71
|
Rapns::Daemon.logger.info("[FeedbackReceiver:#{@name}] Delivery failed at #{formatted_failed_at} for #{device_token}")
|
72
|
-
Rapns::Feedback.create!(:failed_at => failed_at, :device_token => device_token, :app => @name)
|
72
|
+
feedback = Rapns::Feedback.create!(:failed_at => failed_at, :device_token => device_token, :app => @name)
|
73
|
+
begin
|
74
|
+
Rapns.configuration.feedback_callback.call(feedback) if Rapns.configuration.feedback_callback
|
75
|
+
rescue Exception => e
|
76
|
+
Rapns::Daemon.logger.error(e)
|
77
|
+
end
|
73
78
|
end
|
74
79
|
end
|
75
80
|
end
|
data/lib/rapns/daemon/logger.rb
CHANGED
@@ -3,7 +3,7 @@ module Rapns
|
|
3
3
|
class Logger
|
4
4
|
def initialize(options)
|
5
5
|
@options = options
|
6
|
-
log = File.open(File.join(Rails.root, 'log', 'rapns.log'), '
|
6
|
+
log = File.open(File.join(Rails.root, 'log', 'rapns.log'), 'a')
|
7
7
|
log.sync = true
|
8
8
|
@logger = ActiveSupport::BufferedLogger.new(log, Rails.logger.level)
|
9
9
|
@logger.auto_flushing = Rails.logger.respond_to?(:auto_flushing) ? Rails.logger.auto_flushing : true
|
@@ -52,4 +52,4 @@ module Rapns
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
55
|
-
end
|
55
|
+
end
|
data/lib/rapns/notification.rb
CHANGED
@@ -52,22 +52,36 @@ module Rapns
|
|
52
52
|
multi_json_load(read_attribute(:attributes_for_device)) if read_attribute(:attributes_for_device)
|
53
53
|
end
|
54
54
|
|
55
|
-
|
55
|
+
MDM_KEY = '__rapns_mdm__'
|
56
56
|
def mdm=(magic)
|
57
|
-
self.attributes_for_device = {
|
57
|
+
self.attributes_for_device = { MDM_KEY => magic }
|
58
|
+
end
|
59
|
+
|
60
|
+
CONTENT_AVAILABLE_KEY = '__rapns_content_available__'
|
61
|
+
def content_available=(bool)
|
62
|
+
return unless bool
|
63
|
+
self.attributes_for_device = { CONTENT_AVAILABLE_KEY => true }
|
58
64
|
end
|
59
65
|
|
60
66
|
def as_json
|
61
67
|
json = ActiveSupport::OrderedHash.new
|
62
68
|
|
63
|
-
if attributes_for_device && attributes_for_device.key?(
|
64
|
-
json['mdm'] = attributes_for_device[
|
69
|
+
if attributes_for_device && attributes_for_device.key?(MDM_KEY)
|
70
|
+
json['mdm'] = attributes_for_device[MDM_KEY]
|
65
71
|
else
|
66
72
|
json['aps'] = ActiveSupport::OrderedHash.new
|
67
73
|
json['aps']['alert'] = alert if alert
|
68
74
|
json['aps']['badge'] = badge if badge
|
69
75
|
json['aps']['sound'] = sound if sound
|
70
|
-
|
76
|
+
|
77
|
+
if attributes_for_device && attributes_for_device[CONTENT_AVAILABLE_KEY]
|
78
|
+
json['aps']['content-available'] = 1
|
79
|
+
end
|
80
|
+
|
81
|
+
if attributes_for_device
|
82
|
+
non_aps_attributes = attributes_for_device.reject { |k, v| k == CONTENT_AVAILABLE_KEY }
|
83
|
+
non_aps_attributes.each { |k, v| json[k.to_s] = v.to_s }
|
84
|
+
end
|
71
85
|
end
|
72
86
|
|
73
87
|
json
|
data/lib/rapns/version.rb
CHANGED
data/lib/rapns.rb
CHANGED
@@ -0,0 +1,89 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
|
4
|
+
# a test certificate that contains both an X509 certificate and
|
5
|
+
# a private key, similar to those used for connecting to Apple
|
6
|
+
# push notification servers.
|
7
|
+
#
|
8
|
+
# Note that we cannot validate the certificate and private key
|
9
|
+
# because we are missing the certificate chain used to validate
|
10
|
+
# the certificate, and this is private to Apple. So if the app
|
11
|
+
# has a certificate and a private key in it, the only way to find
|
12
|
+
# out if it really is valid is to connect to Apple's servers.
|
13
|
+
#
|
14
|
+
TEST_CERT = <<EOF
|
15
|
+
Bag Attributes
|
16
|
+
friendlyName: test certificate
|
17
|
+
localKeyID: 00 93 8F E4 A3 C3 75 64 3D 7E EA 14 0B 0A EA DD 15 85 8A D5
|
18
|
+
subject=/CN=test certificate/O=Example/OU=Example/ST=QLD/C=AU/L=Example/emailAddress=user@example.com
|
19
|
+
issuer=/CN=test certificate/O=Example/OU=Example/ST=QLD/C=AU/L=Example/emailAddress=user@example.com
|
20
|
+
-----BEGIN CERTIFICATE-----
|
21
|
+
MIID5jCCAs6gAwIBAgIBATALBgkqhkiG9w0BAQswgY0xGTAXBgNVBAMMEHRlc3Qg
|
22
|
+
Y2VydGlmaWNhdGUxEDAOBgNVBAoMB0V4YW1wbGUxEDAOBgNVBAsMB0V4YW1wbGUx
|
23
|
+
DDAKBgNVBAgMA1FMRDELMAkGA1UEBhMCQVUxEDAOBgNVBAcMB0V4YW1wbGUxHzAd
|
24
|
+
BgkqhkiG9w0BCQEWEHVzZXJAZXhhbXBsZS5jb20wHhcNMTIwOTA5MDMxODMyWhcN
|
25
|
+
MjIwOTA3MDMxODMyWjCBjTEZMBcGA1UEAwwQdGVzdCBjZXJ0aWZpY2F0ZTEQMA4G
|
26
|
+
A1UECgwHRXhhbXBsZTEQMA4GA1UECwwHRXhhbXBsZTEMMAoGA1UECAwDUUxEMQsw
|
27
|
+
CQYDVQQGEwJBVTEQMA4GA1UEBwwHRXhhbXBsZTEfMB0GCSqGSIb3DQEJARYQdXNl
|
28
|
+
ckBleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKF+
|
29
|
+
UDsN1sLen8g+97PNTiWju9+wkSv+H5rQlvb6YFLPx11YvqpK8ms6kFU1OmWeLfmh
|
30
|
+
cpsT+bZtKupC7aGPoSG3RXzzf/YUMgs/ZSXA0idZHA6tkReAEzIX6jL5otfPWbaP
|
31
|
+
luCTUoVMeP4u9ywk628zlqh9IQHC1Agl0R1xGCpULDk8kn1gPyEisl38wI5aDbzy
|
32
|
+
6lYQGNUKOqt1xfVjtIFe/jyY/v0sxFjIJlRLcAFBuJx4sRV+PwRBkusOQtYwcwpI
|
33
|
+
loMxJj+GQe66ueATW81aC4iOU66DAFFEuGzwIwm3bOilimGGQbGb92F339RfmSOo
|
34
|
+
TPAvVhsakI3mzESb4lkCAwEAAaNRME8wDgYDVR0PAQH/BAQDAgeAMCAGA1UdJQEB
|
35
|
+
/wQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAbBgNVHREEFDASgRB1c2VyQGV4YW1w
|
36
|
+
bGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQA5UbNR+83ZdI2DiaB4dRmy0V5RDAqJ
|
37
|
+
k9+QskcTV4gBTjsOBS46Dw1tI6iTrfTyjYJdnyH0Y2Y2YVWBnvtON41UCZak+4ed
|
38
|
+
/IqyzU0dtfZ+frWa0RY4reyl80TwqnzyJfni0nDo4zGGvz70cxyaz2u1BWqwLjqb
|
39
|
+
dh8Dxvt+aHW2MQi0iGKh/HNbgwVanR4+ubNwziK9sR1Rnq9MkHWtwBw16SXQG6ao
|
40
|
+
SZKASWNaH8VL08Zz0E98cwd137UJkPsldCwJ8kHR5OzkcjPdXvnGD3d64yy2TC1Z
|
41
|
+
Gy1Aazt98wPcTYBytlhK8Rvzg9OoY9QmsdpmWxz1ZCXECJNqCa3IKsqO
|
42
|
+
-----END CERTIFICATE-----
|
43
|
+
Bag Attributes
|
44
|
+
friendlyName: test certificate
|
45
|
+
localKeyID: 00 93 8F E4 A3 C3 75 64 3D 7E EA 14 0B 0A EA DD 15 85 8A D5
|
46
|
+
Key Attributes: <No Attributes>
|
47
|
+
-----BEGIN RSA PRIVATE KEY-----
|
48
|
+
MIIEpQIBAAKCAQEAoX5QOw3Wwt6fyD73s81OJaO737CRK/4fmtCW9vpgUs/HXVi+
|
49
|
+
qkryazqQVTU6ZZ4t+aFymxP5tm0q6kLtoY+hIbdFfPN/9hQyCz9lJcDSJ1kcDq2R
|
50
|
+
F4ATMhfqMvmi189Zto+W4JNShUx4/i73LCTrbzOWqH0hAcLUCCXRHXEYKlQsOTyS
|
51
|
+
fWA/ISKyXfzAjloNvPLqVhAY1Qo6q3XF9WO0gV7+PJj+/SzEWMgmVEtwAUG4nHix
|
52
|
+
FX4/BEGS6w5C1jBzCkiWgzEmP4ZB7rq54BNbzVoLiI5TroMAUUS4bPAjCbds6KWK
|
53
|
+
YYZBsZv3YXff1F+ZI6hM8C9WGxqQjebMRJviWQIDAQABAoIBAQCTiLIDQUFSBdAz
|
54
|
+
QFNLD+S0vkCEuunlJuP4q1c/ir006l1YChsluBJ/o6D4NwiCjV+zDquEwVsALftm
|
55
|
+
yH4PewfZpXT2Ef508T5GyEO/mchj6iSXxDkpHvhqay6qIyWBwwxSnBtaTzy0Soi+
|
56
|
+
rmlhCtmLXbXld2sQEM1kJChGnWtWPtvSyrn+mapNPZviGRtgRNK+YsrAti1nUext
|
57
|
+
2syO5mTdHf1D8GR7I98OaX6odREuSocEV9PzfapWZx2GK5tvRiS1skiug5ciieTd
|
58
|
+
Am5/C+bb31h4drFslihLb5BRGO5SFQJvMJL2Sx1f19BCC4XikS01P4/zZbxQNq79
|
59
|
+
kxEQuDGBAoGBANP4pIYZ5xshCkx7cTYqmxzWLClGKE2S7Oa8N89mtOwfmqT9AFun
|
60
|
+
t9Us9Ukbi8BaKlKhGpQ1HlLf/KVcpyW0x2qLou6AyIWYH+/5VaR3graNgUnzpK9f
|
61
|
+
1F5HoaNHbhlAoebqhzhASFlJI2aqUdQjdOv73z+s9szJU4gpILNwGDFnAoGBAMMJ
|
62
|
+
j+vIxtG9J2jldyoXzpg5mbMXSj9u/wFLBVdjXWyOoiqVMMBto53RnoqAom7Ifr9D
|
63
|
+
49LxRAT1Q3l4vs/YnM3ziMsIg2vQK1EbrLsY9OnD/kvPaLXOlNIOdfLM8UeVWZMc
|
64
|
+
I4LPbbZrhv/7CC8RjbRhMoWWdGYPvxmvD6V4ZDY/AoGBALoI6OxA45Htx4okdNHj
|
65
|
+
RstiNNPsnQaoQn6nBhxiubraafEPkzbd1fukP4pwQJELEUX/2sHkdL6rkqLW1GPF
|
66
|
+
a5dZAiBsqpCFWNJWdBGqSfBJ9QSgbxLz+gDcwUH6OOi0zuNJRm/aCyVBiW5bYQHc
|
67
|
+
NIvAPMk31ksZDtTbs7WIVdNVAoGBALZ1+KWNxKqs+fSBT5UahpUUtfy8miJz9a7A
|
68
|
+
/3M8q0cGvSF3Rw+OwpW/aEGMi+l2OlU27ykFuyukRAac9m296RwnbF79TO2M5ylO
|
69
|
+
6a5zb5ROXlWP6RbE96b4DlIidssQJqegmHwlEC+rsrVBpOtb0aThlYEyOxzMOGyP
|
70
|
+
wOR9l8rDAoGADZ4TUHFM6VrvPlUZBkGbqiyXH9IM/y9JWk+22JQCEGnM6RFZemSs
|
71
|
+
jxWqQiPAdJtb3xKryJSCMtFPH9azedoCrSgaMflJ1QgoXgpiKZyoEXWraVUggh/0
|
72
|
+
CEavgZcTZ6SvMuayqJdGGB+zb1V8XwXMtCjApR/kTm47DjxO4DmpOPs=
|
73
|
+
-----END RSA PRIVATE KEY-----
|
74
|
+
EOF
|
75
|
+
|
76
|
+
|
77
|
+
describe Rapns::App do
|
78
|
+
|
79
|
+
it "does not validate an app with an invalid certificate" do
|
80
|
+
@app = Rapns::App.new :key => 'test', :environment => 'development', :certificate => 'foo'
|
81
|
+
@app.should_not be_valid
|
82
|
+
@app.errors.should include(:certificate)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "does validate a real certificate" do
|
86
|
+
@app = Rapns::App.new :key => 'test', :environment => 'development', :certificate => TEST_CERT
|
87
|
+
@app.should be_valid
|
88
|
+
end
|
89
|
+
end
|
@@ -9,14 +9,14 @@ describe Rapns::Daemon::FeedbackReceiver, 'check_for_feedback' do
|
|
9
9
|
let(:app) { 'my_app' }
|
10
10
|
let(:connection) { stub(:connect => nil, :read => nil, :close => nil) }
|
11
11
|
let(:logger) { stub(:error => nil, :info => nil) }
|
12
|
-
let(:
|
12
|
+
let(:receiver) { Rapns::Daemon::FeedbackReceiver.new(app, host, port, poll, certificate, password) }
|
13
13
|
|
14
14
|
before do
|
15
|
-
|
15
|
+
receiver.stub(:interruptible_sleep)
|
16
16
|
Rapns::Daemon.logger = logger
|
17
17
|
Rapns::Daemon::Connection.stub(:new => connection)
|
18
18
|
Rapns::Feedback.stub(:create!)
|
19
|
-
|
19
|
+
receiver.instance_variable_set("@stop", false)
|
20
20
|
end
|
21
21
|
|
22
22
|
def stub_connection_read_with_tuple
|
@@ -32,61 +32,87 @@ describe Rapns::Daemon::FeedbackReceiver, 'check_for_feedback' do
|
|
32
32
|
|
33
33
|
it 'instantiates a new connection' do
|
34
34
|
Rapns::Daemon::Connection.should_receive(:new).with("FeedbackReceiver:#{app}", host, port, certificate, password)
|
35
|
-
|
35
|
+
receiver.check_for_feedback
|
36
36
|
end
|
37
37
|
|
38
38
|
it 'connects to the feeback service' do
|
39
39
|
connection.should_receive(:connect)
|
40
|
-
|
40
|
+
receiver.check_for_feedback
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'closes the connection' do
|
44
44
|
connection.should_receive(:close)
|
45
|
-
|
45
|
+
receiver.check_for_feedback
|
46
46
|
end
|
47
47
|
|
48
48
|
it 'reads from the connection' do
|
49
49
|
connection.should_receive(:read).with(38)
|
50
|
-
|
50
|
+
receiver.check_for_feedback
|
51
51
|
end
|
52
52
|
|
53
53
|
it 'logs the feedback' do
|
54
54
|
stub_connection_read_with_tuple
|
55
55
|
Rapns::Daemon.logger.should_receive(:info).with("[FeedbackReceiver:my_app] Delivery failed at 2011-12-10 16:08:45 UTC for 834f786655eb9f84614a05ad7d00af31e5cfe93ac3ea078f1da44d2a4eb0ce17")
|
56
|
-
|
56
|
+
receiver.check_for_feedback
|
57
57
|
end
|
58
58
|
|
59
59
|
it 'creates the feedback' do
|
60
60
|
stub_connection_read_with_tuple
|
61
61
|
Rapns::Feedback.should_receive(:create!).with(:failed_at => Time.at(1323533325), :device_token => '834f786655eb9f84614a05ad7d00af31e5cfe93ac3ea078f1da44d2a4eb0ce17', :app => 'my_app')
|
62
|
-
|
62
|
+
receiver.check_for_feedback
|
63
63
|
end
|
64
64
|
|
65
65
|
it 'logs errors' do
|
66
66
|
error = StandardError.new('bork!')
|
67
67
|
connection.stub(:read).and_raise(error)
|
68
68
|
Rapns::Daemon.logger.should_receive(:error).with(error)
|
69
|
-
lambda {
|
69
|
+
lambda { receiver.check_for_feedback }.should raise_error
|
70
70
|
end
|
71
71
|
|
72
72
|
it 'sleeps for the feedback poll period' do
|
73
|
-
|
74
|
-
|
73
|
+
receiver.stub(:check_for_feedback)
|
74
|
+
receiver.should_receive(:interruptible_sleep).with(60).at_least(:once)
|
75
75
|
Thread.stub(:new).and_yield
|
76
|
-
|
77
|
-
|
76
|
+
receiver.stub(:loop).and_yield
|
77
|
+
receiver.start
|
78
78
|
end
|
79
79
|
|
80
80
|
it 'checks for feedback when started' do
|
81
|
-
|
81
|
+
receiver.should_receive(:check_for_feedback).at_least(:once)
|
82
82
|
Thread.stub(:new).and_yield
|
83
|
-
|
84
|
-
|
83
|
+
receiver.stub(:loop).and_yield
|
84
|
+
receiver.start
|
85
85
|
end
|
86
86
|
|
87
87
|
it 'interrupts sleep when stopped' do
|
88
|
-
|
89
|
-
|
90
|
-
|
88
|
+
receiver.stub(:check_for_feedback)
|
89
|
+
receiver.should_receive(:interrupt_sleep)
|
90
|
+
receiver.stop
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'calls the configuration feedback_callback when feedback is received and the callback is set' do
|
94
|
+
stub_connection_read_with_tuple
|
95
|
+
Rapns::configuration.feedback_callback = Proc.new {}
|
96
|
+
feedback = Object.new
|
97
|
+
Rapns::Feedback.stub(:create! => feedback)
|
98
|
+
Rapns::configuration.feedback_callback.should_receive(:call).with(feedback)
|
99
|
+
receiver.check_for_feedback
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'catches exceptions in the feedback_callback' do
|
103
|
+
error = StandardError.new('bork!')
|
104
|
+
stub_connection_read_with_tuple
|
105
|
+
callback = Proc.new { raise error }
|
106
|
+
Rapns::configuration.feedback_callback = callback
|
107
|
+
expect { receiver.check_for_feedback }.not_to raise_error
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'logs an exception from the feedback_callback' do
|
111
|
+
error = StandardError.new('bork!')
|
112
|
+
stub_connection_read_with_tuple
|
113
|
+
callback = Proc.new { raise error }
|
114
|
+
Rapns::Daemon.logger.should_receive(:error).with(error)
|
115
|
+
Rapns::configuration.feedback_callback = callback
|
116
|
+
receiver.check_for_feedback
|
91
117
|
end
|
92
118
|
end
|
@@ -34,7 +34,7 @@ describe Rapns::Daemon::Logger do
|
|
34
34
|
end
|
35
35
|
|
36
36
|
it "should open the a log file in the Rails log directory" do
|
37
|
-
File.should_receive(:open).with('/rails_root/log/rapns.log', '
|
37
|
+
File.should_receive(:open).with('/rails_root/log/rapns.log', 'a')
|
38
38
|
Rapns::Daemon::Logger.new(:foreground => true)
|
39
39
|
end
|
40
40
|
|
@@ -145,4 +145,4 @@ describe Rapns::Daemon::Logger do
|
|
145
145
|
logger = Rapns::Daemon::Logger.new({})
|
146
146
|
@buffered_logger.auto_flushing.should be_true
|
147
147
|
end
|
148
|
-
end
|
148
|
+
end
|
data/spec/rapns/feedback_spec.rb
CHANGED
@@ -5,8 +5,8 @@ describe Rapns::Feedback do
|
|
5
5
|
it { should validate_presence_of(:failed_at) }
|
6
6
|
|
7
7
|
it "should validate the format of the device_token" do
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
feedback = Rapns::Feedback.new(:device_token => "{$%^&*()}")
|
9
|
+
feedback.valid?.should be_false
|
10
|
+
feedback.errors[:device_token].include?("is invalid").should be_true
|
11
11
|
end
|
12
12
|
end
|
@@ -118,6 +118,24 @@ describe Rapns::Notification, 'MDM' do
|
|
118
118
|
end
|
119
119
|
end
|
120
120
|
|
121
|
+
describe Rapns::Notification, 'content-available' do
|
122
|
+
let(:notification) { Rapns::Notification.new }
|
123
|
+
|
124
|
+
it 'includes content-available in the payload' do
|
125
|
+
notification.content_available = true
|
126
|
+
notification.as_json['aps']['content-available'].should == 1
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'does not include content-available in the payload if not set' do
|
130
|
+
notification.as_json['aps'].key?('content-available').should be_false
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'does not include convert-available as a non-aps attribute' do
|
134
|
+
notification.content_available = true
|
135
|
+
notification.as_json.key?('content-available').should be_false
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
121
139
|
describe Rapns::Notification, "to_binary" do
|
122
140
|
it "should correctly convert the notification to binary" do
|
123
141
|
notification = Rapns::Notification.new
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rapns
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.5
|
5
|
-
prerelease:
|
4
|
+
version: 2.0.5
|
5
|
+
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Ian Leitch
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-11-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: multi_json
|
@@ -47,6 +47,7 @@ files:
|
|
47
47
|
- lib/rapns.rb
|
48
48
|
- lib/rapns/app.rb
|
49
49
|
- lib/rapns/binary_notification_validator.rb
|
50
|
+
- lib/rapns/config.rb
|
50
51
|
- lib/rapns/daemon.rb
|
51
52
|
- lib/rapns/daemon/app_runner.rb
|
52
53
|
- lib/rapns/daemon/connection.rb
|
@@ -70,6 +71,7 @@ files:
|
|
70
71
|
- lib/rapns/patches/rails/3.1.1/postgresql_adapter.rb
|
71
72
|
- lib/rapns/version.rb
|
72
73
|
- config/database.yml
|
74
|
+
- spec/rapns/app_spec.rb
|
73
75
|
- spec/rapns/daemon/app_runner_spec.rb
|
74
76
|
- spec/rapns/daemon/connection_spec.rb
|
75
77
|
- spec/rapns/daemon/database_reconnectable_spec.rb
|
@@ -101,9 +103,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
101
103
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
104
|
none: false
|
103
105
|
requirements:
|
104
|
-
- - ! '
|
106
|
+
- - ! '>='
|
105
107
|
- !ruby/object:Gem::Version
|
106
|
-
version:
|
108
|
+
version: '0'
|
107
109
|
requirements: []
|
108
110
|
rubyforge_project:
|
109
111
|
rubygems_version: 1.8.23
|
@@ -112,6 +114,7 @@ specification_version: 3
|
|
112
114
|
summary: Easy to use, full featured APNs daemon for Rails 3
|
113
115
|
test_files:
|
114
116
|
- config/database.yml
|
117
|
+
- spec/rapns/app_spec.rb
|
115
118
|
- spec/rapns/daemon/app_runner_spec.rb
|
116
119
|
- spec/rapns/daemon/connection_spec.rb
|
117
120
|
- spec/rapns/daemon/database_reconnectable_spec.rb
|