rpush 2.4.0-java → 2.6.0-java

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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -1
  3. data/README.md +18 -8
  4. data/lib/generators/rpush_migration_generator.rb +1 -0
  5. data/lib/generators/templates/rpush.rb +8 -2
  6. data/lib/generators/templates/rpush_2_0_0_updates.rb +1 -1
  7. data/lib/generators/templates/rpush_2_6_0_updates.rb +10 -0
  8. data/lib/rpush/cli.rb +63 -27
  9. data/lib/rpush/client/active_model.rb +3 -0
  10. data/lib/rpush/client/active_model/apns/notification.rb +1 -1
  11. data/lib/rpush/client/active_model/gcm/notification.rb +1 -0
  12. data/lib/rpush/client/active_model/wns/app.rb +23 -0
  13. data/lib/rpush/client/active_model/wns/notification.rb +28 -0
  14. data/lib/rpush/client/active_model/wpns/notification.rb +11 -6
  15. data/lib/rpush/client/active_record.rb +3 -0
  16. data/lib/rpush/client/active_record/notification.rb +1 -1
  17. data/lib/rpush/client/active_record/wns/app.rb +11 -0
  18. data/lib/rpush/client/active_record/wns/notification.rb +11 -0
  19. data/lib/rpush/client/mongoid.rb +3 -0
  20. data/lib/rpush/client/mongoid/apns/feedback.rb +3 -0
  21. data/lib/rpush/client/mongoid/notification.rb +7 -0
  22. data/lib/rpush/client/mongoid/wns/app.rb +14 -0
  23. data/lib/rpush/client/mongoid/wns/notification.rb +11 -0
  24. data/lib/rpush/client/redis.rb +3 -0
  25. data/lib/rpush/client/redis/notification.rb +1 -0
  26. data/lib/rpush/client/redis/wns/app.rb +14 -0
  27. data/lib/rpush/client/redis/wns/notification.rb +11 -0
  28. data/lib/rpush/configuration.rb +3 -7
  29. data/lib/rpush/daemon.rb +9 -0
  30. data/lib/rpush/daemon/apns/feedback_receiver.rb +5 -0
  31. data/lib/rpush/daemon/app_runner.rb +4 -5
  32. data/lib/rpush/daemon/dispatcher/apns_tcp.rb +47 -12
  33. data/lib/rpush/daemon/dispatcher_loop.rb +5 -0
  34. data/lib/rpush/daemon/feeder.rb +11 -0
  35. data/lib/rpush/daemon/gcm/delivery.rb +2 -2
  36. data/lib/rpush/daemon/interruptible_sleep.rb +8 -3
  37. data/lib/rpush/daemon/loggable.rb +4 -0
  38. data/lib/rpush/daemon/rpc.rb +9 -0
  39. data/lib/rpush/daemon/rpc/client.rb +27 -0
  40. data/lib/rpush/daemon/rpc/server.rb +82 -0
  41. data/lib/rpush/daemon/signal_handler.rb +7 -0
  42. data/lib/rpush/daemon/store/active_record.rb +17 -3
  43. data/lib/rpush/daemon/store/mongoid.rb +2 -2
  44. data/lib/rpush/daemon/store/redis.rb +2 -2
  45. data/lib/rpush/daemon/tcp_connection.rb +2 -2
  46. data/lib/rpush/daemon/wns.rb +9 -0
  47. data/lib/rpush/daemon/wns/delivery.rb +204 -0
  48. data/lib/rpush/embed.rb +15 -13
  49. data/lib/rpush/logger.rb +4 -0
  50. data/lib/rpush/plugin.rb +1 -1
  51. data/lib/rpush/push.rb +2 -11
  52. data/lib/rpush/reflection_collection.rb +15 -17
  53. data/lib/rpush/reflection_public_methods.rb +6 -4
  54. data/lib/rpush/version.rb +1 -1
  55. data/spec/functional/apns_spec.rb +1 -11
  56. data/spec/functional/cli_spec.rb +36 -0
  57. data/spec/functional_spec_helper.rb +11 -1
  58. data/spec/spec_helper.rb +4 -3
  59. data/spec/support/active_record_setup.rb +3 -2
  60. data/spec/unit/client/active_record/apns/notification_spec.rb +1 -1
  61. data/spec/unit/client/active_record/gcm/notification_spec.rb +5 -0
  62. data/spec/unit/configuration_spec.rb +0 -7
  63. data/spec/unit/daemon/adm/delivery_spec.rb +2 -2
  64. data/spec/unit/daemon/app_runner_spec.rb +2 -3
  65. data/spec/unit/daemon/gcm/delivery_spec.rb +1 -1
  66. data/spec/unit/daemon/tcp_connection_spec.rb +1 -1
  67. data/spec/unit/daemon/wns/delivery_spec.rb +171 -0
  68. data/spec/unit/daemon/wpns/delivery_spec.rb +1 -1
  69. data/spec/unit/daemon_spec.rb +2 -0
  70. data/spec/unit/embed_spec.rb +4 -11
  71. data/spec/unit/logger_spec.rb +2 -2
  72. data/spec/unit/push_spec.rb +0 -7
  73. data/spec/unit_spec_helper.rb +1 -1
  74. metadata +20 -2
