rpush 1.0.0-java → 2.0.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (201) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/README.md +37 -22
  4. data/bin/rpush +13 -4
  5. data/lib/generators/rpush_generator.rb +2 -0
  6. data/lib/generators/templates/add_adm.rb +5 -5
  7. data/lib/generators/templates/add_alert_is_json_to_rapns_notifications.rb +1 -1
  8. data/lib/generators/templates/add_app_to_rapns.rb +2 -2
  9. data/lib/generators/templates/add_fail_after_to_rpush_notifications.rb +1 -1
  10. data/lib/generators/templates/add_gcm.rb +32 -32
  11. data/lib/generators/templates/add_rpush.rb +67 -67
  12. data/lib/generators/templates/add_wpns.rb +2 -2
  13. data/lib/generators/templates/create_rapns_apps.rb +5 -5
  14. data/lib/generators/templates/create_rapns_feedback.rb +2 -2
  15. data/lib/generators/templates/create_rapns_notifications.rb +15 -15
  16. data/lib/generators/templates/rpush.rb +28 -7
  17. data/lib/generators/templates/rpush_2_0_0_updates.rb +42 -0
  18. data/lib/rpush/client/active_model/adm/app.rb +23 -0
  19. data/lib/rpush/client/active_model/adm/data_validator.rb +14 -0
  20. data/lib/rpush/client/active_model/adm/notification.rb +28 -0
  21. data/lib/rpush/client/active_model/apns/app.rb +37 -0
  22. data/lib/rpush/client/active_model/apns/binary_notification_validator.rb +16 -0
  23. data/lib/rpush/client/active_model/apns/device_token_format_validator.rb +14 -0
  24. data/lib/rpush/client/active_model/apns/notification.rb +90 -0
  25. data/lib/rpush/client/active_model/gcm/app.rb +19 -0
  26. data/lib/rpush/client/active_model/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +14 -0
  27. data/lib/rpush/client/active_model/gcm/notification.rb +31 -0
  28. data/lib/rpush/client/active_model/notification.rb +26 -0
  29. data/lib/rpush/client/active_model/payload_data_size_validator.rb +13 -0
  30. data/lib/rpush/client/active_model/registration_ids_count_validator.rb +13 -0
  31. data/lib/rpush/client/active_model/wpns/app.rb +13 -0
  32. data/lib/rpush/client/active_model/wpns/notification.rb +17 -0
  33. data/lib/rpush/client/active_model.rb +21 -0
  34. data/lib/rpush/client/active_record/adm/app.rb +11 -0
  35. data/lib/rpush/client/active_record/adm/notification.rb +11 -0
  36. data/lib/rpush/client/active_record/apns/app.rb +11 -0
  37. data/lib/rpush/client/active_record/apns/feedback.rb +22 -0
  38. data/lib/rpush/client/active_record/apns/notification.rb +46 -0
  39. data/lib/rpush/client/active_record/app.rb +17 -0
  40. data/lib/rpush/client/active_record/gcm/app.rb +11 -0
  41. data/lib/rpush/client/active_record/gcm/notification.rb +11 -0
  42. data/lib/rpush/client/active_record/notification.rb +38 -0
  43. data/lib/rpush/client/active_record/wpns/app.rb +11 -0
  44. data/lib/rpush/client/active_record/wpns/notification.rb +11 -0
  45. data/lib/rpush/client/active_record.rb +19 -0
  46. data/lib/rpush/client/redis/adm/app.rb +14 -0
  47. data/lib/rpush/client/redis/adm/notification.rb +11 -0
  48. data/lib/rpush/client/redis/apns/app.rb +11 -0
  49. data/lib/rpush/client/redis/apns/feedback.rb +20 -0
  50. data/lib/rpush/client/redis/apns/notification.rb +11 -0
  51. data/lib/rpush/client/redis/app.rb +24 -0
  52. data/lib/rpush/client/redis/gcm/app.rb +11 -0
  53. data/lib/rpush/client/redis/gcm/notification.rb +11 -0
  54. data/lib/rpush/client/redis/notification.rb +68 -0
  55. data/lib/rpush/client/redis/wpns/app.rb +11 -0
  56. data/lib/rpush/client/redis/wpns/notification.rb +11 -0
  57. data/lib/rpush/client/redis.rb +35 -0
  58. data/lib/rpush/configuration.rb +27 -6
  59. data/lib/rpush/daemon/adm/delivery.rb +56 -55
  60. data/lib/rpush/daemon/apns/delivery.rb +20 -44
  61. data/lib/rpush/daemon/apns/feedback_receiver.rb +11 -8
  62. data/lib/rpush/daemon/apns.rb +6 -5
  63. data/lib/rpush/daemon/app_runner.rb +103 -99
  64. data/lib/rpush/daemon/batch.rb +54 -40
  65. data/lib/rpush/daemon/delivery.rb +13 -3
  66. data/lib/rpush/daemon/delivery_error.rb +10 -2
  67. data/lib/rpush/daemon/dispatcher/apns_tcp.rb +114 -0
  68. data/lib/rpush/daemon/dispatcher/http.rb +3 -3
  69. data/lib/rpush/daemon/dispatcher/tcp.rb +3 -3
  70. data/lib/rpush/daemon/dispatcher_loop.rb +37 -23
  71. data/lib/rpush/daemon/errors.rb +18 -0
  72. data/lib/rpush/daemon/feeder.rb +28 -39
  73. data/lib/rpush/daemon/gcm/delivery.rb +19 -20
  74. data/lib/rpush/daemon/interruptible_sleep.rb +26 -45
  75. data/lib/rpush/daemon/loggable.rb +2 -4
  76. data/lib/rpush/daemon/proc_title.rb +16 -0
  77. data/lib/rpush/daemon/queue_payload.rb +12 -0
  78. data/lib/rpush/daemon/reflectable.rb +3 -5
  79. data/lib/rpush/daemon/retry_header_parser.rb +6 -6
  80. data/lib/rpush/daemon/retryable_error.rb +2 -0
  81. data/lib/rpush/daemon/ring_buffer.rb +16 -0
  82. data/lib/rpush/daemon/service_config_methods.rb +23 -7
  83. data/lib/rpush/daemon/signal_handler.rb +56 -0
  84. data/lib/rpush/daemon/store/active_record/reconnectable.rb +21 -17
  85. data/lib/rpush/daemon/store/active_record.rb +71 -38
  86. data/lib/rpush/daemon/store/interface.rb +19 -0
  87. data/lib/rpush/daemon/store/redis.rb +149 -0
  88. data/lib/rpush/daemon/string_helpers.rb +15 -0
  89. data/lib/rpush/daemon/synchronizer.rb +60 -0
  90. data/lib/rpush/daemon/tcp_connection.rb +6 -11
  91. data/lib/rpush/daemon/wpns/delivery.rb +21 -30
  92. data/lib/rpush/daemon.rb +40 -60
  93. data/lib/rpush/deprecatable.rb +4 -3
  94. data/lib/rpush/deprecation.rb +7 -10
  95. data/lib/rpush/embed.rb +8 -3
  96. data/lib/rpush/logger.rb +11 -15
  97. data/lib/rpush/push.rb +1 -2
  98. data/lib/rpush/reflection.rb +8 -12
  99. data/lib/rpush/version.rb +1 -1
  100. data/lib/rpush.rb +5 -29
  101. data/lib/tasks/quality.rake +35 -0
  102. data/lib/tasks/test.rake +1 -5
  103. data/spec/.rubocop.yml +4 -0
  104. data/spec/functional/adm_spec.rb +3 -6
  105. data/spec/functional/apns_spec.rb +117 -24
  106. data/spec/functional/embed_spec.rb +20 -20
  107. data/spec/functional/gcm_spec.rb +4 -7
  108. data/spec/functional/new_app_spec.rb +59 -0
  109. data/spec/functional/retry_spec.rb +46 -0
  110. data/spec/functional/synchronization_spec.rb +68 -0
  111. data/spec/functional/wpns_spec.rb +3 -6
  112. data/spec/functional_spec_helper.rb +26 -0
  113. data/spec/integration/rpush_spec.rb +13 -0
  114. data/spec/integration/support/gcm_success_response.json +1 -0
  115. data/spec/spec_helper.rb +60 -0
  116. data/spec/support/active_record_setup.rb +48 -0
  117. data/{config → spec/support/config}/database.yml +0 -0
  118. data/spec/support/install.sh +43 -7
  119. data/spec/support/simplecov_helper.rb +9 -5
  120. data/spec/support/simplecov_quality_formatter.rb +10 -6
  121. data/spec/unit/apns_feedback_spec.rb +3 -3
  122. data/spec/unit/{adm → client/active_record/adm}/app_spec.rb +3 -3
  123. data/spec/unit/{adm → client/active_record/adm}/notification_spec.rb +5 -7
  124. data/spec/unit/client/active_record/apns/app_spec.rb +29 -0
  125. data/spec/unit/client/active_record/apns/feedback_spec.rb +9 -0
  126. data/spec/unit/client/active_record/apns/notification_spec.rb +231 -0
  127. data/spec/unit/client/active_record/app_spec.rb +30 -0
  128. data/spec/unit/client/active_record/gcm/app_spec.rb +4 -0
  129. data/spec/unit/{gcm → client/active_record/gcm}/notification_spec.rb +5 -7
  130. data/spec/unit/client/active_record/notification_spec.rb +21 -0
  131. data/spec/unit/client/active_record/wpns/app_spec.rb +4 -0
  132. data/spec/unit/client/active_record/wpns/notification_spec.rb +21 -0
  133. data/spec/unit/configuration_spec.rb +12 -5
  134. data/spec/unit/daemon/adm/delivery_spec.rb +66 -55
  135. data/spec/unit/daemon/apns/certificate_expired_error_spec.rb +3 -3
  136. data/spec/unit/daemon/apns/delivery_spec.rb +90 -83
  137. data/spec/unit/daemon/apns/feedback_receiver_spec.rb +22 -17
  138. data/spec/unit/daemon/app_runner_spec.rb +78 -186
  139. data/spec/unit/daemon/batch_spec.rb +52 -115
  140. data/spec/unit/daemon/delivery_spec.rb +15 -1
  141. data/spec/unit/daemon/dispatcher/http_spec.rb +3 -2
  142. data/spec/unit/daemon/dispatcher/tcp_spec.rb +10 -9
  143. data/spec/unit/daemon/dispatcher_loop_spec.rb +6 -24
  144. data/spec/unit/daemon/feeder_spec.rb +38 -39
  145. data/spec/unit/daemon/gcm/delivery_spec.rb +122 -101
  146. data/spec/unit/daemon/reflectable_spec.rb +2 -2
  147. data/spec/unit/daemon/retryable_error_spec.rb +1 -1
  148. data/spec/unit/daemon/service_config_methods_spec.rb +6 -3
  149. data/spec/unit/daemon/signal_handler_spec.rb +95 -0
  150. data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +48 -27
  151. data/spec/unit/daemon/store/active_record_spec.rb +38 -47
  152. data/spec/unit/daemon/tcp_connection_spec.rb +22 -34
  153. data/spec/unit/daemon/wpns/delivery_spec.rb +58 -50
  154. data/spec/unit/daemon_spec.rb +48 -82
  155. data/spec/unit/embed_spec.rb +6 -4
  156. data/spec/unit/logger_spec.rb +35 -43
  157. data/spec/unit/notification_shared.rb +9 -79
  158. data/spec/unit/push_spec.rb +6 -10
  159. data/spec/unit/reflection_spec.rb +25 -25
  160. data/spec/unit/rpush_spec.rb +1 -2
  161. data/spec/unit_spec_helper.rb +33 -88
  162. metadata +126 -76
  163. data/lib/rpush/TODO +0 -3
  164. data/lib/rpush/adm/app.rb +0 -15
  165. data/lib/rpush/adm/data_validator.rb +0 -11
  166. data/lib/rpush/adm/notification.rb +0 -29
  167. data/lib/rpush/apns/app.rb +0 -29
  168. data/lib/rpush/apns/binary_notification_validator.rb +0 -12
  169. data/lib/rpush/apns/device_token_format_validator.rb +0 -12
  170. data/lib/rpush/apns/feedback.rb +0 -16
  171. data/lib/rpush/apns/notification.rb +0 -84
  172. data/lib/rpush/app.rb +0 -18
  173. data/lib/rpush/daemon/apns/certificate_expired_error.rb +0 -20
  174. data/lib/rpush/daemon/apns/disconnection_error.rb +0 -20
  175. data/lib/rpush/daemon/dispatcher_loop_collection.rb +0 -33
  176. data/lib/rpush/daemon/too_many_requests_error.rb +0 -20
  177. data/lib/rpush/gcm/app.rb +0 -11
  178. data/lib/rpush/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +0 -11
  179. data/lib/rpush/gcm/notification.rb +0 -30
  180. data/lib/rpush/notification.rb +0 -69
  181. data/lib/rpush/notifier.rb +0 -52
  182. data/lib/rpush/payload_data_size_validator.rb +0 -10
  183. data/lib/rpush/railtie.rb +0 -11
  184. data/lib/rpush/registration_ids_count_validator.rb +0 -10
  185. data/lib/rpush/wpns/app.rb +0 -9
  186. data/lib/rpush/wpns/notification.rb +0 -26
  187. data/lib/tasks/cane.rake +0 -18
  188. data/lib/tasks/rpush.rake +0 -16
  189. data/spec/unit/apns/app_spec.rb +0 -29
  190. data/spec/unit/apns/feedback_spec.rb +0 -9
  191. data/spec/unit/apns/notification_spec.rb +0 -208
  192. data/spec/unit/app_spec.rb +0 -30
  193. data/spec/unit/daemon/apns/disconnection_error_spec.rb +0 -18
  194. data/spec/unit/daemon/dispatcher_loop_collection_spec.rb +0 -37
  195. data/spec/unit/daemon/interruptible_sleep_spec.rb +0 -68
  196. data/spec/unit/daemon/too_many_requests_error_spec.rb +0 -14
  197. data/spec/unit/gcm/app_spec.rb +0 -4
  198. data/spec/unit/notification_spec.rb +0 -15
  199. data/spec/unit/notifier_spec.rb +0 -49
  200. data/spec/unit/wpns/app_spec.rb +0 -4
  201. data/spec/unit/wpns/notification_spec.rb +0 -30
