rpush 2.2.0 → 2.3.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/README.md +17 -9
  4. data/lib/generators/rpush_migration_generator.rb +1 -1
  5. data/lib/rpush.rb +4 -1
  6. data/lib/rpush/apns_feedback.rb +1 -1
  7. data/lib/rpush/cli.rb +25 -22
  8. data/lib/rpush/client/active_model/apns/app.rb +1 -1
  9. data/lib/rpush/client/active_model/apns/notification.rb +2 -2
  10. data/lib/rpush/client/active_model/wpns/notification.rb +7 -1
  11. data/lib/rpush/configuration.rb +32 -22
  12. data/lib/rpush/daemon.rb +18 -9
  13. data/lib/rpush/daemon/adm/delivery.rb +4 -1
  14. data/lib/rpush/daemon/apns/delivery.rb +3 -0
  15. data/lib/rpush/daemon/apns/feedback_receiver.rb +6 -2
  16. data/lib/rpush/daemon/app_runner.rb +11 -16
  17. data/lib/rpush/daemon/batch.rb +9 -0
  18. data/lib/rpush/daemon/delivery.rb +10 -2
  19. data/lib/rpush/daemon/delivery_error.rb +3 -3
  20. data/lib/rpush/daemon/dispatcher/apns_tcp.rb +11 -11
  21. data/lib/rpush/daemon/dispatcher/tcp.rb +2 -10
  22. data/lib/rpush/daemon/gcm/delivery.rb +13 -7
  23. data/lib/rpush/daemon/signal_handler.rb +5 -3
  24. data/lib/rpush/daemon/store/active_record.rb +14 -0
  25. data/lib/rpush/daemon/store/interface.rb +2 -1
  26. data/lib/rpush/daemon/store/redis.rb +3 -0
  27. data/lib/rpush/daemon/tcp_connection.rb +47 -17
  28. data/lib/rpush/daemon/wpns/delivery.rb +19 -10
  29. data/lib/rpush/logger.rb +30 -12
  30. data/lib/rpush/plugin.rb +44 -0
  31. data/lib/rpush/push.rb +1 -1
  32. data/lib/rpush/reflectable.rb +11 -0
  33. data/lib/rpush/{reflection.rb → reflection_collection.rb} +1 -9
  34. data/lib/rpush/reflection_public_methods.rb +9 -0
  35. data/lib/rpush/version.rb +1 -1
  36. data/lib/tasks/test.rake +6 -4
  37. data/spec/functional/adm_spec.rb +12 -0
  38. data/spec/functional/apns_spec.rb +61 -42
  39. data/spec/functional/gcm_spec.rb +9 -0
  40. data/spec/functional/retry_spec.rb +1 -1
  41. data/spec/functional/wpns_spec.rb +44 -11
  42. data/spec/spec_helper.rb +2 -0
  43. data/spec/unit/apns_feedback_spec.rb +2 -2
  44. data/spec/unit/client/active_record/apns/app_spec.rb +2 -2
  45. data/spec/unit/client/active_record/apns/notification_spec.rb +1 -2
  46. data/spec/unit/client/active_record/wpns/notification_spec.rb +9 -3
  47. data/spec/unit/configuration_spec.rb +1 -0
  48. data/spec/unit/daemon/adm/delivery_spec.rb +0 -1
  49. data/spec/unit/daemon/apns/feedback_receiver_spec.rb +0 -1
  50. data/spec/unit/daemon/app_runner_spec.rb +14 -9
  51. data/spec/unit/daemon/delivery_spec.rb +0 -1
  52. data/spec/unit/daemon/dispatcher/tcp_spec.rb +0 -7
  53. data/spec/unit/daemon/gcm/delivery_spec.rb +1 -1
  54. data/spec/unit/daemon/signal_handler_spec.rb +5 -1
  55. data/spec/unit/daemon/store/active_record_spec.rb +1 -1
  56. data/spec/unit/daemon/tcp_connection_spec.rb +18 -18
  57. data/spec/unit/daemon/wpns/delivery_spec.rb +1 -1
  58. data/spec/unit/daemon_spec.rb +10 -2
  59. data/spec/unit/logger_spec.rb +0 -1
  60. data/spec/unit/plugin_spec.rb +36 -0
  61. data/spec/unit/push_spec.rb +2 -2
  62. data/spec/unit/{daemon/reflectable_spec.rb → reflectable_spec.rb} +6 -6
  63. data/spec/unit/{reflection_spec.rb → reflection_collection_spec.rb} +4 -8
  64. metadata +16 -18
  65. data/lib/rpush/daemon/reflectable.rb +0 -11
  66. data/spec/integration/rpush_spec.rb +0 -13
  67. data/spec/integration/support/gcm_success_response.json +0 -1
  68. data/spec/support/install.sh +0 -68
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ade9eddd89766399d488b8d364041c517911c0cc
4
- data.tar.gz: 3ee953452451b0ea1318de7f52e090ab58bd6439
3
+ metadata.gz: f5611fd691dabad23056a88e8f2365f6ce04b763
4
+ data.tar.gz: 82754af135986e7b53c8f2243336a407072c513a
5
5
  SHA512:
