rapns_rails_2 3.4.3 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,5 +1,6 @@
1
- ## 3.4.2 (unreleased)
1
+ ## 3.5.0 (unreleased)
2
2
  * Fix sqlite3 support (#160).
3
+ * Drop support for Ruby 1.8.
3
4
 
4
5
  ## 3.4.1 (Aug 30, 2013)
5
6
  * Silence unintended airbrake_notify deprecation warning (#158).
data/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  * Run as a daemon or inside an [existing processs](https://github.com/ileitch/rapns/wiki/Embedding-API).
12
12
  * Use in a scheduler for low-workload deployments ([Push API](https://github.com/ileitch/rapns/wiki/Push-API)).
13
13
  * Reflection API for fine-grained instrumentation and error handling ([Reflection API](https://github.com/ileitch/rapns/wiki/Reflection-API)).
14
- * Works with MRI, JRuby, Rubinius 1.8 and 1.9.
14
+ * Works with MRI, JRuby, Rubinius 1.9, 2.0.
15
15
  * Built with love.
16
16
 
17
17
  ### Who uses Rapns?
data/config/database.yml CHANGED
@@ -15,7 +15,7 @@ jdbcpostgresql:
15
15
  password: ""
16
16
 
17
17
  mysql2:
18
- adapter: mysql
18
+ adapter: mysql2
19
19
  database: rapns_test
20
20
  host: localhost
21
21
  username: rapns_test
@@ -71,7 +71,7 @@ Rapns.reflect do |on|
71
71
  # on.gcm_canonical_id do |old_id, canonical_id|
72
72
  # end
73
73
 
74
- # Called when the GCM returns a failure that indicates an invalid tegistration id.
74
+ # Called when the GCM returns a failure that indicates an invalid registration id.
75
75
  # You will need to delete the registration_id from your records.
76
76
  # on.gcm_invalid_registration_id do |app, error, registration_id|
77
77
  # end
@@ -3,7 +3,7 @@ module Rapns
3
3
  class DeviceTokenFormatValidator < ActiveModel::Validator
4
4
 
5
5
  def validate(record)
6
- if record.device_token !~ /^[a-z0-9]{64}$/
6
+ if record.device_token !~ /^[a-z0-9]{64}$/i
7
7
  record.errors.add(:device_token, "is invalid")
8
8
  end
9
9
  end
@@ -9,7 +9,7 @@ module Rapns
9
9
 
10
10
  CONFIG_ATTRS = [:foreground, :push_poll, :feedback_poll, :embedded,
11
11
  :airbrake_notify, :check_for_errors, :pid_file, :batch_size,
12
- :push, :store, :logger, :batch_storage_updates, :udp_wake_host, :udp_wake_port]
12
+ :push, :store, :logger, :batch_storage_updates, :wakeup]
13
13
 
14
14
  class ConfigurationWithoutDefaults < Struct.new(*CONFIG_ATTRS)
15
15
  end
@@ -51,15 +51,15 @@ module Rapns
51
51
  end
52
52
 
53
53
  def self.interruptible_sleeper
54
- unless @interruptible_sleeper
55
- @interruptible_sleeper = InterruptibleSleep.new
56
- if Rapns.config.udp_wake_host && Rapns.config.udp_wake_port
57
- @interruptible_sleeper.enable_wake_on_udp Rapns.config.udp_wake_host, Rapns.config.udp_wake_port
58
- end
54
+ return @interruptible_sleeper if @interruptible_sleeper
55
+
56
+ @interruptible_sleeper = InterruptibleSleep.new
57
+ if Rapns.config.wakeup
58
+ @interruptible_sleeper.enable_wake_on_udp Rapns.config.wakeup[:bind], Rapns.config.wakeup[:port]
59
59
  end
60
+
60
61
  @interruptible_sleeper
61
62
  end
62
-
63
63
  end
64
64
  end
65
65
  end
@@ -46,6 +46,9 @@ module Rapns
46
46
 
47
47
  def ok(response)
48
48
  body = multi_json_load(response.body)
49
+
50
+ handle_canonical_ids(response, body)
51
+
49
52
  if body['failure'].to_i == 0
50
53
  mark_delivered
51
54
  Rapns.logger.info("[#{@app.name}] #{@notification.id} sent to #{@notification.registration_ids.join(', ')}")
@@ -54,7 +57,6 @@ module Rapns
54
57
  handle_errors(response, body)
55
58
  end
56
59
 
57
- handle_canonical_ids(response, body)
58
60
  end
59
61
 
60
62
  def handle_errors(response, body)
@@ -63,9 +65,10 @@ module Rapns
63
65
  body['results'].each_with_index do |result, i|
64
66
  errors[i] = result['error'] if result['error'] && ! INVALID_REGISTRATION_ID_STATES.include?(result['error'])
65
67
  end
66
- return if errors.empty?
67
68
 
68
- if body['success'].to_i == 0 && errors.values.all? { |error| UNAVAILABLE_STATES.include?(error) }
69
+ if errors.empty?
70
+ all_errors_were_invalid_registration_ids(response)
71
+ elsif body['success'].to_i == 0 && errors.values.all? { |error| UNAVAILABLE_STATES.include?(error) }
69
72
  all_devices_unavailable(response)
70
73
  elsif errors.values.any? { |error| UNAVAILABLE_STATES.include?(error) }
71
74
  some_devices_unavailable(response, errors)
@@ -117,6 +120,10 @@ module Rapns
117
120
  Rapns.logger.warn("All recipients unavailable. " + retry_message)
118
121
  end
119
122
 
123
+ def all_errors_were_invalid_registration_ids(response)
124
+ mark_failed(nil, "All registration IDs were invalid.")
125
+ end
126
+
120
127
  def some_devices_unavailable(response, errors)
121
128
  unavailable_idxs = errors.find_all { |i, error| UNAVAILABLE_STATES.include?(error) }.map(&:first)
122
129
  new_notification = create_new_notification(response, unavailable_idxs)
@@ -32,4 +32,21 @@ module Rapns
32
32
  end
33
33
 
34
34
  end
35
+
36
+ # Call this from a client application after saving a Notification to the database to wakeup the Rapns
37
+ # Daemon to deliver the notification immediately.
38
+ def self.wakeup
39
+ notifier.notify
40
+ end
41
+
42
+ # Default notifier instance. This uses the :connect, :port values in Rapns.config.wakeup to connect to the
43
+ # wakeup socket in the Rapns Daemon. It will fall back to :host, :port if :connect is not specified.
44
+ def self.notifier
45
+ unless @notifier
46
+ if Rapns.config.wakeup
47
+ @notifier = Notifier.new(Rapns.config.wakeup[:connect] || Rapns.config.wakeup[:host], Rapns.config.wakeup[:port])
48
+ end
49
+ end
50
+ @notifier
51
+ end
35
52
  end
data/lib/rapns/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Rapns
2
- VERSION = '3.4.3'
2
+ VERSION = '3.5.0'
3
3
  end
data/lib/rapns_rails_2.rb CHANGED
@@ -34,6 +34,7 @@ require 'rapns/embed'
34
34
  require 'rapns/push'
35
35
  require 'rapns/apns_feedback'
36
36
  require 'rapns/upgraded'
37
+ require 'rapns/notifier'
37
38
 
38
39
  require 'rapns/apns/binary_notification_validator'
39
40
  require 'rapns/apns/device_token_format_validator'
@@ -4,6 +4,6 @@ describe Rapns::Apns::Feedback do
4
4
  it "should validate the format of the device_token" do
5
5
  notification = Rapns::Apns::Feedback.new(:device_token => "{$%^&*()}")
6
6
  notification.valid?.should be_false
7
- notification.errors[:device_token].include?("is invalid").should be_true
7
+ notification.errors[:device_token].should include("is invalid")
8
8
  end
9
9
  end
@@ -5,77 +5,85 @@ describe Rapns::Daemon::Feeder do
5
5
  :push_poll => 0,
6
6
  :embedded => false,
7
7
  :push => false,
8
- :udp_wake_host => nil,
9
- :udp_wake_port => nil) }
8
+ :wakeup => nil) }
10
9
  let!(:app) { Rapns::Apns::App.create!(:name => 'my_app', :environment => 'development', :certificate => TEST_CERT) }
11
10
  let(:notification) { Rapns::Apns::Notification.create!(:device_token => "a" * 64, :app => app) }
12
11
  let(:logger) { double }
12
+ let(:interruptible_sleep) { double(:sleep => nil, :interrupt_sleep => nil) }
13
13
 
14
14
  before do
15
15
  Rapns.stub(:config => config,:logger => logger)
16
16
  Rapns::Daemon.stub(:store => double(:deliverable_notifications => [notification]))
17
17
  Rapns::Daemon::Feeder.stub(:stop? => true)
18
18
  Rapns::Daemon::AppRunner.stub(:enqueue => nil, :idle => [double(:app => app)])
19
+ Rapns::Daemon::InterruptibleSleep.stub(:new => interruptible_sleep)
20
+ Rapns::Daemon::Feeder.instance_variable_set('@interruptible_sleeper', nil)
19
21
  end
20
22
 
21
- def start
23
+ def start_and_stop
22
24
  Rapns::Daemon::Feeder.start
25
+ Rapns::Daemon::Feeder.stop
23
26
  end
24
27
 
25
28
  it "starts the loop in a new thread if embedded" do
26
29
  config.stub(:embedded => true)
27
30
  Thread.should_receive(:new).and_yield
28
31
  Rapns::Daemon::Feeder.should_receive(:feed_forever)
29
- start
32
+ start_and_stop
30
33
  end
31
34
 
32
35
  it 'loads deliverable notifications' do
33
36
  Rapns::Daemon.store.should_receive(:deliverable_notifications).with([app])
34
- start
37
+ start_and_stop
35
38
  end
36
39
 
37
40
  it 'does not attempt to load deliverable notifications if there are no idle runners' do
38
41
  Rapns::Daemon::AppRunner.stub(:idle => [])
39
42
  Rapns::Daemon.store.should_not_receive(:deliverable_notifications)
40
- start
43
+ start_and_stop
41
44
  end
42
45
 
43
46
  it 'enqueues notifications without looping if in push mode' do
44
47
  config.stub(:push => true)
45
48
  Rapns::Daemon::Feeder.should_not_receive(:feed_forever)
46
49
  Rapns::Daemon::Feeder.should_receive(:enqueue_notifications)
47
- start
50
+ start_and_stop
48
51
  end
49
52
 
50
53
  it "enqueues the notifications" do
51
54
  Rapns::Daemon::AppRunner.should_receive(:enqueue).with([notification])
52
- start
55
+ start_and_stop
53
56
  end
54
57
 
55
58
  it "logs errors" do
56
59
  e = StandardError.new("bork")
57
60
  Rapns::Daemon.store.stub(:deliverable_notifications).and_raise(e)
58
61
  Rapns.logger.should_receive(:error).with(e)
59
- start
62
+ start_and_stop
60
63
  end
61
64
 
62
65
  it "interrupts sleep when stopped" do
63
66
  Rapns::Daemon::Feeder.should_receive(:interrupt_sleep)
64
- Rapns::Daemon::Feeder.stop
67
+ start_and_stop
65
68
  end
66
69
 
67
70
  it "enqueues notifications when started" do
68
71
  Rapns::Daemon::Feeder.should_receive(:enqueue_notifications).at_least(:once)
69
72
  Rapns::Daemon::Feeder.stub(:loop).and_yield
70
- start
73
+ start_and_stop
71
74
  end
72
75
 
73
76
  it "sleeps for the given period" do
74
77
  config.stub(:push_poll => 2)
75
- sleeper = double(:sleep => true)
76
- sleeper.should_receive(:sleep).with(2)
77
- Rapns::Daemon::Feeder.stub(:interruptible_sleeper => sleeper)
78
- Rapns::Daemon::Feeder.stub(:loop).and_yield
79
- Rapns::Daemon::Feeder.start
78
+ interruptible_sleep.should_receive(:sleep).with(2)
79
+ start_and_stop
80
+ end
81
+
82
+ it "creates the wakeup socket" do
83
+ bind = '127.0.0.1'
84
+ port = 12345
85
+ config.stub(:wakeup => { :bind => bind, :port => port})
86
+ interruptible_sleep.should_receive(:enable_wake_on_udp).with(bind, port)
87
+ start_and_stop
80
88
  end
81
89
  end
@@ -110,7 +110,7 @@ describe Rapns::Daemon::Gcm::Delivery do
110
110
  perform
111
111
  end
112
112
 
113
- it 'does not retry, raise or marks a notification as failed for invalid ids.' do
113
+ it 'does marks a notification as failed if any ids are invalid.' do
114
114
  body = {
115
115
  'failure' => 1,
116
116
  'success' => 2,
@@ -122,7 +122,7 @@ describe Rapns::Daemon::Gcm::Delivery do
122
122
  ]}
123
123
 
124
124
  response.stub(:body => MultiJson.dump(body))
125
- batch.should_not_receive(:mark_failed)
125
+ batch.should_receive(:mark_failed)
126
126
  batch.should_not_receive(:mark_retryable)
127
127
  store.should_not_receive(:create_gcm_notification)
128
128
  perform
@@ -29,4 +29,24 @@ describe Rapns::Notifier do
29
29
  end
30
30
  end
31
31
  end
32
+
33
+ describe "default notifier" do
34
+ it "creates using :connect first" do
35
+ Rapns.config.stub :wakeup => { :connect => '127.0.0.1', :port => 1234 }
36
+ Rapns::Notifier.should_receive(:new).with('127.0.0.1', 1234)
37
+ Rapns.notifier
38
+ end
39
+
40
+ it "creates using :host next" do
41
+ Rapns.config.stub :wakeup => { :host => '127.0.0.1', :port => 1234 }
42
+ Rapns::Notifier.should_receive(:new).with('127.0.0.1', 1234)
43
+ Rapns.notifier
44
+ end
45
+
46
+ it "returns nil when wakeup is not specified" do
47
+ Rapns.config.stub :wakeup => nil
48
+ Rapns::Notifier.should_not_receive(:new)
49
+ Rapns.notifier.should be_nil
50
+ end
51
+ end
32
52
  end
@@ -4,7 +4,6 @@ require 'bundler'
4
4
  Bundler.require(:default)
5
5
 
6
6
  require 'active_record'
7
- require 'database_cleaner'
8
7
 
9
8
  unless ENV['TRAVIS'] && ENV['QUALITY'] == 'false'
10
9
  begin
@@ -53,6 +52,7 @@ require 'generators/templates/add_gcm'
53
52
  migration.up
54
53
  end
55
54
 
55
+ require 'database_cleaner'
56
56
  DatabaseCleaner.strategy = :truncation
57
57
 
58
58
  require 'rapns_rails_2'
metadata CHANGED
@@ -1,52 +1,62 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: rapns_rails_2
3
- version: !ruby/object:Gem::Version
4
- version: 3.4.3
3
+ version: !ruby/object:Gem::Version
4
+ hash: 19
5
+ prerelease:
6
+ segments:
7
+ - 3
8
+ - 5
9
+ - 0
10
+ version: 3.5.0
5
11
  platform: ruby
6
- authors:
12
+ authors:
7
13
  - Ian Leitch
8
14
  - Marc Rohloff
9
15
  autorequire:
10
16
  bindir: bin
11
17
  cert_chain: []
12
- date: 2013-10-02 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
18
+
19
+ date: 2013-11-20 00:00:00 Z
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
15
22
  name: multi_json
16
- requirement: !ruby/object:Gem::Requirement
17
- requirements:
18
- - - ~>
19
- - !ruby/object:Gem::Version
20
- version: '1.0'
21
- type: :runtime
22
23
  prerelease: false
23
- version_requirements: !ruby/object:Gem::Requirement
24
- requirements:
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
25
27
  - - ~>
26
- - !ruby/object:Gem::Version
27
- version: '1.0'
28
- - !ruby/object:Gem::Dependency
29
- name: net-http-persistent
30
- requirement: !ruby/object:Gem::Requirement
31
- requirements:
32
- - - ! '>='
33
- - !ruby/object:Gem::Version
34
- version: '0'
28
+ - !ruby/object:Gem::Version
29
+ hash: 15
30
+ segments:
31
+ - 1
32
+ - 0
33
+ version: "1.0"
35
34
  type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: net-http-persistent
36
38
  prerelease: false
37
- version_requirements: !ruby/object:Gem::Requirement
38
- requirements:
39
- - - ! '>='
40
- - !ruby/object:Gem::Version
41
- version: '0'
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 3
45
+ segments:
46
+ - 0
47
+ version: "0"
48
+ type: :runtime
49
+ version_requirements: *id002
42
50
  description: Professional grade APNs and GCM for Ruby with Rails 2 compatibility
43
- email:
51
+ email:
44
52
  - port001@gmail.com
45
- executables:
53
+ executables:
46
54
  - rapns
47
55
  extensions: []
56
+
48
57
  extra_rdoc_files: []
49
- files:
58
+
59
+ files:
50
60
  - CHANGELOG.md
51
61
  - LICENSE
52
62
  - README.md
@@ -160,28 +170,38 @@ files:
160
170
  - bin/rapns
161
171
  homepage: https://github.com/marcrohloff/rapns_rails_2
162
172
  licenses: []
163
- metadata: {}
173
+
164
174
  post_install_message:
165
175
  rdoc_options: []
166
- require_paths:
176
+
177
+ require_paths:
167
178
  - lib
168
- required_ruby_version: !ruby/object:Gem::Requirement
169
- requirements:
170
- - - ! '>='
171
- - !ruby/object:Gem::Version
172
- version: '0'
173
- required_rubygems_version: !ruby/object:Gem::Requirement
174
- requirements:
175
- - - ! '>='
176
- - !ruby/object:Gem::Version
177
- version: '0'
179
+ required_ruby_version: !ruby/object:Gem::Requirement
180
+ none: false
181
+ requirements:
182
+ - - ">="
183
+ - !ruby/object:Gem::Version
184
+ hash: 3
185
+ segments:
186
+ - 0
187
+ version: "0"
188
+ required_rubygems_version: !ruby/object:Gem::Requirement
189
+ none: false
190
+ requirements:
191
+ - - ">="
192
+ - !ruby/object:Gem::Version
193
+ hash: 3
194
+ segments:
195
+ - 0
196
+ version: "0"
178
197
  requirements: []
198
+
179
199
  rubyforge_project:
180
- rubygems_version: 2.0.2
200
+ rubygems_version: 1.8.4
181
201
  signing_key:
182
- specification_version: 4
202
+ specification_version: 3
183
203
  summary: Professional grade APNs and GCM for Ruby
184
- test_files:
204
+ test_files:
185
205
  - config/database.yml
186
206
  - spec/support/cert_with_password.pem
187
207
  - spec/support/cert_without_password.pem
checksums.yaml DELETED
@@ -1,15 +0,0 @@
1
- ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- ODdlNDhlOTIzODkyMDZiODdiNzIwYjAyNDJlNjkzZDYyMmYyZDhjNQ==
5
- data.tar.gz: !binary |-
6
- NDlhMWY3NGRmOTUwMmQ1NGRjMjg2MjE2ZDY5NmYwNWE5NjgyZWM1MA==
7
- !binary "U0hBNTEy":
8
- metadata.gz: !binary |-
9
- MTkzNDAxZTZmNWM4YTg3OTEzYWJhM2Q1YmE3MzBhZjg0YjUxYWJmMjAwYWMz
10
- NGZmMGM0Mzk4MDM1MGU3OTFjZWVlNThhZTg1MDhiMmRmNDFhZjk3ZjcxYTA4
11
- OTllMzFjM2NkZWRmYmVhZTlmOTkwYzlhMGI3NmVkZjQ1NjRiMTE=
12
- data.tar.gz: !binary |-
13
- YzQ3ZmMzMzU1MzFmYzczZGI4M2FlYWRjMTY3Y2NmNmJlOTY5Y2UxMWNhODUz
14
- NTlmY2QwNTEyMmM0MWVkNGExNGJiNjdlYmViNjY3MzkyOWFhM2M3ZWUwY2Jm
15
- M2Q0ODNlNmJiMmU1MDI2Mjc3ZGIzYjE1ZWQ1YjgxZmZiNGY3MzU=