@@ -0,0 +1,149 @@
1
+ module Rpush
2
+ module Daemon
3
+ module Store
4
+ class Redis
5
+ DEFAULT_MARK_OPTIONS = { persist: true }
6
+
7
+ def app(app_id)
8
+ Rpush::Client::Redis::App.find(app_id)
9
+ end
10
+
11
+ def all_apps
12
+ Rpush::Client::Redis::App.all
13
+ end
14
+
15
+ def deliverable_notifications(limit)
16
+ retryable_ids = retryable_notification_ids
17
+ limit -= retryable_ids.size
18
+ pending_ids = limit > 0 ? pending_notification_ids(limit) : []
19
+ ids = retryable_ids + pending_ids
20
+ ids.map { |id| Rpush::Client::Redis::Notification.find(id) }
21
+ end
22
+
23
+ def mark_delivered(notification, time, opts = {})
24
+ opts = DEFAULT_MARK_OPTIONS.dup.merge(opts)
25
+ notification.delivered = true
26
+ notification.delivered_at = time
27
+ notification.save!(validate: false) if opts[:persist]
28
+ end
29
+
30
+ def mark_batch_delivered(notifications)
31
+ now = Time.now
32
+ notifications.each { |n| mark_delivered(n, now) }
33
+ end
34
+
35
+ def mark_failed(notification, code, description, time, opts = {})
36
+ opts = DEFAULT_MARK_OPTIONS.dup.merge(opts)
37
+ notification.delivered = false
38
+ notification.delivered_at = nil
39
+ notification.failed = true
40
+ notification.failed_at = time
41
+ notification.error_code = code
42
+ notification.error_description = description
43
+ notification.save!(validate: false) if opts[:persist]
44
+ end
45
+
46
+ def mark_batch_failed(notifications, code, description)
47
+ now = Time.now
48
+ notifications.each { |n| mark_failed(n, code, description, now) }
49
+ end
50
+
51
+ def mark_ids_failed(ids, code, description, time)
52
+ ids.each { |id| mark_failed(Rpush::Client::Redis::Apns::Notification.find(id), code, description, time) }
53
+ end
54
+
55
+ def mark_retryable(notification, deliver_after, opts = {})
56
+ opts = DEFAULT_MARK_OPTIONS.dup.merge(opts)
57
+ notification.delivered = false
58
+ notification.delivered_at = nil
59
+ notification.failed = false
60
+ notification.failed_at = nil
61
+ notification.retries += 1
62
+ notification.deliver_after = deliver_after
63
+
64
+ return unless opts[:persist]
65
+
66
+ notification.save!(validate: false)
67
+ namespace = Rpush::Client::Redis::Notification.absolute_retryable_namespace
68
+ Modis.with_connection do |redis|
69
+ redis.zadd(namespace, deliver_after.to_i, notification.id)
70
+ end
71
+ end
72
+
73
+ def mark_batch_retryable(notifications, deliver_after)
74
+ notifications.each { |n| mark_retryable(n, deliver_after) }
75
+ end
76
+
77
+ def mark_ids_retryable(ids, deliver_after)
78
+ ids.each { |id| mark_retryable(Rpush::Client::Redis::Apns::Notification.find(id), deliver_after) }
79
+ end
80
+
81
+ def create_apns_feedback(failed_at, device_token, app)
82
+ Rpush::Client::Redis::Apns::Feedback.create!(failed_at: failed_at, device_token: device_token, app_id: app.id)
83
+ end
84
+
85
+ def create_gcm_notification(attrs, data, registration_ids, deliver_after, app) # rubocop:disable ParameterLists
86
+ notification = Rpush::Client::Redis::Gcm::Notification.new
87
+ create_gcm_like_notification(notification, attrs, data, registration_ids, deliver_after, app)
88
+ end
89
+
90
+ def create_adm_notification(attrs, data, registration_ids, deliver_after, app) # rubocop:disable ParameterLists
91
+ notification = Rpush::Client::Redis::Adm::Notification.new
92
+ create_gcm_like_notification(notification, attrs, data, registration_ids, deliver_after, app)
93
+ end
94
+
95
+ def update_app(app)
96
+ app.save!
97
+ end
98
+
99
+ def update_notification(notification)
100
+ notification.save!
101
+ end
102
+
103
+ def release_connection
104
+ end
105
+
106
+ private
107
+
108
+ def create_gcm_like_notification(notification, attrs, data, registration_ids, deliver_after, app) # rubocop:disable ParameterLists
109
+ notification.assign_attributes(attrs)
110
+ notification.data = data
111
+ notification.registration_ids = registration_ids
112
+ notification.deliver_after = deliver_after
113
+ notification.app = app
114
+ notification.save!
115
+ notification
116
+ end
117
+
118
+ def retryable_notification_ids
119
+ retryable_ns = Rpush::Client::Redis::Notification.absolute_retryable_namespace
120
+
121
+ Modis.with_connection do |redis|
122
+ retryable_results = redis.multi do
123
+ now = Time.now.to_i
124
+ redis.zrangebyscore(retryable_ns, 0, now)
125
+ redis.zremrangebyscore(retryable_ns, 0, now)
126
+ end
127
+
128
+ retryable_results.first
129
+ end
130
+ end
131
+
132
+ def pending_notification_ids(limit)
133
+ pending_ns = Rpush::Client::Redis::Notification.absolute_pending_namespace
134
+
135
+ Modis.with_connection do |redis|
136
+ pending_results = redis.multi do
137
+ redis.zrange(pending_ns, 0, limit)
138
+ redis.zremrangebyrank(pending_ns, 0, limit)
139
+ end
140
+
141
+ pending_results.first
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
148
+
149
+ Rpush::Daemon::Store::Interface.check(Rpush::Daemon::Store::Redis)
@@ -0,0 +1,15 @@
1
+ module Rpush
2
+ module Daemon
3
+ module StringHelpers
4
+ def pluralize(count, singular, plural = nil)
5
+ if count == 1 || count =~ /^1(\.0+)?$/
6
+ word = singular
7
+ else
8
+ word = plural || singular.pluralize
9
+ end
10
+
11
+ "#{count || 0} #{word}"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,60 @@
1
+ module Rpush
2
+ module Daemon
3
+ class Synchronizer
4
+ extend Loggable
5
+ extend StringHelpers
6
+
7
+ def self.sync
8
+ apps = Rpush::Daemon.store.all_apps
9
+ apps.each { |app| sync_app(app) }
10
+ removed = AppRunner.app_ids - apps.map(&:id)
11
+ removed.each { |app_id| AppRunner.stop_app(app_id) }
12
+
13
+ ProcTitle.update
14
+ end
15
+
16
+ def self.sync_app(app)
17
+ if !AppRunner.app_running?(app)
18
+ AppRunner.start_app(app)
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)
29
+ end
30
+ end
31
+
32
+ def self.sync_dispatcher_count(app)
33
+ num_dispatchers = AppRunner.num_dispatchers_for_app(app)
34
+ diff = num_dispatchers - app.connections
35
+ return if diff == 0
36
+
37
+ if diff > 0
38
+ AppRunner.decrement_dispatchers(app, diff)
39
+ start_stop_str = "Stopped"
40
+ else
41
+ AppRunner.increment_dispatchers(app, diff.abs)
42
+ start_stop_str = "Started"
43
+ end
44
+
45
+ num_dispatchers = AppRunner.num_dispatchers_for_app(app)
46
+ log_info("[#{app.name}] #{start_stop_str} #{pluralize(diff.abs, 'dispatcher')}. #{num_dispatchers} running.")
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
58
+ end
59
+ end
60
+ end
@@ -27,11 +27,9 @@ module Rpush
27
27
  end
