rpush 1.0.0-java → 2.0.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 (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