@@ -27,5 +27,8 @@ require 'rpush/client/mongoid/gcm/app'
27
27
  require 'rpush/client/mongoid/wpns/notification'
28
28
  require 'rpush/client/mongoid/wpns/app'
29
29
 
30
+ require 'rpush/client/mongoid/wns/notification'
31
+ require 'rpush/client/mongoid/wns/app'
32
+
30
33
  require 'rpush/client/mongoid/adm/notification'
31
34
  require 'rpush/client/mongoid/adm/app'
@@ -13,6 +13,9 @@ module Rpush
13
13
  validates :device_token, presence: true
14
14
  validates :failed_at, presence: true
15
15
 
16
+ index device_token: 1
17
+ index app_id: 1
18
+
16
19
  validates_with Rpush::Client::ActiveModel::Apns::DeviceTokenFormatValidator
17
20
  end
18
21
  end
@@ -3,6 +3,7 @@ module Rpush
3
3
  module Mongoid
4
4
  class Notification
5
5
  include ::Mongoid::Document
6
+ include ::Mongoid::Timestamps
6
7
  include ::Mongoid::Autoinc
7
8
  include Rpush::MultiJsonHelper
8
9
  include Rpush::Client::ActiveModel::Notification
@@ -31,11 +32,17 @@ module Rpush
31
32
  field :priority, type: Integer
32
33
  field :url_args, type: Array
33
34
  field :category, type: String
35
+ field :content_available, type: Boolean, default: false
34
36
 
35
37
  field :integer_id, type: Integer
36
38
  increments :integer_id, model_name: name
37
39
  index integer_id: 1
38
40
 
41
+ index delivered: 1, failed: 1, deliver_after: 1, processing: 1
42
+ index delivered: 1, failed: 1
43
+ index device_token: 1
44
+ index app_id: 1
45
+
39
46
  belongs_to :app
40
47
  end
41
48
  end
@@ -0,0 +1,14 @@
1
+ module Rpush
2
+ module Client
3
+ module Mongoid
4
+ module Wns
5
+ class App < Rpush::Client::Mongoid::App
6
+ include Rpush::Client::ActiveModel::Wns::App
7
+
8
+ field :access_token, type: String
9
+ field :access_token_expiration, type: Time
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ module Rpush
2
+ module Client
3
+ module Mongoid
4
+ module Wns
5
+ class Notification < Rpush::Client::Mongoid::Notification
6
+ include Rpush::Client::ActiveModel::Wns::Notification
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -30,6 +30,9 @@ require 'rpush/client/redis/adm/notification'
30
30
  require 'rpush/client/redis/wpns/app'
31
31
  require 'rpush/client/redis/wpns/notification'
32
32
 
33
+ require 'rpush/client/redis/wns/app'
34
+ require 'rpush/client/redis/wns/notification'
35
+
33
36
  Modis.configure do |config|
34
37
  config.namespace = :rpush
35
38
  end
@@ -42,6 +42,7 @@ module Rpush
42
42
  attribute :priority, :integer
43
43
  attribute :url_args, :array
44
44
  attribute :category, :string
45
+ attribute :content_available, :boolean, default: false
45
46
 
46
47
  def app
47
48
  return nil unless app_id
@@ -0,0 +1,14 @@
1
+ module Rpush
2
+ module Client
3
+ module Redis
4
+ module Wns
5
+ class App < Rpush::Client::Redis::App
6
+ include Rpush::Client::ActiveModel::Wns::App
7
+
8
+ attribute :access_token, :string
9
+ attribute :access_token_expiration, :timestamp
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ module Rpush
2
+ module Client
3
+ module Redis
4
+ module Wns
5
+ class Notification < Rpush::Client::Redis::Notification
6
+ include Rpush::Client::ActiveModel::Wns::Notification
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,4 +1,5 @@
1
1
  require 'pathname'