28
28
 
29
29
  def close
30
- begin
31
- @ssl_socket.close if @ssl_socket
32
- @tcp_socket.close if @tcp_socket
33
- rescue IOError
34
- end
30
+ @ssl_socket.close if @ssl_socket
31
+ @tcp_socket.close if @tcp_socket
32
+ rescue IOError # rubocop:disable HandleExceptions
35
33
  end
36
34
 
37
35
  def read(num_bytes)
@@ -50,11 +48,10 @@ module Rpush
50
48
  begin
51
49
  write_data(data)
52
50
  rescue Errno::EPIPE, Errno::ETIMEDOUT, OpenSSL::SSL::SSLError, IOError => e
53
- retry_count += 1;
51
+ retry_count += 1
54
52
 
55
53
  if retry_count == 1
56
54
  log_error("Lost connection to #{@host}:#{@port} (#{e.class.name}), reconnecting...")
57
- reflect(:apns_connection_lost, @app, e) # deprecated
58
55
  reflect(:tcp_connection_lost, @app, e)
59
56
  end
60
57
 
@@ -63,7 +60,7 @@ module Rpush
63
60
  sleep 1
64
61
  retry
65
62
  else
66
- raise TcpConnectionError, "#{@app.name} tried #{retry_count-1} times to reconnect but failed (#{e.class.name})."
63
+ raise TcpConnectionError, "#{@app.name} tried #{retry_count - 1} times to reconnect but failed (#{e.class.name})."
67
64
  end