6
- metadata.gz: 9f10cb58e8a84f852a43bd9d2b7b7bea5df1d8f3bed8638297601960a9365254e4605376f340f78dcc3c1e0296269a31b97554705f588642cc1dc481ec905d22
7
- data.tar.gz: ed5f267363e0b76deaf60811109c8e6fe9ef63e95f35c8e4bc266edd46efc4f4c1900e2a47116a92ff1463a761b5533c085c1f166f04c6a2acbffae4ef31c39c
6
+ metadata.gz: c8c6f6eb789c720bec7c28c080855014032a510fae0e84faa009c5fa19891e6d879959161d693256177c3cd7eee3dad5dcb7b9b3396245b4d51103b0d84b662b
7
+ data.tar.gz: 7ce71396e9811513f8387824869f9770ce851d67afaf28ad5ff22429de91d66b71027e7cf085d8f4de5e2a95487616752477b4dda8aa00b450c94c5d78c71f0e
@@ -1,3 +1,13 @@
1
+ ## 2.3.0 (unreleased)
2
+ * Add 'version' CLI command.
3
+ * Rpush::Wpns::Notification now supports setting the 'data' attribute.
4
+ * ActiveRecord is now directed to the configured Rpush logger (#104).
5
+ * Logs are reopened when the HUP signal is received (#95).
6
+ * Fix setting config.redis_options (#114).
7
+ * Increase frequency of TCP keepalive probes on Linux.
8
+ * APNs notifications are no longer marked as failed when a dropped connection is detected, as it's impossible to know exactly how many actually failed (if any).
9
+ * Notifications are now retried instead of being marked as failed if a TCP/HTTP connection cannot be established.
10
+
1
11
  ## 2.2.0 (Oct 7, 2014)
2
12
  * Numerous command-line fixes, sorry folks!
3
13
  * Add 'rpush push' command-line command for one-off use.
data/README.md CHANGED
@@ -61,7 +61,7 @@ app.save!
61
61
  ```ruby
62
62
  n = Rpush::Apns::Notification.new
63
63
  n.app = Rpush::Apns::App.find_by_name("ios_app")
64
- n.device_token = "..."
64
+ n.device_token = "..." # 64-character hex string
65
65
  n.alert = "hi mom!"
66
66
  n.data = { foo: :bar }
67
67
  n.save!
@@ -126,7 +126,7 @@ app.save!
126
126
  n = Rpush::Wpns::Notification.new
127
127
  n.app = Rpush::Wpns::App.find_by_name("windows_phone_app")
128
128
  n.uri = "http://..."
129
- n.alert = "..."
129
+ n.data = {title:"MyApp", body:"Hello world", param:"user_param1"}
130
130
  n.save!
131
131
  ```
132
132
 
@@ -143,16 +143,15 @@ rpush start
143
143
 
144
144
  See `rpush help` for all available commands and options.
145
145
 
146
- #### Embedded inside an existing process
146
+ #### One-off, manual
147
147
 
148
- ```ruby
149
- # Call this during startup of your application, for example, by adding it to the end of config/rpush.rb
150
- Rpush.embed
151
- ```
148
+ On the command-line:
152
149
 
153
- See [Embedding API](https://github.com/rpush/rpush/wiki/Embedding-API) for more details.
150
+ ```
151
+ rpush push
152
+ ```
154
153
 
155
- #### Manually (in a scheduler)
154
+ In your code:
156
155
 
157
156
  ```ruby
158
157
  Rpush.push
@@ -161,6 +160,15 @@ Rpush.apns_feedback
161
160
 
162
161
  See [Push API](https://github.com/rpush/rpush/wiki/Push-API) for more details.
163
162
 
163
+ #### Embedded inside an existing process
164
+
165
+ ```ruby
166
+ # Call this during startup of your application, for example, by adding it to the end of config/rpush.rb
167
+ Rpush.embed
168
+ ```
169
+
170
+ See [Embedding API](https://github.com/rpush/rpush/wiki/Embedding-API) for more details.
171
+
164
172
  ### Configuration
165
173
 
166
174
  See [Configuration](https://github.com/rpush/rpush/wiki/Configuration) for a list of options.
@@ -6,7 +6,7 @@ class RpushMigrationGenerator < Rails::Generators::Base
6
6
  @time ||= Time.now.utc
7
7
  @calls ||= -1
8
8
  @calls += 1
9
- (@time + @calls.seconds).strftime("%Y%m%d%H%M%S")
9
+ (@time + @calls.seconds).strftime('%Y%m%d%H%M%S')
10
10
  end
11
11
 
12
12
  def copy_migration
@@ -19,7 +19,10 @@ require 'rpush/deprecatable'
19
19
  require 'rpush/logger'
20
20
  require 'rpush/multi_json_helper'
21
21
  require 'rpush/configuration'
22
- require 'rpush/reflection'
22
+ require 'rpush/reflection_collection'
23
+ require 'rpush/reflection_public_methods'
24
+ require 'rpush/reflectable'
25
+ require 'rpush/plugin'
23
26
  require 'rpush/embed'
24
27
  require 'rpush/push'
25
28
  require 'rpush/apns_feedback'
@@ -1,7 +1,7 @@
1
1
  module Rpush
2
2
  def self.apns_feedback
3
3
  require 'rpush/daemon'
4
- Rpush::Daemon.initialize_store
4
+ Rpush::Daemon.common_init
5
5
 
6
6
  Rpush::Apns::App.all.each do |app|
7
7
  receiver = Rpush::Daemon::Apns::FeedbackReceiver.new(app)
@@ -1,12 +1,10 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  require 'thor'
4
- require 'term/ansicolor'
4
+ require 'ansi/code'
5
5
 
6
6
  module Rpush
7
7
  class CLI < Thor
8
- include Term::ANSIColor
9
-
10
8
  def self.detect_rails?
11
9
  ['bin/rails', 'script/rails'].any? { |path| File.exist?(path) }
12
10
  end
@@ -22,9 +20,7 @@ module Rpush
22
20
  option 'pid-file', type: :string, aliases: '-p'
23
21
  desc 'start', 'Start Rpush'
24
22
  def start
25
- underscore_option_names
26
- check_ruby_version
27
- configure_rpush
23
+ config_setup
28
24
 
29
25
  require 'rpush/daemon'
30
26
  Rpush::Daemon.start
@@ -33,9 +29,7 @@ module Rpush
33
29
  desc 'stop', 'Stop Rpush'
34
30
  option 'pid-file', type: :string, aliases: '-p'
35
31
  def stop
36
- underscore_option_names
37
- check_ruby_version
38
- configure_rpush
32
+ config_setup
39
33
  ensure_pid_file_set
40
34
 
41
35
  if File.exist?(Rpush.config.pid_file)
@@ -53,21 +47,21 @@ module Rpush
53
47
  end
54
48
  end
55
49
 
56
- puts green('✔')
50
+ puts ANSI.green { '✔' }
57
51
  else
58
52
  STDERR.puts("* Rpush isn't running? #{Rpush.config.pid_file} does not exist.")
59
53
  return
60
54
  end
61
55
  end
62
56
 
63
- desc 'init', 'Initialize Rpush into the current directory.'
57
+ desc 'init', 'Initialize Rpush into the current directory'
64
58
  option 'active-record', type: :boolean, desc: 'Install ActiveRecord migrations'
65
59
  def init
66
60
  underscore_option_names
67
61
  check_ruby_version
68
62
  require 'rails/generators'
69
63
 
70
- puts "* #{green('Installing config...')}"
64
+ puts "* " + ANSI.green { 'Installing config...' }
71
65
  $RPUSH_CONFIG_PATH = default_config_path # rubocop:disable Style/GlobalVars
72
66
  Rails::Generators.invoke('rpush_config')
73
67
 
@@ -76,7 +70,7 @@ module Rpush
76
70
  unless options.key?('active_record')
77
71
  has_answer = false
78
72
  until has_answer
79
- STDOUT.write "\n* #{green('Install ActiveRecord migrations?')} [y/n]: "
73
+ STDOUT.write "\n* #{ANSI.green { 'Install ActiveRecord migrations?' }} [y/n]: "
80
74
  STDOUT.flush
81
75
  answer = STDIN.gets.chomp.downcase
82
76
  has_answer = %w(y n).include?(answer)
@@ -87,7 +81,7 @@ module Rpush
87
81
 
88
82
  Rails::Generators.invoke('rpush_migration', ['--force']) if install_migrations
89
83
 
90
- puts "\n* #{green('Next steps:')}"
84
+ puts "\n* #{ANSI.green { 'Next steps:' }}"
91
85
  puts " - Run 'db:migrate'." if install_migrations
92
86
  puts " - Review and update your configuration in #{default_config_path}."
93
87
  puts " - Create your first app, see https://github.com/rpush/rpush for examples."
@@ -96,16 +90,25 @@ module Rpush
96
90
 
97
91
  desc 'push', 'Deliver all pending notifications and then exit'
98
92
  def push
99
- underscore_option_names
100
- check_ruby_version
101
- configure_rpush
93
+ config_setup
102
94
  Rpush.config.foreground = true
103
95
 
104
96
  Rpush.push
105
97
  end
106
98
 
107
- private
99
+ desc 'version', 'Print Rpush version'
100
+ def version
101
+ puts Rpush::VERSION
102
+ end
108
103
 
104
+ private
105
+
106
+ def config_setup
107
+ underscore_option_names
108
+ check_ruby_version
109
+ configure_rpush
110
+ end
111
+
109
112
  def configure_rpush
110
113
  load_rails_environment || load_standalone
111
114
  end
@@ -117,7 +120,7 @@ module Rpush
117
120
  ENV['RAILS_ENV'] = options['rails_env']
118
121
  load 'config/environment.rb'
119
122
  Rpush.config.update(options)
120
- puts green('✔')
123
+ puts ANSI.green { '✔' }
121
124
 
122
125
  return true
123
126
  end
@@ -127,7 +130,7 @@ module Rpush
127
130
 
128
131
  def load_standalone
129
132
  if !File.exist?(options[:config])
130
- STDERR.puts(red('ERROR: ') + "#{options[:config]} does not exist. Please run 'rpush init' to generate it or specify the --config option.")
133
+ STDERR.puts(ANSI.red { 'ERROR: ' } + "#{options[:config]} does not exist. Please run 'rpush init' to generate it or specify the --config option.")
131
134
  exit 1
132
135
  else
133
136
  load options[:config]
@@ -146,12 +149,12 @@ module Rpush
146
149
  def ensure_pid_file_set
147
150
  return unless Rpush.config.pid_file.blank?
148
151
 
149
- STDERR.puts(red('ERROR: ') + 'config.pid_file is not set.')
152
+ STDERR.puts(ANSI.red { 'ERROR: ' } + 'config.pid_file is not set.')
150
153
  exit 1
151
154
  end
152
155
 
153
156
  def check_ruby_version
154
- STDERR.puts(yellow('WARNING: ') + "You are using an old and unsupported version of Ruby.") if RUBY_VERSION <= '1.9.3' && RUBY_ENGINE == 'ruby'
157
+ STDERR.puts(ANSI.yellow { 'WARNING: ' } + "You are using an old and unsupported version of Ruby.") if RUBY_VERSION <= '1.9.3' && RUBY_ENGINE == 'ruby'
155
158
  end
156
159
 
157
160
  def underscore_option_names
@@ -25,7 +25,7 @@ module Rpush
25
25
  pkey = OpenSSL::PKey::RSA.new(certificate, password)
26
26
  result = x509 && pkey
27
27
  rescue OpenSSL::OpenSSLError
28
- errors.add :certificate, 'Certificate value must contain a certificate and a private key.'
28
+ errors.add :certificate, 'value must contain a certificate and a private key.'
29
29
  end
30
30
  end
31
31
  result
@@ -38,7 +38,7 @@ module Rpush
38
38
  self.data = (data || {}).merge(CONTENT_AVAILABLE_KEY => true)
39
39
  end
40
40
 
41
- def as_json # rubocop:disable Metrics/PerceivedComplexity
41
+ def as_json # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
42
42
  json = ActiveSupport::OrderedHash.new
43
43
 
44
44
  if data && data.key?(MDM_KEY)
@@ -64,7 +64,7 @@ module Rpush
64
64
  json
65
65
  end
66
66
 
67
- def to_binary(options = {})
67
+ def to_binary(options = {}) # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
68
68
  frame_payload = payload
69
69
  frame_id = options[:for_validation] ? 0 : id
70
70
  frame = ""
@@ -7,7 +7,13 @@ module Rpush
7
7
  base.instance_eval do
8
8
  validates :uri, presence: true
9
9
  validates :uri, format: { with: %r{https?://[\S]+} }
10
- validates :alert, presence: true
10
+ validates :data, presence: true
11
+ end
12
+ def alert=(value)
13
+ return unless value
14
+ data = self.data || {}
15
+ data['title'] = value
16
+ self.data = data
11
17
  end
12
18
  end
13
19
  end
@@ -8,37 +8,24 @@ module Rpush
8
8
  def self.configure
9
9
  if block_given?
10
10
  yield config
11
- initialize_client
11
+ config.initialize_client
12
12
  end
13
13
  end
14
14
 
15
- def self.initialize_client
16
- return if @client_initialized
17
- require "rpush/client/#{config.client}"
18
- client_module = Rpush::Client.const_get(config.client.to_s.camelize)
19
- Rpush.send(:include, client_module)
20
-
21
- [:Apns, :Gcm, :Wpns, :Adm].each do |service|
22
- Rpush.const_set(service, client_module.const_get(service))
23
- end
24
-
25
- @client_initialized = true
26
- end
15
+ CURRENT_ATTRS = [:push_poll, :feedback_poll, :embedded, :pid_file, :batch_size,
16
+ :push, :client, :logger, :log_file, :foreground, :log_level, :plugin]
17
+ DEPRECATED_ATTRS = [:log_dir]
18
+ CONFIG_ATTRS = CURRENT_ATTRS + DEPRECATED_ATTRS
27
19
 
28
- CONFIG_ATTRS = [:push_poll, :feedback_poll, :embedded, :pid_file, :batch_size,
29
- :push, :client, :logger, :log_file, :foreground, :log_level,
30
- # Deprecated
31
- :log_dir]
32
-
33
- class ConfigurationWithoutDefaults < Struct.new(*CONFIG_ATTRS)
34
- end
20
+ class ConfigurationError < StandardError; end
21
+ class ConfigurationWithoutDefaults < Struct.new(*CONFIG_ATTRS); end
35
22
 
36
23
  class Configuration < Struct.new(*CONFIG_ATTRS)
37
24
  include Deprecatable
38
25
 
39
26
  deprecated(:log_dir=, '2.3.0', 'Please use log_file instead.')
40
27
 
41
- delegate :redis_options, :redis_options=, to: :Modis
28
+ delegate :redis_options, to: '::Modis'
42
29
 
43
30
  def initialize
44
31
  super
@@ -72,19 +59,42 @@ module Rpush
72
59
  super(logger)
73
60
  end
74
61
 
62
+ def client=(client)
63
+ super
64
+ initialize_client
65
+ end
66
+
67
+ def redis_options=(options)
68
+ Modis.redis_options = options if client == :redis
69
+ end
70
+
75
71
  def set_defaults
76
72
  self.push_poll = 2
77
73
  self.feedback_poll = 60
78
74
  self.batch_size = 100
79
- self.client = :active_record
80
75
  self.logger = nil
81
76
  self.log_file = 'log/rpush.log'
82
77
  self.pid_file = 'tmp/rpush.pid'
83
78
  self.log_level = (defined?(Rails) && Rails.logger) ? Rails.logger.level : ::Logger::Severity::INFO
79
+ self.plugin = OpenStruct.new
84
80
 
85
81
  # Internal options.
86
82
  self.embedded = false
87
83
  self.push = false
88
84
  end
85
+
86
+ def initialize_client
87
+ return if @client_initialized
88
+ raise ConfigurationError, 'Rpush.config.client is not set.' unless client
89
+ require "rpush/client/#{client}"
90
+ client_module = Rpush::Client.const_get(client.to_s.camelize)
91
+ Rpush.send(:include, client_module)
92
+
93
+ [:Apns, :Gcm, :Wpns, :Adm].each do |service|
94
+ Rpush.const_set(service, client_module.const_get(service))
95
+ end
96
+
97
+ @client_initialized = true
98
+ end
89
99
  end
90
100
  end
@@ -8,7 +8,6 @@ require 'net/http/persistent'
8
8
 
9
9
  require 'rpush/daemon/errors'
10
10
  require 'rpush/daemon/constants'
11
- require 'rpush/daemon/reflectable'
12
11
  require 'rpush/daemon/loggable'
13
12
  require 'rpush/daemon/string_helpers'
14
13
  require 'rpush/daemon/interruptible_sleep'
@@ -48,17 +47,15 @@ require 'rpush/daemon/adm'
48
47
 
49
48
  module Rpush
50
49
  module Daemon
51
- extend Term::ANSIColor
52
-
53
50
  class << self
54
51
  attr_accessor :store
55
52
  end
56
53
 
57
54
  def self.start
58
55
  Process.daemon if daemonize?
59
- SignalHandler.start
60
- initialize_store
61
56
  write_pid_file
57
+ SignalHandler.start
58
+ common_init
62
59
  Synchronizer.sync
63
60
 
64
61
  # No further store connections will be made from this thread.
@@ -87,7 +84,7 @@ module Rpush
87
84
  Feeder.stop
88
85
  AppRunner.stop
89
86
  delete_pid_file
90
- puts green('✔') if Rpush.config.foreground
87
+ puts ANSI.green { '✔' } if Rpush.config.foreground
91
88
  end
92
89
  end
93
90
 
@@ -97,7 +94,14 @@ module Rpush
97
94
  @shutdown_lock
98
95
  end
99
96
 
100
- def self.initialize_store
97
+ def self.common_init
98
+ init_store
99
+ init_plugins
100
+ end
101
+
102
+ protected
103
+
104
+ def self.init_store
101
105
  return if store
102
106
  begin
103
107
  name = Rpush.config.client.to_s
@@ -110,7 +114,12 @@ module Rpush
110
114
  end
111
115
  end
112
116
 
113
- protected
117
+ def self.init_plugins
118
+ Rpush.plugins.each do |name, plugin|
119
+ plugin.init_block.call
120
+ Rpush.logger.info("[plugin:#{name}] Loaded.")
121
+ end
122
+ end
114
123
 
115
124
  def self.daemonize?
116
125
  !(Rpush.config.push || Rpush.config.foreground || Rpush.config.embedded || Rpush.jruby?)
@@ -136,7 +145,7 @@ module Rpush
136
145
  if Rpush::Daemon::AppRunner.app_ids.count == 0
137
146
  puts <<-EOS
138
147
 
139
- * #{green('Is this your first time using Rpush?')}
148
+ * #{ANSI.green { 'Is this your first time using Rpush?' }}
140
149
  You need to create an App before you can start using Rpush.
141
150
  Please refer to the documentation at https://github.com/rpush/rpush
142
151