2
+ require 'ostruct'
2
3
 
3
4
  module Rpush
4
5
  class << self
@@ -16,7 +17,7 @@ module Rpush
16
17
  end
17
18
 
18
19
  CURRENT_ATTRS = [:push_poll, :embedded, :pid_file, :batch_size, :push, :client, :logger, :log_file, :foreground, :log_level, :plugin, :apns]
19
- DEPRECATED_ATTRS = [:feedback_poll]
20
+ DEPRECATED_ATTRS = []
20
21
  CONFIG_ATTRS = CURRENT_ATTRS + DEPRECATED_ATTRS
21
22
 
22
23
  class ConfigurationError < StandardError; end
@@ -97,11 +98,6 @@ module Rpush
97
98
  Modis.redis_options = options if client == :redis
98
99
  end
99
100
 
100
- def feedback_poll=(frequency)
101
- apns.feedback_receiver.frequency = frequency
102
- end
103
- deprecated(:feedback_poll=, '2.5.0', 'Please use apns.feedback_receiver.frequency= instead.')
104
-
105
101
  def initialize_client
106
102
  return if @client_initialized
107
103
  raise ConfigurationError, 'Rpush.config.client is not set.' unless client
@@ -110,7 +106,7 @@ module Rpush
110
106
  client_module = Rpush::Client.const_get(client.to_s.camelize)
111
107
  Rpush.send(:include, client_module) unless Rpush.ancestors.include?(client_module)
112
108
 
113
- [:Apns, :Gcm, :Wpns, :Adm].each do |service|
109
+ [:Apns, :Gcm, :Wpns, :Wns, :Adm].each do |service|
114
110
  Rpush.const_set(service, client_module.const_get(service)) unless Rpush.const_defined?(service)
115
111
  end
116
112
 
@@ -30,6 +30,10 @@ require 'rpush/daemon/ring_buffer'
30
30
  require 'rpush/daemon/signal_handler'
31
31
  require 'rpush/daemon/proc_title'
32
32
 
33
+ require 'rpush/daemon/rpc'
34
+ require 'rpush/daemon/rpc/server'
35
+ require 'rpush/daemon/rpc/client'
36
+
33
37
  require 'rpush/daemon/store/interface'
34
38
 
35
39
  require 'rpush/daemon/apns/delivery'
@@ -42,6 +46,9 @@ require 'rpush/daemon/gcm'
42
46
  require 'rpush/daemon/wpns/delivery'
43
47
  require 'rpush/daemon/wpns'
44
48
 
49
+ require 'rpush/daemon/wns/delivery'
50
+ require 'rpush/daemon/wns'
51
+
45
52
  require 'rpush/daemon/adm/delivery'
46
53
  require 'rpush/daemon/adm'
47
54
 
@@ -57,6 +64,7 @@ module Rpush
57
64
  SignalHandler.start
58
65
  common_init
59
66
  Synchronizer.sync
67
+ Rpc::Server.start
60
68
 
61
69
  # No further store connections will be made from this thread.
62
70
  store.release_connection
@@ -81,6 +89,7 @@ module Rpush
81
89
  Rpush.logger.info('Shutting down... ', true)
82
90
 
83
91
  shutdown_lock.synchronize do
92
+ Rpc::Server.stop
84
93
  Feeder.stop
85
94
  AppRunner.stop
86
95
  delete_pid_file
@@ -43,6 +43,11 @@ module Rpush
43
43
  @stop = true
44
44
  @interruptible_sleep.stop
45
45
  @thread.join if @thread
46
+ rescue StandardError => e
47
+ log_error(e)
48
+ reflect(:error, e)
49
+ ensure
50
+ @thread = nil
46
51
  end
47
52
 
48
53
  def check_for_feedback
@@ -84,8 +84,8 @@ module Rpush
84
84
  @runners[app.id].increment_dispatchers(num)
85
85
  end
86
86
 
87
- def self.debug
88
- @runners.values.map(&:debug)
87
+ def self.status
88
+ { app_runners: @runners.values.map(&:status) }
89
89
  end
90
90
 
91
91
  attr_reader :app
@@ -140,7 +140,7 @@ module Rpush
140
140
  num.times { @dispatcher_loops.push(new_dispatcher_loop) }
141
141
  end
142
142
 
143
- def debug
143
+ def status
144
144
  dispatcher_details = {}
145
145
 
146
146
  @dispatcher_loops.each_with_index do |dispatcher_loop, i|