68
65
  end
69
66
  end
@@ -110,7 +107,6 @@ module Rpush
110
107
  ssl_socket = OpenSSL::SSL::SSLSocket.new(tcp_socket, @ssl_context)
111
108
  ssl_socket.sync = true
112
109
  ssl_socket.connect
113
- log_info("Connected to #{@host}:#{@port}")
114
110
  [tcp_socket, ssl_socket]
115
111
  end
116
112
 
@@ -118,10 +114,9 @@ module Rpush
118
114
  cert = @ssl_context.cert
119
115
  if certificate_expired?
120
116
  log_error(certificate_msg('expired'))
121
- raise Rpush::Apns::CertificateExpiredError.new(@app, cert.not_after)
117
+ fail Rpush::CertificateExpiredError.new(@app, cert.not_after)
122
118
  elsif certificate_expires_soon?
123
119
  log_warn(certificate_msg('will expire'))
124
- reflect(:apns_certificate_will_expire, @app, cert.not_after) # deprecated
125
120
  reflect(:ssl_certificate_will_expire, @app, cert.not_after)
126
121
  end
127
122
  end
@@ -1,10 +1,8 @@
1
1
  module Rpush
2
2
  module Daemon
3
3
  module Wpns
4
-
5
4
  # http://msdn.microsoft.com/en-us/library/windowsphone/develop/ff941100%28v=vs.105%29.aspx
