rapns 0.1.3 → 0.1.4
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 +1 -0
- data/lib/generators/templates/rapns.yml +2 -1
- data/lib/rapns/daemon/configuration.rb +12 -1
- data/lib/rapns/daemon/connection.rb +2 -2
- data/lib/rapns/daemon/delivery_handler.rb +1 -1
- data/lib/rapns/daemon/delivery_queue.rb +4 -7
- data/lib/rapns/daemon/feeder.rb +1 -1
- data/lib/rapns/daemon.rb +32 -5
- data/lib/rapns/version.rb +1 -1
- data/lib/rapns.rb +4 -4
- data/spec/rapns/daemon/configuration_spec.rb +25 -3
- data/spec/rapns/daemon/connection_spec.rb +4 -4
- data/spec/rapns/daemon/delivery_handler_spec.rb +5 -0
- data/spec/rapns/daemon/feeder_spec.rb +2 -2
- data/spec/rapns/daemon_spec.rb +28 -1
- data/spec/spec_helper.rb +5 -0
- metadata +4 -4
data/README.md
CHANGED
@@ -50,6 +50,7 @@ If you want to use rapns in environments other than development or production, y
|
|
50
50
|
* `airbrake_notify` (default: true) Enables/disables error notifications via Airbrake.
|
51
51
|
* `poll` (default: 2) Frequency in seconds to check for new notifications to deliver.
|
52
52
|
* `connections` (default: 3) the number of connections to keep open to the APNs. Consider increasing this if you are sending a very large number of notifications.
|
53
|
+
* `pid_file` (default: blank) the file that rapns will write its process ID to. Paths are relative to your project's RAILS_ROOT unless an absolute path is given.
|
53
54
|
|
54
55
|
## Starting the rapns Daemon
|
55
56
|
|
@@ -5,7 +5,7 @@ module Rapns
|
|
5
5
|
|
6
6
|
module Daemon
|
7
7
|
class Configuration
|
8
|
-
attr_accessor :host, :port, :certificate, :certificate_password, :poll, :airbrake_notify, :connections
|
8
|
+
attr_accessor :host, :port, :certificate, :certificate_password, :poll, :airbrake_notify, :connections, :pid_file
|
9
9
|
alias_method :airbrake_notify?, :airbrake_notify
|
10
10
|
|
11
11
|
def initialize(environment, config_path)
|
@@ -24,6 +24,7 @@ module Rapns
|
|
24
24
|
set_variable(:certificate_password, config, :optional => true, :default => "")
|
25
25
|
set_variable(:poll, config, :optional => true, :default => 2)
|
26
26
|
set_variable(:connections, config, :optional => true, :default => 3)
|
27
|
+
set_variable(:pid_file, config, :optional => true, :default => "")
|
27
28
|
end
|
28
29
|
|
29
30
|
def certificate
|
@@ -34,6 +35,16 @@ module Rapns
|
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
38
|
+
def pid_file
|
39
|
+
return if @pid_file.blank?
|
40
|
+
|
41
|
+
if Pathname.new(@pid_file).absolute?
|
42
|
+
@pid_file
|
43
|
+
else
|
44
|
+
File.join(Rails.root, @pid_file)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
37
48
|
protected
|
38
49
|
|
39
50
|
def read_config
|
@@ -40,7 +40,7 @@ module Rapns
|
|
40
40
|
|
41
41
|
check_for_error
|
42
42
|
rescue Errno::EPIPE => e
|
43
|
-
Rapns::Daemon.logger.
|
43
|
+
Rapns::Daemon.logger.error("[#{@name}] Lost connection to #{Rapns::Daemon.configuration.host}:#{Rapns::Daemon.configuration.port}, reconnecting...")
|
44
44
|
@tcp_socket, @ssl_socket = connect_socket
|
45
45
|
|
46
46
|
retry_count += 1
|
@@ -70,7 +70,7 @@ module Rapns
|
|
70
70
|
end
|
71
71
|
|
72
72
|
begin
|
73
|
-
Rapns::Daemon.logger.
|
73
|
+
Rapns::Daemon.logger.error("[#{@name}] Error received, reconnecting...")
|
74
74
|
close
|
75
75
|
@tcp_socket, @ssl_socket = connect_socket
|
76
76
|
ensure
|
@@ -5,11 +5,9 @@ module Rapns
|
|
5
5
|
@queue = Queue.new
|
6
6
|
@waiting_threads = []
|
7
7
|
@mutex = Mutex.new
|
8
|
-
@counter = 0
|
9
8
|
end
|
10
9
|
|
11
10
|
def push(obj)
|
12
|
-
@mutex.synchronize { @counter += 1 }
|
13
11
|
@queue.push(obj)
|
14
12
|
end
|
15
13
|
|
@@ -17,11 +15,10 @@ module Rapns
|
|
17
15
|
@queue.pop
|
18
16
|
end
|
19
17
|
|
20
|
-
def
|
18
|
+
def signal_waiters_if_empty
|
21
19
|
@mutex.synchronize do
|
22
20
|
begin
|
23
|
-
@
|
24
|
-
if @counter <= 0
|
21
|
+
if @queue.size == 0
|
25
22
|
t = @waiting_threads.shift
|
26
23
|
t.wakeup if t
|
27
24
|
end
|
@@ -31,9 +28,9 @@ module Rapns
|
|
31
28
|
end
|
32
29
|
end
|
33
30
|
|
34
|
-
def
|
31
|
+
def wait_until_empty
|
35
32
|
Thread.exclusive do
|
36
|
-
if @
|
33
|
+
if @queue.size > 0
|
37
34
|
@waiting_threads << Thread.current
|
38
35
|
Thread.stop
|
39
36
|
end
|
data/lib/rapns/daemon/feeder.rb
CHANGED
data/lib/rapns/daemon.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'socket'
|
3
|
+
require 'pathname'
|
4
|
+
|
1
5
|
require "rapns/daemon/configuration"
|
2
6
|
require "rapns/daemon/certificate"
|
3
7
|
require "rapns/daemon/delivery_error"
|
@@ -37,6 +41,8 @@ module Rapns
|
|
37
41
|
ActiveRecord::Base.establish_connection
|
38
42
|
end
|
39
43
|
|
44
|
+
write_pid_file
|
45
|
+
|
40
46
|
self.delivery_handler_pool = DeliveryHandlerPool.new(configuration.connections)
|
41
47
|
delivery_handler_pool.populate
|
42
48
|
|
@@ -49,19 +55,27 @@ module Rapns
|
|
49
55
|
protected
|
50
56
|
|
51
57
|
def self.setup_signal_hooks
|
52
|
-
@
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
58
|
+
@shutting_down = false
|
59
|
+
|
60
|
+
["SIGINT", "SIGTERM"].each do |signal|
|
61
|
+
Signal.trap(signal) do
|
62
|
+
handle_shutdown_signal
|
63
|
+
end
|
57
64
|
end
|
58
65
|
end
|
59
66
|
|
67
|
+
def self.handle_shutdown_signal
|
68
|
+
exit 1 if @shutting_down
|
69
|
+
@shutting_down = true
|
70
|
+
shutdown
|
71
|
+
end
|
72
|
+
|
60
73
|
def self.shutdown
|
61
74
|
puts "\nShutting down..."
|
62
75
|
Rapns::Daemon::Feeder.stop
|
63
76
|
Rapns::Daemon.delivery_handler_pool.drain if Rapns::Daemon.delivery_handler_pool
|
64
77
|
Rapns::Daemon.connection_pool.drain if Rapns::Daemon.connection_pool
|
78
|
+
delete_pid_file
|
65
79
|
end
|
66
80
|
|
67
81
|
def self.daemonize
|
@@ -76,5 +90,18 @@ module Rapns
|
|
76
90
|
STDOUT.reopen '/dev/null', 'a'
|
77
91
|
STDERR.reopen STDOUT
|
78
92
|
end
|
93
|
+
|
94
|
+
def self.write_pid_file
|
95
|
+
if !configuration.pid_file.blank?
|
96
|
+
File.open(configuration.pid_file, "w") do |f|
|
97
|
+
f.puts $$
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.delete_pid_file
|
103
|
+
pid_file = configuration.pid_file
|
104
|
+
File.delete(pid_file) if !pid_file.blank? && File.exists?(pid_file)
|
105
|
+
end
|
79
106
|
end
|
80
107
|
end
|
data/lib/rapns/version.rb
CHANGED
data/lib/rapns.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
1
|
+
require 'active_record'
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require 'rapns/version'
|
4
|
+
require 'rapns/binary_notification_validator'
|
5
|
+
require 'rapns/notification'
|
@@ -5,7 +5,8 @@ describe Rapns::Daemon::Configuration do
|
|
5
5
|
end
|
6
6
|
|
7
7
|
before do
|
8
|
-
|
8
|
+
Rails.stub(:root).and_return("/rails_root")
|
9
|
+
@config = {"port" => 123, "host" => "localhost", "certificate" => "production.pem", "certificate_password" => "abc123", "airbrake_notify" => false, "poll" => 4, "connections" => 6, "pid_file" => "rapns.pid"}
|
9
10
|
end
|
10
11
|
|
11
12
|
it "should raise an error if the configuration file does not exist" do
|
@@ -107,7 +108,6 @@ describe Rapns::Daemon::Configuration do
|
|
107
108
|
end
|
108
109
|
|
109
110
|
it "should set the certificate, with absolute path" do
|
110
|
-
Rails.stub(:root).and_return("/rails_root")
|
111
111
|
configuration = Rapns::Daemon::Configuration.new("production", "/some/config.yml")
|
112
112
|
configuration.stub(:read_config).and_return({"production" => @config})
|
113
113
|
configuration.load
|
@@ -115,11 +115,33 @@ describe Rapns::Daemon::Configuration do
|
|
115
115
|
end
|
116
116
|
|
117
117
|
it "should keep the absolute path of the certificate if it has one" do
|
118
|
-
Rails.stub(:root).and_return("/rails_root")
|
119
118
|
@config["certificate"] = "/different_path/to/production.pem"
|
120
119
|
configuration = Rapns::Daemon::Configuration.new("production", "/some/config.yml")
|
121
120
|
configuration.stub(:read_config).and_return({"production" => @config})
|
122
121
|
configuration.load
|
123
122
|
configuration.certificate.should == "/different_path/to/production.pem"
|
124
123
|
end
|
124
|
+
|
125
|
+
it "should set the PID file path" do
|
126
|
+
configuration = Rapns::Daemon::Configuration.new("production", "/some/config.yml")
|
127
|
+
configuration.stub(:read_config).and_return({"production" => @config})
|
128
|
+
configuration.load
|
129
|
+
configuration.pid_file.should == "/rails_root/rapns.pid"
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should keep the absolute path of the PID file if it has one" do
|
133
|
+
@config["pid_file"] = "/some/absolue/path/rapns.pid"
|
134
|
+
configuration = Rapns::Daemon::Configuration.new("production", "/some/config.yml")
|
135
|
+
configuration.stub(:read_config).and_return({"production" => @config})
|
136
|
+
configuration.load
|
137
|
+
configuration.pid_file.should == "/some/absolue/path/rapns.pid"
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should return nil if no PID file was set" do
|
141
|
+
@config["pid_file"] = ""
|
142
|
+
configuration = Rapns::Daemon::Configuration.new("production", "/some/config.yml")
|
143
|
+
configuration.stub(:read_config).and_return({"production" => @config})
|
144
|
+
configuration.load
|
145
|
+
configuration.pid_file.should be_nil
|
146
|
+
end
|
125
147
|
end
|
@@ -122,15 +122,15 @@ describe Rapns::Daemon::Connection, "when the connection is lost" do
|
|
122
122
|
@connection.instance_variable_set("@ssl_socket", @ssl_socket)
|
123
123
|
@connection.stub(:connect_socket).and_return([mock("TCPSocket"), @ssl_socket])
|
124
124
|
@ssl_socket.stub(:write).and_raise(Errno::EPIPE)
|
125
|
-
@logger = mock("Logger", :
|
125
|
+
@logger = mock("Logger", :error => nil)
|
126
126
|
Rapns::Daemon.stub(:logger).and_return(@logger)
|
127
127
|
@connection.stub(:sleep)
|
128
128
|
configuration = mock("Configuration", :host => "localhost", :port => 123)
|
129
129
|
Rapns::Daemon.stub(:configuration).and_return(configuration)
|
130
130
|
end
|
131
131
|
|
132
|
-
it "should log a
|
133
|
-
Rapns::Daemon.logger.should_receive(:
|
132
|
+
it "should log a error" do
|
133
|
+
Rapns::Daemon.logger.should_receive(:error).with("[Connection 1] Lost connection to localhost:123, reconnecting...")
|
134
134
|
begin
|
135
135
|
@connection.write(nil)
|
136
136
|
rescue Rapns::Daemon::ConnectionError
|
@@ -248,7 +248,7 @@ describe Rapns::Daemon::Connection, "when receiving an error packet" do
|
|
248
248
|
end
|
249
249
|
|
250
250
|
it "should log that the connection is being reconnected" do
|
251
|
-
Rapns::Daemon.logger.should_receive(:
|
251
|
+
Rapns::Daemon.logger.should_receive(:error).with("[Connection 1] Error received, reconnecting...")
|
252
252
|
begin
|
253
253
|
@connection.write("msg with an error")
|
254
254
|
rescue Rapns::DeliveryError
|
@@ -59,6 +59,11 @@ describe Rapns::Daemon::DeliveryHandler do
|
|
59
59
|
@delivery_handler.send(:handle_next_notification)
|
60
60
|
end
|
61
61
|
|
62
|
+
it "should signal the feeder if the delivery queue is empty" do
|
63
|
+
Rapns::Daemon.delivery_queue.should_receive(:signal_waiters_if_empty)
|
64
|
+
@delivery_handler.send(:handle_next_notification)
|
65
|
+
end
|
66
|
+
|
62
67
|
describe "when delivery fails" do
|
63
68
|
before do
|
64
69
|
@error = Rapns::DeliveryError.new(4, "Missing payload", 1)
|
@@ -6,7 +6,7 @@ describe Rapns::Daemon::Feeder do
|
|
6
6
|
@notification = Rapns::Notification.create!(:device_token => "a" * 64)
|
7
7
|
@logger = mock("Logger", :info => nil, :error => nil)
|
8
8
|
Rapns::Daemon.stub(:logger).and_return(@logger)
|
9
|
-
@queue = mock(:push => nil, :
|
9
|
+
@queue = mock(:push => nil, :wait_until_empty => nil)
|
10
10
|
Rapns::Daemon.stub(:delivery_queue).and_return(@queue)
|
11
11
|
Rapns::Daemon.stub(:configuration => mock("Configuration", :poll => 2))
|
12
12
|
end
|
@@ -53,7 +53,7 @@ describe Rapns::Daemon::Feeder do
|
|
53
53
|
end
|
54
54
|
|
55
55
|
it "should wait for the delivery queue to be emptied" do
|
56
|
-
Rapns::Daemon.delivery_queue.should_receive(:
|
56
|
+
Rapns::Daemon.delivery_queue.should_receive(:wait_until_empty)
|
57
57
|
Rapns::Daemon::Feeder.enqueue_notifications
|
58
58
|
end
|
59
59
|
|
data/spec/rapns/daemon_spec.rb
CHANGED
@@ -8,7 +8,7 @@ describe Rapns::Daemon, "when starting" do
|
|
8
8
|
Rails.stub(:root).and_return("/rails_root")
|
9
9
|
|
10
10
|
@configuration = Rapns::Daemon::Configuration.new("development", "/rails_root/config/rapns/rapns.yml")
|
11
|
-
@configuration.stub(:read_config).and_return({"development" => {"port" => 123, "host" => "localhost", "certificate" => "development.pem", "certificate_password" => "abc123"}})
|
11
|
+
@configuration.stub(:read_config).and_return({"development" => {"port" => 123, "host" => "localhost", "certificate" => "development.pem", "certificate_password" => "abc123", "pid_file" => "rapns.pid"}})
|
12
12
|
Rapns::Daemon::Configuration.stub(:new).and_return(@configuration)
|
13
13
|
|
14
14
|
@certificate = Rapns::Daemon::Certificate.new("/rails_root/config/rapns/development.pem")
|
@@ -26,6 +26,7 @@ describe Rapns::Daemon, "when starting" do
|
|
26
26
|
Rapns::Daemon::Feeder.stub(:start)
|
27
27
|
Rapns::Daemon::Feeder.stub(:wait)
|
28
28
|
Rapns::Daemon.stub(:daemonize)
|
29
|
+
Rapns::Daemon.stub(:write_pid_file)
|
29
30
|
@logger = mock("Logger")
|
30
31
|
Rapns::Daemon::Logger.stub(:new).and_return(@logger)
|
31
32
|
end
|
@@ -92,6 +93,11 @@ describe Rapns::Daemon, "when starting" do
|
|
92
93
|
Rapns::Daemon.start("development", true)
|
93
94
|
end
|
94
95
|
|
96
|
+
it "should write the process ID to the PID file" do
|
97
|
+
Rapns::Daemon.should_receive(:write_pid_file)
|
98
|
+
Rapns::Daemon.start("development", {})
|
99
|
+
end
|
100
|
+
|
95
101
|
it "should start the feeder" do
|
96
102
|
Rapns::Daemon::Feeder.should_receive(:start)
|
97
103
|
Rapns::Daemon.start("development", true)
|
@@ -111,11 +117,14 @@ end
|
|
111
117
|
|
112
118
|
describe Rapns::Daemon, "when being shutdown" do
|
113
119
|
before do
|
120
|
+
Rails.stub(:root).and_return("/rails_root")
|
114
121
|
Rapns::Daemon::Feeder.stub(:stop)
|
115
122
|
@connection_pool = mock("ConnectionPool", :drain => nil)
|
116
123
|
Rapns::Daemon.stub(:connection_pool).and_return(@connection_pool)
|
117
124
|
@handler_pool = mock("DeliveryHandlerPool", :drain => nil)
|
118
125
|
Rapns::Daemon.stub(:delivery_handler_pool).and_return(@handler_pool)
|
126
|
+
@configuration = mock("Configuration", :pid_file => File.join(Rails.root, "rapns.pid"))
|
127
|
+
Rapns::Daemon.stub(:configuration).and_return(@configuration)
|
119
128
|
Rapns::Daemon.stub(:puts)
|
120
129
|
end
|
121
130
|
|
@@ -145,4 +154,22 @@ describe Rapns::Daemon, "when being shutdown" do
|
|
145
154
|
@handler_pool.should_not_receive(:drain)
|
146
155
|
Rapns::Daemon.send(:shutdown)
|
147
156
|
end
|
157
|
+
|
158
|
+
it "should remove the PID file if one was written" do
|
159
|
+
File.stub(:exists?).and_return(true)
|
160
|
+
File.should_receive(:delete).with("/rails_root/rapns.pid")
|
161
|
+
Rapns::Daemon.send(:shutdown)
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should not attempt to remove the PID file if it does not exist" do
|
165
|
+
File.stub(:exists?).and_return(false)
|
166
|
+
File.should_not_receive(:delete)
|
167
|
+
Rapns::Daemon.send(:shutdown)
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should not remove the PID file if one was not written" do
|
171
|
+
@configuration.stub(:pid_file).and_return(nil)
|
172
|
+
File.should_not_receive(:delete)
|
173
|
+
Rapns::Daemon.send(:shutdown)
|
174
|
+
end
|
148
175
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rapns
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
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: 2011-
|
12
|
+
date: 2011-10-08 00:00:00.000000000Z
|
13
13
|
dependencies: []
|
14
14
|
description: Easy to use library for Apple's Push Notification Service with Rails
|
15
15
|
3
|
@@ -53,7 +53,7 @@ files:
|
|
53
53
|
- spec/rapns/notification_spec.rb
|
54
54
|
- spec/spec_helper.rb
|
55
55
|
- bin/rapns
|
56
|
-
homepage:
|
56
|
+
homepage: https://github.com/ileitch/rapns
|
57
57
|
licenses: []
|
58
58
|
post_install_message:
|
59
59
|
rdoc_options: []
|
@@ -73,7 +73,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
73
73
|
version: '0'
|
74
74
|
requirements: []
|
75
75
|
rubyforge_project:
|
76
|
-
rubygems_version: 1.8.
|
76
|
+
rubygems_version: 1.8.10
|
77
77
|
signing_key:
|
78
78
|
specification_version: 3
|
79
79
|
summary: Easy to use library for Apple's Push Notification Service with Rails 3
|