@@ -151,8 +151,7 @@ module Rpush
151
151
  }
152
152
  end
153
153
 
154
- runner_details = { dispatchers: dispatcher_details, queued: queue_size }
155
- log_info(JSON.pretty_generate(runner_details))
154
+ { app_name: @app.name, dispatchers: dispatcher_details, queued: queue_size }
156
155
  end
157
156
 
158
157
  def num_dispatcher_loops
@@ -16,6 +16,7 @@ module Rpush
16
16
  6 => 'Missing topic size',
17
17
  7 => 'Missing payload size',
18
18
  8 => 'Invalid token',
19
+ 10 => 'APNs closed connection (possible maintenance)',
19
20
  255 => 'None (unknown error)'
20
21
  }
21
22
 
@@ -34,9 +35,21 @@ module Rpush
34
35
  end
35
36
 
36
37
  def cleanup
38
+ if Rpush.config.push
39
+ # In push mode only a single batch is sent, followed my immediate shutdown.
40
+ # Allow the error receiver time to handle any errors.
41
+ @reconnect_disabled = true
42
+ sleep 1
43
+ end
44
+
37
45
  @stop_error_receiver = true
38
46
  super
39
47
  @error_receiver_thread.join if @error_receiver_thread
48
+ rescue StandardError => e
49
+ log_error(e)
50
+ reflect(:error, e)
51
+ ensure
52
+ @error_receiver_thread = nil
40
53
  end
41
54
 
42
55
  private
@@ -63,12 +76,12 @@ module Rpush
63
76
  # On Linux, select returns nil from a dropped connection.
64
77
  # On OS X, Errno::EBADF is raised following a Errno::EADDRNOTAVAIL from the write call.
65
78
  return unless @connection.select(SELECT_TIMEOUT)
66
- rescue SystemCallError, IOError
67
- # Connection closed.
79
+ tuple = @connection.read(ERROR_TUPLE_BYTES)
80
+ rescue *TcpConnection::TCP_ERRORS
81
+ reconnect unless @stop_error_receiver
68
82
  return
69
83
  end
70
84
 
71
- tuple = @connection.read(ERROR_TUPLE_BYTES)
72
85
  @dispatch_mutex.synchronize { handle_error_response(tuple) }
73
86
  rescue StandardError => e
74
87
  log_error(e)
@@ -82,12 +95,23 @@ module Rpush
82
95
  handle_disconnect
83
96
  end
84
97
 
85
- log_error("Lost connection to #{@connection.host}:#{@connection.port}, reconnecting...")
86
- @connection.reconnect_with_rescue
98
+ if Rpush.config.push
99
+ # Only attempt to handle a single error in Push mode.
100
+ @stop_error_receiver = true
101
+ return
102
+ end
103
+
104
+ reconnect
87
105
  ensure
88
106
  delivered_buffer.clear
89
107
  end
90
108
 
109
+ def reconnect
110
+ return if @reconnect_disabled
111
+ log_error("Lost connection to #{@connection.host}:#{@connection.port}, reconnecting...")
112
+ @connection.reconnect_with_rescue
113
+ end
114
+
91
115
  def handle_disconnect
92
116
  log_error("The APNs disconnected before any notifications could be delivered. This usually indicates you are using an invalid certificate.") if delivered_buffer.size == 0
93
117
  end
@@ -95,22 +119,33 @@ module Rpush
95
119
  def handle_error(code, notification_id)
96
120
  notification_id = Rpush::Daemon.store.translate_integer_notification_id(notification_id)
97
121
  failed_pos = delivered_buffer.index(notification_id)
98
- description = APNS_ERRORS[code.to_i] || "Unknown error code #{code.inspect}. Possible Rpush bug?"
99
- log_error(description + " (#{code})")
122
+ description = description_for_code(code)
123
+ log_error("Notification #{notification_id} failed with error: " + description)
100
124
  Rpush::Daemon.store.mark_ids_failed([notification_id], code, description, Time.now)
101
125
  reflect(:notification_id_failed, @app, notification_id, code, description)
102
126
 
103
127
  if failed_pos
104
128
  retry_ids = delivered_buffer[(failed_pos + 1)..-1]
105
- if retry_ids.size > 0
106
- now = Time.now
107
- Rpush::Daemon.store.mark_ids_retryable(retry_ids, now)
108
- retry_ids.each { |id| reflect(:notification_id_will_retry, @app, id, now) }
109
- end
129
+ retry_notification_ids(retry_ids, notification_id)
110
130
  elsif delivered_buffer.size > 0