6
5
  class Delivery < Rpush::Daemon::Delivery
7
-
8
6
  FAILURE_MESSAGES = {
9
7
  400 => 'Bad XML or malformed notification URI.',
10
8
  401 => 'Unauthorized to send a notification to this app.'
@@ -18,12 +16,12 @@ module Rpush
18
16
  end
19
17
 
20
18
  def perform
21
- begin
22
- handle_response(do_post)
23
- rescue Rpush::DeliveryError => error
24
- mark_failed(error.code, error.description)
25
- raise
26
- end
19
+ handle_response(do_post)
20
+ rescue StandardError => error
21
+ mark_failed(error)
22
+ raise
23
+ ensure
24
+ @batch.notification_processed
27
25
  end
28
26
 
29
27
  private
@@ -34,25 +32,21 @@ module Rpush
34
32
  when 200
35
33
  ok(response)
36
34
  when 406
37
- not_acceptable(response)
35
+ not_acceptable
38
36
  when 412
39
- precondition_failed(response)
37
+ precondition_failed
40
38
  when 503
41
- service_unavailable(response)
39
+ service_unavailable
42
40
  else
43
41
  handle_failure(code)
44
42
  end
45
43
  end
46
44
 
47
- def handle_failure(code, msg=nil)
45
+ def handle_failure(code, msg = nil)
48
46
  unless msg
49
- msg = if FAILURE_MESSAGES.key?(code)
50
- FAILURE_MESSAGES[code]
51
- else
52
- Rpush::Daemon::HTTP_STATUS_CODES[code]
53
- end
47
+ msg = FAILURE_MESSAGES.key?(code) ? FAILURE_MESSAGES[code] : Rpush::Daemon::HTTP_STATUS_CODES[code]
54
48
  end
55
- raise Rpush::DeliveryError.new(code, @notification.id, msg)
49
+ fail Rpush::DeliveryError.new(code, @notification.id, msg)
56
50
  end
57
51
 
58
52
  def ok(response)
@@ -62,22 +56,22 @@ module Rpush
62
56
  mark_delivered
63
57
  log_info("#{@notification.id} sent successfully")
64
58
  when ["QueueFull"]
65
- mark_retryable(@notification, Time.now + (60*10))
59
+ mark_retryable(@notification, Time.now + (60 * 10))
66
60
  log_warn("#{@notification.id} cannot be sent. The Queue is full.")
67
61
  when ["Suppressed"]
68
62
  handle_failure(200, "Notification was received but suppressed by the service.")
69
63
  end
70
64
  end
71
65
 
72
- def not_acceptable(response)
66
+ def not_acceptable
73
67
  retry_notification("Per-day throttling limit reached.")
74
68
  end
75
69
 
76
- def precondition_failed(response)
70
+ def precondition_failed
77
71
  retry_notification("Device unreachable.")
78
72
  end
79
73
 
80
- def service_unavailable(response)
74
+ def service_unavailable
81
75
  mark_retryable_exponential(@notification)
82
76
  log_warn("Service Unavailable. " + retry_message)
83
77
  end
@@ -87,20 +81,17 @@ module Rpush
87
81
  end
88
82
 
89
83
  def retry_notification(reason)
90
- deliver_after = Time.now + (60*60)
84
+ deliver_after = Time.now + (60 * 60)
91
85
  mark_retryable(@notification, deliver_after)
92
86
  log_warn("#{reason} " + retry_message)
93
87
  end
94
88
 
95
89
  def do_post
96
90
  body = notification_to_xml
97
- header = {
98
- "Content-Length" => body.length.to_s,
99
- "Content-Type" => "text/xml",
100
- "X-WindowsPhone-Target" => "toast",
101
- "X-NotificationClass" => '2'
102
- }
103
- post = Net::HTTP::Post.new(URI.parse(@notification.uri).path, initheader=header)
91
+ post = Net::HTTP::Post.new(URI.parse(@notification.uri).path, "Content-Length" => body.length.to_s,
92
+ "Content-Type" => "text/xml",
93
+ "X-WindowsPhone-Target" => "toast",
94
+ "X-NotificationClass" => '2')
104
95
  post.body = body
105
96
  @http.request(URI.parse(@notification.uri), post)
106
97
  end
data/lib/rpush/daemon.rb CHANGED
@@ -2,31 +2,36 @@ require 'thread'
2
2
  require 'socket'
3
3
  require 'pathname'
4
4
  require 'openssl'
5
-
6
5
  require 'net/http/persistent'
7
6
 
7
+ require 'rpush/daemon/errors'
8
8
  require 'rpush/daemon/constants'
9
9
  require 'rpush/daemon/reflectable'
10
10
  require 'rpush/daemon/loggable'
11
+ require 'rpush/daemon/string_helpers'
11
12
  require 'rpush/daemon/interruptible_sleep'
12
13
  require 'rpush/daemon/delivery_error'
13
14
  require 'rpush/daemon/retryable_error'
14
- require 'rpush/daemon/too_many_requests_error'
15
15
  require 'rpush/daemon/delivery'
16
16
  require 'rpush/daemon/feeder'
17
17
  require 'rpush/daemon/batch'
18
+ require 'rpush/daemon/queue_payload'
19
+ require 'rpush/daemon/synchronizer'
18
20
  require 'rpush/daemon/app_runner'
19
21
  require 'rpush/daemon/tcp_connection'
20
22
  require 'rpush/daemon/dispatcher_loop'
21
- require 'rpush/daemon/dispatcher_loop_collection'
22
23
  require 'rpush/daemon/dispatcher/http'
23
24
  require 'rpush/daemon/dispatcher/tcp'
25
+ require 'rpush/daemon/dispatcher/apns_tcp'
24
26
  require 'rpush/daemon/service_config_methods'
25
27
  require 'rpush/daemon/retry_header_parser'
28
+ require 'rpush/daemon/ring_buffer'
29
+ require 'rpush/daemon/signal_handler'
30
+ require 'rpush/daemon/proc_title'
31
+
32
+ require 'rpush/daemon/store/interface'
26
33
 
27
34
  require 'rpush/daemon/apns/delivery'
28
- require 'rpush/daemon/apns/disconnection_error'
29
- require 'rpush/daemon/apns/certificate_expired_error'
30
35
  require 'rpush/daemon/apns/feedback_receiver'
31
36
  require 'rpush/daemon/apns'
32
37
 
@@ -46,69 +51,59 @@ module Rpush
46
51
  end
47
52
 
48
53
  def self.start
49
- setup_signal_traps if trap_signals?
50
-
54
+ Process.daemon if daemonize?
55
+ SignalHandler.start
51
56
  initialize_store
52
- return unless store
57
+ write_pid_file
58
+ Synchronizer.sync
53
59
 
54
- if daemonize?
55
- daemonize
56
- store.after_daemonize
57
- end
60
+ # No further store connections will be made from this thread.
61
+ store.release_connection
58
62
 
59
- write_pid_file
60
- AppRunner.sync
63
+ # Blocking call, returns after Feeder.stop is called from another thread.
61
64
  Feeder.start
65
+
66
+ # Wait for shutdown to complete.
67
+ shutdown_lock.synchronize { true }
68
+ end
69
+
70
+ def self.shutdown
71
+ puts "\nShutting down..."
72
+
73
+ shutdown_lock.synchronize do
74
+ Feeder.stop
75
+ AppRunner.stop
76
+ delete_pid_file
77
+ end
62
78
  end
63
79
 
64
- def self.shutdown(quiet = false)
65
- puts "\nShutting down..." unless quiet
66
- Feeder.stop
67
- AppRunner.stop
68
- delete_pid_file
80
+ def self.shutdown_lock
81
+ return @shutdown_lock if @shutdown_lock
82
+ @shutdown_lock = Mutex.new
83
+ @shutdown_lock
69
84
  end
70
85
 
71
86
  def self.initialize_store
72
87
  return if store
73
88
  begin
74
- name = Rpush.config.store.to_s
89
+ name = Rpush.config.client.to_s
75
90
  require "rpush/daemon/store/#{name}"
76
91
  self.store = Rpush::Daemon::Store.const_get(name.camelcase).new
77
92
  rescue StandardError, LoadError => e
78
- Rpush.logger.error("Failed to load '#{Rpush.config.store}' storage backend.")
93
+ Rpush.logger.error("Failed to load '#{Rpush.config.client}' storage backend.")
79
94
  Rpush.logger.error(e)
95
+ exit 1
80
96
  end
81
97
  end
82
98
 
83
99
  protected
84
100
 
85
101
  def self.daemonize?
86
- !(Rpush.config.foreground || Rpush.config.embedded || Rpush.jruby?)
87
- end
88
-
89
- def self.trap_signals?
90
- !Rpush.config.embedded
91
- end
92
-
93
- def self.setup_signal_traps
94
- @shutting_down = false
95
-
96
- Signal.trap('SIGHUP') { AppRunner.sync }
97
- Signal.trap('SIGUSR2') { AppRunner.debug }
98
-
99
- ['SIGINT', 'SIGTERM'].each do |signal|
100
- Signal.trap(signal) { handle_shutdown_signal }
101
- end
102
- end
103
-
104
- def self.handle_shutdown_signal
105
- exit 1 if @shutting_down
106
- @shutting_down = true
107
- shutdown
102
+ !(Rpush.config.push || Rpush.config.foreground || Rpush.config.embedded || Rpush.jruby?)
108
103
  end
109
104
 
110
105
  def self.write_pid_file
111
- if !Rpush.config.pid_file.blank?
106
+ unless Rpush.config.pid_file.blank?
112
107
  begin
113
108
  File.open(Rpush.config.pid_file, 'w') { |f| f.puts Process.pid }
114
109
  rescue SystemCallError => e
@@ -119,22 +114,7 @@ module Rpush
119
114
 
120
115
  def self.delete_pid_file
121
116
  pid_file = Rpush.config.pid_file
122
- File.delete(pid_file) if !pid_file.blank? && File.exists?(pid_file)
123
- end
124
-
125
- # :nocov:
126
- def self.daemonize
127
- if RUBY_VERSION < "1.9"
128
- exit if fork
129
- Process.setsid
130
- exit if fork
131
- Dir.chdir "/"
132
- STDIN.reopen "/dev/null"
133
- STDOUT.reopen "/dev/null", "a"
134
- STDERR.reopen "/dev/null", "a"
135
- else
136
- Process.daemon
137
- end
117
+ File.delete(pid_file) if !pid_file.blank? && File.exist?(pid_file)
138
118
  end
139
119
  end
140
120
  end
@@ -5,16 +5,17 @@ module Rpush
5
5
  end
6
6
 
7
7
  module ClassMethods
8
- def deprecated(method_name, version, msg=nil)
8
+ def deprecated(method_name, version, msg = nil)
9
+ method_name_as_var = method_name.to_s.tr('=', '_setter_')
9
10
  instance_eval do
10
- alias_method "#{method_name}_without_warning", method_name
11
+ alias_method "#{method_name_as_var}_without_warning", method_name
11
12
  end
12
13
  warning = "#{method_name} is deprecated and will be removed from Rpush #{version}."
13
14
  warning << " #{msg}" if msg
14
15
  class_eval(<<-RUBY, __FILE__, __LINE__)
15
16
  def #{method_name}(*args, &blk)
16
17
  Rpush::Deprecation.warn(#{warning.inspect})
17
- #{method_name}_without_warning(*args, &blk)
18
+ #{method_name_as_var}_without_warning(*args, &blk)
18
19
  end
19
20
  RUBY
20
21
  end
@@ -1,13 +1,11 @@
1
1
  module Rpush
2
2
  class Deprecation
3
3
  def self.muted
4
- begin
5
- orig_val = Thread.current[:rpush_mute_deprecations]
6
- Thread.current[:rpush_mute_deprecations] = true
7
- yield
8
- ensure
9
- Thread.current[:rpush_mute_deprecations] = orig_val
10
- end
4
+ orig_val = Thread.current[:rpush_mute_deprecations]
5
+ Thread.current[:rpush_mute_deprecations] = true
6
+ yield
7
+ ensure
8
+ Thread.current[:rpush_mute_deprecations] = orig_val
11
9
  end
12
10
 
13
11
  def self.muted?
@@ -15,9 +13,8 @@ module Rpush
15
13
  end
16
14
 
17
15
  def self.warn(msg)
18
- unless Rpush::Deprecation.muted?
19
- STDERR.puts "DEPRECATION WARNING: #{msg}"
20
- end
16
+ return if Rpush::Deprecation.muted?
17
+ STDERR.puts "DEPRECATION WARNING: #{msg}"
21
18
  end
22
19
  end
23
20
  end
data/lib/rpush/embed.rb CHANGED
@@ -2,23 +2,28 @@ module Rpush
2
2
  def self.embed(options = {})
3
3
  Rpush.require_for_daemon
4
4
 
5
+ if @embed_thread
6
+ STDERR.puts 'Rpush.embed can only be run once inside this process.'
7
+ end
8
+
5
9
  config = Rpush::ConfigurationWithoutDefaults.new
6
10
  options.each { |k, v| config.send("#{k}=", v) }
7
11
  config.embedded = true
8
12
  Rpush.config.update(config)
9
- Rpush::Daemon.start
10
-
11
13
  Kernel.at_exit { shutdown }
14
+ @embed_thread = Thread.new { Rpush::Daemon.start }
12
15
  end
13
16
 
14
17
  def self.shutdown
15
18
  return unless Rpush.config.embedded
16
19
  Rpush::Daemon.shutdown
20
+ @embed_thread.join if @embed_thread
21
+ @embed_thread = nil
17
22
  end
18
23
 
19
24
  def self.sync
20
25
  return unless Rpush.config.embedded
21
- Rpush::Daemon::AppRunner.sync
26
+ Rpush::Daemon::Synchronizer.sync
22
27
  end
23
28
 
24
29
  def self.debug
data/lib/rpush/logger.rb CHANGED
@@ -1,19 +1,15 @@
1
1
  module Rpush
2
2
  class Logger
3
- def initialize(options)
4
- @options = options
5
-
6
- begin
7
- log_dir = File.join(Rails.root, 'log')
8
- FileUtils.mkdir_p(log_dir)
9
- log = File.open(File.join(log_dir, 'rpush.log'), 'a')
10
- log.sync = true
11
- setup_logger(log)
12
- rescue Errno::ENOENT, Errno::EPERM => e
13
- @logger = nil
14
- error(e)
15
- error('Logging disabled.')
16
- end
3
+ def initialize
4
+ log_dir = File.join(Rpush.config.log_dir, 'log')
5
+ FileUtils.mkdir_p(log_dir)
6
+ log = File.open(File.join(log_dir, 'rpush.log'), 'a')
7
+ log.sync = true
8
+ setup_logger(log)
9
+ rescue Errno::ENOENT, Errno::EPERM => e
10
+ @logger = nil
11
+ error(e)
12
+ error('Logging disabled.')
17
13
  end
18
14
 
19
15
  def info(msg)
@@ -53,7 +49,7 @@ module Rpush
53
49
 
54
50
  if io == STDERR
55
51
  io.puts formatted_msg
56
- elsif @options[:foreground]
52
+ elsif Rpush.config.foreground
57
53
  io.puts formatted_msg
58
54
  end
59
55