rpush 2.0.0.rc1-java → 2.0.1-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dc01aeffab54e2ec19bc908f3b38640cdd31b6c8
4
- data.tar.gz: 729ab2e1a5132e130535dabbfe2403457818899d
3
+ metadata.gz: 13082e421fbc9ede84fe1dea84373de5ccab8bd5
4
+ data.tar.gz: c1b695784b56de4a796e75402c808d015f7d9c8f
5
5
  SHA512:
6
- metadata.gz: 0dbcca1188ed3eb635b8f15eb4de10a376c66954bb3d0b7cc91f487d1da086b4dd13d596650c775133ae169eb0df39a0748d911dd82be76a7376a0599ba97e16
7
- data.tar.gz: 0470666c1fa13dbd45fe29cf83449e9b921e4842d2c2c7c668f8078d1f5fb7e6b518f5d6ac37d0b0c54fcf58f0c0b57f3297a00799c1ea58ca65d3de95c48b62
6
+ metadata.gz: bc6c33f58cb98c3f5a0958fc8a11b554b375aae30e3ad0f44d61a5ddb91da5ae970e0fd4c7b8fe35d773771dedd37b011a4527030df023e7587fa2b5eb49f04c
7
+ data.tar.gz: 44ebe64b26b051db0e0ae5acb1bfb91cd1ec0efc6a2658138f2a1c493be013f8785683e46ba9a39d2c4c93f7f4bbef101c2a4a7dddca70278fa43544a3861c93
data/CHANGELOG.md CHANGED
@@ -1,4 +1,8 @@
1
- ## 2.0.0 (unreleased)
1
+ ## 2.0.1 (Sept 13, 2014)
2
+ * Add ssl_certificate_revoked reflection (#68).
3
+ * Fix for Postgis support in 2.0.0 migration (#70).
4
+
5
+ ## 2.0.0 (Sept 6, 2014)
2
6
  * Use APNs enhanced binary format version 2.
3
7
  * Support running multiple Rpush processes when using ActiveRecord and Redis.
4
8
  * APNs error detection is now performed asynchronously, 'check_for_errors' is therefore deprecated.
@@ -11,6 +15,7 @@
11
15
  * The 'batch_storage_updates' config option has been deprecated, storage backends will now always batch updates where appropriate.
12
16
  * The rpush process title updates with number of queued notifications and number of dispatchers.
13
17
  * Rpush::Apns::Feedback#app has been renamed to app_id and is now an Integer.
18
+ * An app is restarted when the HUP signal is received if its certificate or environment attribute changed.
14
19
 
15
20
  ## 1.0.0 (Feb 9, 2014)
16
21
  * Renamed to Rpush (from Rapns). Version number reset to 1.0.0.
data/README.md CHANGED
@@ -7,15 +7,21 @@
7
7
 
8
8
  ### Rpush. The push notification service for Ruby.
9
9
 
10
- * Supports:
11
- * **Apple Push Notification Service**
12
- * **Google Cloud Messaging**
13
- * **Amazon Device Messaging**
14
- * **Windows Phone Push Notification Service**.
15
- * Seamless Rails (3, 4) integration.
16
- * Scalable - choose the number of persistent connections for each app.
17
- * Designed for uptime - signal -HUP to add, update apps.
18
- * Run as a daemon or inside an [existing processs](https://github.com/rpush/rpush/wiki/Embedding-API).
10
+ * Supported services:
11
+ * [**Apple Push Notification Service**](#apple-push-notification-service)
12
+ * [**Google Cloud Messaging**](#google-cloud-messaging)
13
+ * [**Amazon Device Messaging**](#amazon-device-messaging)
14
+ * [**Windows Phone Push Notification Service**](#windows-phone-notification-service)
15
+
16
+ * Supported storage backends:
17
+ * **ActiveRecord**
18
+ * **Redis**
19
+ * More coming!
20
+
21
+ * Seamless Rails integration (3 & 4) .
22
+ * Scales vertically (threading) and horizontally (multiple processes).
23
+ * Designed for uptime - new apps are loaded automatically, signal `HUP` to update running apps.
24
+ * Run as a daemon or inside an [existing process](https://github.com/rpush/rpush/wiki/Embedding-API).
19
25
  * Use in a scheduler for low-workload deployments ([Push API](https://github.com/rpush/rpush/wiki/Push-API)).
20
26
  * Hooks for fine-grained instrumentation and error handling ([Reflection API](https://github.com/rpush/rpush/wiki/Reflection-API)).
21
27
  * Works with MRI, JRuby and Rubinius.
@@ -122,31 +128,40 @@ n.alert = "..."
122
128
  n.save!
123
129
  ```
124
130
 
125
- ### Starting Rpush
131
+ ### Running Rpush
126
132
 
127
- As a daemon (recommended):
133
+ It is recommended to run Rpush as a separate process in most cases, though embedding and manual modes are provided for low-workload environments.
134
+
135
+ #### As a daemon (recommended):
128
136
 
129
137
  cd /path/to/rails/app
130
138
  rpush <Rails environment> [options]
131
139
 
132
- Inside an existing process (see [Embedding API](https://github.com/rpush/rpush/wiki/Embedding-API)):
140
+ #### Embedded inside an existing process
133
141
 
134
142
  ```ruby
143
+ # Call this during startup of your application, for example, by adding it to the end of config/initializers/rpush.rb
135
144
  Rpush.embed
136
145
  ```
137
146
 
138
- In a scheduler (see [Push API](https://github.com/rpush/rpush/wiki/Push-API)):
147
+ See [Embedding API](https://github.com/rpush/rpush/wiki/Embedding-API) for more details.
148
+
149
+ #### Manually (in a scheduler)
139
150
 
140
151
  ```ruby
141
152
  Rpush.push
142
153
  Rpush.apns_feedback
143
154
  ```
144
155
 
156
+ See [Push API](https://github.com/rpush/rpush/wiki/Push-API) for more details.
157
+
158
+ ### Configuration
159
+
145
160
  See [Configuration](https://github.com/rpush/rpush/wiki/Configuration) for a list of options, or run `rpush --help`.
146
161
 
147
162
  ### Updating Rpush
148
163
 
149
- After updating you should run `rails g rpush` to check for any new migrations.
164
+ If you're using ActiveRecord, you should run `rails g rpush` after upgrading Rpush to check for any new migrations.
150
165
 
151
166
  ### Wiki
152
167
 
data/bin/rpush CHANGED
@@ -12,10 +12,10 @@ options = ARGV.options do |opts|
12
12
  opts.on('-f', '--foreground', 'Run in the foreground.') { config.foreground = true }
13
13
  opts.on('-P N', '--db-poll N', Integer, "Frequency in seconds to check for new notifications.") { |n| config.push_poll = n }
14
14
  opts.on('-F N', '--feedback-poll N', Integer, "Frequency in seconds to check for feedback.") { |n| config.feedback_poll = n }
15
- opts.on('-e', '--no-error-checks', 'Disable APNs error checking after notification delivery.') { config.check_for_errors = false }
15
+ opts.on('-e', '--no-error-checks', 'Disable APNs error checking after notification delivery.') { config.check_for_errors = false } # deprecated
16
16
  opts.on('-p PATH', '--pid-file PATH', String, 'Path to write PID file. Relative to Rails root unless absolute.') { |path| config.pid_file = path }
17
17
  opts.on('-b N', '--batch-size N', Integer, 'Storage backend notification batch size.') { |n| config.batch_size = n }
18
- opts.on('-B', '--[no-]batch-storage-updates', 'Perform storage updates in batches.') { |v| config.batch_storage_updates = v }
18
+ opts.on('-B', '--[no-]batch-storage-updates', 'Perform storage updates in batches.') { |v| config.batch_storage_updates = v } # deprecated
19
19
  opts.on('-v', '--version', 'Print the version.') do
20
20
  puts "rpush #{Rpush::VERSION}"
21
21
  exit
@@ -106,6 +106,10 @@ Rpush.reflect do |on|
106
106
  # on.ssl_certificate_will_expire do |app, expiration_time|
107
107
  # end
108
108
 
109
+ # Called when an SSL certificate has been revoked.
110
+ # on.ssl_certificate_revoked do |app, error|
111
+ # end
112
+
109
113
  # Called when the ADM returns a canonical registration ID.
110
114
  # You will need to replace old_id with canonical_id in your records.
111
115
  # on.adm_canonical_id do |old_id, canonical_id|
@@ -119,7 +123,6 @@ Rpush.reflect do |on|
119
123
  # on.adm_failed_to_recipient do |notification, registration_id, reason|
120
124
  # end
121
125
 
122
-
123
126
  # Called when an exception is raised.
124
127
  # on.error do |error|
125
128
  # end
@@ -7,7 +7,7 @@ class Rpush200Updates < ActiveRecord::Migration
7
7
  remove_index :rpush_notifications, name: :index_rpush_notifications_multi
8
8
  end
9
9
 
10
- add_index :rpush_notifications, [:processing, :delivered, :failed, :deliver_after], name: 'index_rpush_notifications_multi'
10
+ add_index :rpush_notifications, [:delivered, :failed], name: 'index_rpush_notifications_multi', where: 'NOT delivered AND NOT failed'
11
11
 
12
12
  rename_column :rpush_feedback, :app, :app_id
13
13
 
@@ -37,6 +37,6 @@ class Rpush200Updates < ActiveRecord::Migration
37
37
  end
38
38
 
39
39
  def self.postgresql?
40
- adapter_name =~ /postgresql/
40
+ adapter_name =~ /postgresql|postgis/
41
41
  end
42
42
  end
@@ -14,6 +14,8 @@ module Rpush
14
14
  attribute :client_id, :string
15
15
  attribute :client_secret, :string
16
16
 
17
+ index :name
18
+
17
19
  validates :name, presence: true
18
20
  validates_numericality_of :connections, greater_than: 0, only_integer: true
19
21
  end
data/lib/rpush/daemon.rb CHANGED
@@ -51,8 +51,8 @@ module Rpush
51
51
  end
52
52
 
53
53
  def self.start
54
- SignalHandler.start
55
54
  Process.daemon if daemonize?
55
+ SignalHandler.start
56
56
  initialize_store
57
57
  write_pid_file
58
58
  Synchronizer.sync
@@ -4,7 +4,9 @@ module Rpush
4
4
  extend Reflectable
5
5
  include Reflectable
6
6
  include Loggable
7
+ extend Loggable
7
8
  include StringHelpers
9
+ extend StringHelpers
8
10
 
9
11
  @runners = {}
10
12
 
@@ -24,6 +26,7 @@ module Rpush
24
26
  def self.start_app(app)
25
27
  @runners[app.id] = new(app)
26
28
  @runners[app.id].start
29
+ log_info("[#{app.name}] Started, #{pluralize(app.connections, 'dispatcher')}.")
27
30
  rescue StandardError => e
28
31
  @runners.delete(app.id)
29
32
  Rpush.logger.error("[#{app.name}] Exception raised during startup. Notifications will not be delivered for this app.")
@@ -32,7 +35,15 @@ module Rpush
32
35
  end
33
36
 
34
37
  def self.stop_app(app_id)
35
- @runners.delete(app_id).stop
38
+ runner = @runners.delete(app_id)
39
+ if runner
40
+ runner.stop
41
+ log_info("[#{runner.app.name}] Stopped.")
42
+ end
43
+ end
44
+
45
+ def self.app_with_id(app_id)
46
+ @runners[app_id].app
36
47
  end
37
48
 
38
49
  def self.app_running?(app)
@@ -7,42 +7,47 @@ module Rpush
7
7
 
8
8
  def self.start
9
9
  return unless trap_signals?
10
- @shutting_down = false
10
+
11
11
  read_io, @write_io = IO.pipe
12
12
  start_handler(read_io)
13
13
  %w(INT TERM HUP USR2).each do |signal|
14
- Signal.trap(signal) { @write_io.write("#{Signal.list[signal]}\n") }
14
+ Signal.trap(signal) { @write_io.puts(signal) }
15
15
  end
16
16
  end
17
17
 
18
18
  def self.stop
19
- @write_io.write("shutdown\n") if @write_io
19
+ @write_io.puts('break') if @write_io
20
20
  @thread.join if @thread
21
21
  end
22
22
 
23
23
  def self.start_handler(read_io)
24
24
  @thread = Thread.new do
25
- loop do
26
- case read_io.readline.strip.to_i
27
- when Signal.list['HUP']
28
- Synchronizer.sync
29
- Feeder.wakeup
30
- when Signal.list['USR2']
31
- AppRunner.debug
32
- when Signal.list['INT'], Signal.list['TERM']
33
- Thread.new { handle_shutdown_signal }
34
- else
35
- break
25
+ while readable_io = IO.select([read_io]) # rubocop:disable AssignmentInCondition
26
+ signal = readable_io.first[0].gets.strip
27
+
28
+ begin
29
+ case signal
30
+ when 'HUP'
31
+ Synchronizer.sync
32
+ Feeder.wakeup
33
+ when 'USR2'
34
+ AppRunner.debug
35
+ when 'INT', 'TERM'
36
+ Thread.new { Rpush::Daemon.shutdown }
37
+ break
38
+ when 'break'
39
+ break
40
+ else
41
+ Rpush.logger.error("Unhandled signal: #{signal}")
42
+ end
43
+ rescue StandardError => e
44
+ Rpush.logger.error("Error raised when hndling signal '#{signal}'")
45
+ Rpush.logger.error(e)
36
46
  end
37
47
  end
38
48
  end
39
49
  end
40
50
 
41
- def self.handle_shutdown_signal
42
- @shutting_down = true
43
- Rpush::Daemon.shutdown
44
- end
45
-
46
51
  def self.trap_signals?
47
52
  !Rpush.config.embedded
48
53
  end
@@ -14,13 +14,19 @@ module Rpush
14
14
  end
15
15
 
16
16
  def self.sync_app(app)
17
- unless AppRunner.app_running?(app)
17
+ if !AppRunner.app_running?(app)
18
18
  AppRunner.start_app(app)
19
- log_info("[#{app.name}] Started, #{pluralize(app.connections, 'dispatcher')}.")
20
- return
19
+ elsif certificate_changed?(app)
20
+ log_info("[#{app.name}] Certificate changed, restarting...")
21
+ AppRunner.stop_app(app.id)
22
+ AppRunner.start_app(app)
23
+ elsif environment_changed?(app)
24
+ log_info("[#{app.name}] Environment changed, restarting...")
25
+ AppRunner.stop_app(app.id)
26
+ AppRunner.start_app(app)
27
+ else
28
+ sync_dispatcher_count(app)
21
29
  end
22
-
23
- sync_dispatcher_count(app)
24
30
  end
25
31
 
26
32
  def self.sync_dispatcher_count(app)
@@ -39,6 +45,16 @@ module Rpush
39
45
  num_dispatchers = AppRunner.num_dispatchers_for_app(app)
40
46
  log_info("[#{app.name}] #{start_stop_str} #{pluralize(diff.abs, 'dispatcher')}. #{num_dispatchers} running.")
41
47
  end
48
+
49
+ def self.certificate_changed?(app)
50
+ old_app = AppRunner.app_with_id(app.id)
51
+ app.certificate != old_app.certificate
52
+ end
53
+
54
+ def self.environment_changed?(app)
55
+ old_app = AppRunner.app_with_id(app.id)
56
+ app.environment != old_app.environment
57
+ end
42
58
  end
43
59
  end
44
60
  end
@@ -108,6 +108,12 @@ module Rpush
108
108
  ssl_socket.sync = true
109
109
  ssl_socket.connect
110
110
  [tcp_socket, ssl_socket]
111
+ rescue StandardError => error
112
+ if error.message =~ /certificate revoked/i
113
+ log_warn('Certificate has been revoked.')
114
+ reflect(:ssl_certificate_revoked, @app, error)
115
+ end
116
+ raise
111
117
  end
112
118
 
113
119
  def check_certificate_expiration
@@ -15,7 +15,7 @@ module Rpush
15
15
  :notification_failed, :notification_will_retry, :gcm_delivered_to_recipient,
16
16
  :gcm_failed_to_recipient, :gcm_canonical_id, :gcm_invalid_registration_id,
17
17
  :error, :adm_canonical_id, :adm_failed_to_recipient,
18
- :tcp_connection_lost, :ssl_certificate_will_expire,
18
+ :tcp_connection_lost, :ssl_certificate_will_expire, :ssl_certificate_revoked,
19
19
  :notification_id_will_retry, :notification_id_failed
20
20
  ]
21
21
 
data/lib/rpush/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Rpush
2
- VERSION = '2.0.0.rc1'
2
+ VERSION = '2.0.1'
3
3
  end
@@ -127,17 +127,16 @@ describe 'APNs' do
127
127
  notification1.delivered.should be_true
128
128
  end
129
129
 
130
- it 'marks notifications following the failed one as retryable' # do
131
- # # Such hacks. Set the poll frequency high enough that we'll only ever feed once.
132
- # Rpush.config.push_poll = 1_000_000
133
- #
134
- # notifications.each { |n| wait_for_notification_to_deliver(n) }
135
- # fail_notification(notification2)
136
- #
137
- # [notification3, notification4].each do |n|
138
- # wait_for_notification_to_retry(n)
139
- # end
140
- # end
130
+ it 'marks notifications following the failed one as retryable' do
131
+ Rpush.config.push_poll = 1_000_000
132
+
133
+ notifications.each { |n| wait_for_notification_to_deliver(n) }
134
+ fail_notification(notification2)
135
+
136
+ [notification3, notification4].each do |n|
137
+ wait_for_notification_to_retry(n)
138
+ end
139
+ end
141
140
 
142
141
  describe 'without an error response' do
143
142
  it 'marks all notifications as failed' do
@@ -16,6 +16,9 @@ describe 'Synchronization' do
16
16
  app.name = 'test'
17
17
  app.auth_key = 'abc123'
18
18
  app.connections = 2
19
+ app.certificate = TEST_CERT_WITH_PASSWORD
20
+ app.password = 'fubar'
21
+ app.environment = 'sandbox'
19
22
  app.save!
20
23
 
21
24
  Rpush.embed
@@ -43,4 +46,23 @@ describe 'Synchronization' do
43
46
  Rpush.sync
44
47
  Rpush::Daemon::AppRunner.app_running?(app).should be_false
45
48
  end
49
+
50
+ it 'restarts an app when the certificate is changed' do
51
+ app.certificate = TEST_CERT
52
+ app.password = nil
53
+ app.save!
54
+ Rpush.sync
55
+
56
+ running_app = Rpush::Daemon::AppRunner.app_with_id(app.id)
57
+ expect(running_app.certificate).to eql(TEST_CERT)
58
+ end
59
+
60
+ it 'restarts an app when the environment is changed' do
61
+ app.environment = 'production'
62
+ app.save!
63
+ Rpush.sync
64
+
65
+ running_app = Rpush::Daemon::AppRunner.app_with_id(app.id)
66
+ expect(running_app.environment).to eql('production')
67
+ end
46
68
  end
@@ -32,7 +32,7 @@ module Rpush
32
32
  end
33
33
 
34
34
  describe Rpush::Daemon::AppRunner, 'enqueue' do
35
- let(:app) { double(id: 1) }
35
+ let(:app) { double(id: 1, name: 'Test', connections: 1) }
36
36
  let(:notification) { double(app_id: 1) }
37
37
  let(:runner) { double(Rpush::Daemon::AppRunner, enqueue: nil, start: nil, stop: nil) }
38
38
  let(:logger) { double(Rpush::Logger, error: nil, info: nil) }
@@ -53,7 +53,7 @@ describe Rpush::Daemon::AppRunner, 'enqueue' do
53
53
 
54
54
  it 'starts the app if a runner does not exist' do
55
55
  notification = double(app_id: 3)
56
- new_app = double(Rpush::App, id: 3)
56
+ new_app = double(Rpush::App, id: 3, name: 'NewApp', connections: 1)
57
57
  Rpush::Daemon.store = double(app: new_app)
58
58
  Rpush::Daemon::AppRunner.enqueue([notification])
59
59
  Rpush::Daemon::AppRunner.app_running?(new_app).should be_true
@@ -69,4 +69,27 @@ describe Rpush::Daemon::SignalHandler do
69
69
  end
70
70
  end
71
71
  end
72
+
73
+ describe 'error handing' do
74
+ let(:error) { StandardError.new('test') }
75
+
76
+ before { Rpush.stub(logger: double(error: nil)) }
77
+
78
+ it 'logs errors received when handling a signal' do
79
+ Rpush::Daemon::Synchronizer.stub(:sync).and_raise(error)
80
+ expect(Rpush.logger).to receive(:error).with(error)
81
+ with_handler_start_stop do
82
+ signal_handler('HUP')
83
+ end
84
+ end
85
+
86
+ it 'does not interrupt processing of further errors' do
87
+ Rpush::Daemon::Synchronizer.stub(:sync).and_raise(error)
88
+ expect(Rpush::Daemon::AppRunner).to receive(:debug)
89
+ with_handler_start_stop do
90
+ signal_handler('HUP')
91
+ signal_handler('USR2')
92
+ end
93
+ end
94
+ end
72
95
  end
@@ -113,6 +113,23 @@ describe Rpush::Daemon::TcpConnection do
113
113
  end
114
114
  end
115
115
  end
116
+
117
+ describe 'certificate revocation' do
118
+ let(:cert_revoked_error) { OpenSSL::SSL::SSLError.new('certificate revoked') }
119
+ before do
120
+ ssl_socket.stub(:connect).and_raise(cert_revoked_error)
121
+ end
122
+
123
+ it 'reflects that the certificate has been revoked' do
124
+ connection.should_receive(:reflect).with(:ssl_certificate_revoked, app, cert_revoked_error)
125
+ expect { connection.connect }.to raise_error(cert_revoked_error)
126
+ end
127
+
128
+ it 'logs that the certificate has been revoked' do
129
+ logger.should_receive(:warn).with('[Connection 0] Certificate has been revoked.')
130
+ expect { connection.connect }.to raise_error(cert_revoked_error)
131
+ end
132
+ end
116
133
  end
117
134
 
118
135
  describe "when shuting down the connection" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rpush
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.rc1
4
+ version: 2.0.1
5
5
  platform: java
6
6
  authors:
7
7
  - Ian Leitch
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-02 00:00:00.000000000 Z
11
+ date: 2014-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: multi_json
@@ -277,9 +277,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
277
277
  version: '0'
278
278
  required_rubygems_version: !ruby/object:Gem::Requirement
279
279
  requirements:
280
- - - '>'
280
+ - - '>='
281
281
  - !ruby/object:Gem::Version
282
- version: 1.3.1
282
+ version: '0'
283
283
  requirements: []
284
284
  rubyforge_project:
285
285
  rubygems_version: 2.1.9