111
131
  log_error("Delivery sequence unknown for notifications following #{notification_id}.")
112
132
  end
113
133
  end
134
+
135
+ def description_for_code(code)
136
+ APNS_ERRORS[code.to_i] ? "#{APNS_ERRORS[code.to_i]} (#{code})" : "Unknown error code #{code.inspect}. Possible Rpush bug?"
137
+ end
138
+
139
+ def retry_notification_ids(ids, notification_id)
140
+ return if ids.size == 0
141
+
142
+ now = Time.now
143
+ Rpush::Daemon.store.mark_ids_retryable(ids, now)
144
+ notifications_str = 'Notification'
145
+ notifications_str += 's' if ids.size > 1
146
+ log_warn("#{notifications_str} #{ids.join(', ')} will be retried due to the failure of notification #{notification_id}.")
147
+ ids.each { |id| reflect(:notification_id_will_retry, @app, id, now) }
148
+ end
114
149
  end
115
150
  end
116
151
  end
@@ -44,6 +44,11 @@ module Rpush
44
44
  @queue.push([STOP, object_id]) if @thread
45
45
  @thread.join if @thread
46
46
  @dispatcher.cleanup
47
+ rescue StandardError => e
48
+ log_error(e)
49
+ reflect(:error, e)
50
+ ensure
51
+ @thread = nil
47
52
  end
48
53
 
49
54
  private
@@ -2,6 +2,7 @@ module Rpush
2
2
  module Daemon
3
3
  class Feeder
4
4
  extend Reflectable
5
+ extend Loggable
5
6
 
6
7
  def self.start(push_mode = false)
7
8
  self.should_stop = false
@@ -12,12 +13,22 @@ module Rpush
12
13
  end
13
14
 
14
15
  @thread.join
16
+ rescue StandardError => e
17
+ log_error(e)
18
+ reflect(:error, e)
19
+ ensure
20
+ @thread = nil
15
21
  end
16
22
 
17
23
  def self.stop
18
24
  self.should_stop = true
19
25
  interruptible_sleeper.stop
20
26
  @thread.join if @thread
27
+ rescue StandardError => e
28
+ log_error(e)
29
+ reflect(:error, e)
30
+ ensure
31
+ @thread = nil
21
32
  end
22
33
 
23
34
  def self.wakeup
@@ -5,7 +5,7 @@ module Rpush
5
5
  class Delivery < Rpush::Daemon::Delivery
6
6
  include MultiJsonHelper
7
7
 
8
- host = 'https://android.googleapis.com'
8
+ host = 'https://gcm-http.googleapis.com'
9
9
  GCM_URI = URI.parse("#{host}/gcm/send")
10
10
  UNAVAILABLE_STATES = %w(Unavailable InternalServerError)
11
11
  INVALID_REGISTRATION_ID_STATES = %w(InvalidRegistration MismatchSenderId NotRegistered InvalidPackageName)
@@ -44,7 +44,7 @@ module Rpush
44
44
  when 503
45
45
  service_unavailable(response)
46
46
  else
47
- fail Rpush::DeliveryError.new(response.code, @notification.id, Rpush::Daemon::HTTP_STATUS_CODES[response.code.to_i])
47
+ fail Rpush::DeliveryError.new(response.code.to_i, @notification.id, Rpush::Daemon::HTTP_STATUS_CODES[response.code.to_i])
48
48
  end
49
49
  end
50
50
 
@@ -1,17 +1,22 @@
1
- require 'monitor'
2
-
3
1
  module Rpush
4
2
  module Daemon
5
3
  class InterruptibleSleep
6
4
  def sleep(duration)
7
5
  @thread = Thread.new { Kernel.sleep duration }
8
6
  Thread.pass
9
- @thread.join
7
+
8
+ begin
9
+ @thread.join
10
+ rescue StandardError
11
+ @thread = nil
12
+ end
10
13
  end
11
14
 
12
15
  def stop
13
16
  @thread.kill if @thread
14
17
  rescue StandardError # rubocop:disable Lint/HandleExceptions
18
+ ensure
19
+ @thread = nil
15
20
  end
16
21
  end
17
22
  end
@@ -1,6 +1,10 @@
1
1
  module Rpush
2
2
  module Daemon
3
3
  module Loggable
4
+ def log_debug(msg)
5
+ Rpush.logger.debug(app_prefix(msg))
6
+ end
7
+
4
8
  def log_info(msg)
5
9
  Rpush.logger.info(app_prefix(msg))
6
10
  end