rpush_extended 3.2.5
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +365 -0
- data/LICENSE +7 -0
- data/README.md +393 -0
- data/bin/rpush +4 -0
- data/lib/generators/rpush_config_generator.rb +7 -0
- data/lib/generators/rpush_migration_generator.rb +66 -0
- data/lib/generators/templates/add_adm.rb +23 -0
- data/lib/generators/templates/add_alert_is_json_to_rapns_notifications.rb +9 -0
- data/lib/generators/templates/add_app_to_rapns.rb +11 -0
- data/lib/generators/templates/add_fail_after_to_rpush_notifications.rb +9 -0
- data/lib/generators/templates/add_gcm.rb +117 -0
- data/lib/generators/templates/add_rpush.rb +402 -0
- data/lib/generators/templates/add_wpns.rb +16 -0
- data/lib/generators/templates/create_rapns_apps.rb +16 -0
- data/lib/generators/templates/create_rapns_feedback.rb +25 -0
- data/lib/generators/templates/create_rapns_notifications.rb +36 -0
- data/lib/generators/templates/rename_rapns_to_rpush.rb +87 -0
- data/lib/generators/templates/rpush.rb +135 -0
- data/lib/generators/templates/rpush_2_0_0_updates.rb +79 -0
- data/lib/generators/templates/rpush_2_1_0_updates.rb +11 -0
- data/lib/generators/templates/rpush_2_6_0_updates.rb +10 -0
- data/lib/generators/templates/rpush_2_7_0_updates.rb +12 -0
- data/lib/generators/templates/rpush_3_0_0_updates.rb +11 -0
- data/lib/generators/templates/rpush_3_0_1_updates.rb +13 -0
- data/lib/generators/templates/rpush_3_1_0_add_pushy.rb +9 -0
- data/lib/generators/templates/rpush_3_1_1_updates.rb +15 -0
- data/lib/generators/templates/rpush_3_2_0_add_apns_p8.rb +15 -0
- data/lib/generators/templates/rpush_3_2_4_updates.rb +9 -0
- data/lib/generators/templates/rpush_3_3_0_updates.rb +9 -0
- data/lib/generators/templates/rpush_3_3_1_updates.rb +11 -0
- data/lib/rpush/apns_feedback.rb +17 -0
- data/lib/rpush/cli.rb +213 -0
- data/lib/rpush/client/active_model/adm/app.rb +23 -0
- data/lib/rpush/client/active_model/adm/data_validator.rb +14 -0
- data/lib/rpush/client/active_model/adm/notification.rb +28 -0
- data/lib/rpush/client/active_model/apns/app.rb +37 -0
- data/lib/rpush/client/active_model/apns/binary_notification_validator.rb +16 -0
- data/lib/rpush/client/active_model/apns/device_token_format_validator.rb +14 -0
- data/lib/rpush/client/active_model/apns/notification.rb +104 -0
- data/lib/rpush/client/active_model/apns2/app.rb +15 -0
- data/lib/rpush/client/active_model/apns2/notification.rb +9 -0
- data/lib/rpush/client/active_model/apnsp8/app.rb +23 -0
- data/lib/rpush/client/active_model/apnsp8/notification.rb +9 -0
- data/lib/rpush/client/active_model/gcm/app.rb +19 -0
- data/lib/rpush/client/active_model/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +14 -0
- data/lib/rpush/client/active_model/gcm/notification.rb +59 -0
- data/lib/rpush/client/active_model/notification.rb +22 -0
- data/lib/rpush/client/active_model/payload_data_size_validator.rb +13 -0
- data/lib/rpush/client/active_model/pushy/app.rb +20 -0
- data/lib/rpush/client/active_model/pushy/notification.rb +31 -0
- data/lib/rpush/client/active_model/pushy/time_to_live_validator.rb +14 -0
- data/lib/rpush/client/active_model/registration_ids_count_validator.rb +13 -0
- data/lib/rpush/client/active_model/wns/app.rb +23 -0
- data/lib/rpush/client/active_model/wns/notification.rb +32 -0
- data/lib/rpush/client/active_model/wpns/app.rb +13 -0
- data/lib/rpush/client/active_model/wpns/notification.rb +28 -0
- data/lib/rpush/client/active_model.rb +34 -0
- data/lib/rpush/client/active_record/adm/app.rb +11 -0
- data/lib/rpush/client/active_record/adm/notification.rb +11 -0
- data/lib/rpush/client/active_record/apns/app.rb +11 -0
- data/lib/rpush/client/active_record/apns/feedback.rb +18 -0
- data/lib/rpush/client/active_record/apns/notification.rb +40 -0
- data/lib/rpush/client/active_record/apns2/app.rb +11 -0
- data/lib/rpush/client/active_record/apns2/notification.rb +10 -0
- data/lib/rpush/client/active_record/apnsp8/app.rb +11 -0
- data/lib/rpush/client/active_record/apnsp8/notification.rb +10 -0
- data/lib/rpush/client/active_record/app.rb +13 -0
- data/lib/rpush/client/active_record/gcm/app.rb +11 -0
- data/lib/rpush/client/active_record/gcm/notification.rb +11 -0
- data/lib/rpush/client/active_record/notification.rb +42 -0
- data/lib/rpush/client/active_record/pushy/app.rb +11 -0
- data/lib/rpush/client/active_record/pushy/notification.rb +11 -0
- data/lib/rpush/client/active_record/wns/app.rb +11 -0
- data/lib/rpush/client/active_record/wns/badge_notification.rb +15 -0
- data/lib/rpush/client/active_record/wns/notification.rb +11 -0
- data/lib/rpush/client/active_record/wns/raw_notification.rb +13 -0
- data/lib/rpush/client/active_record/wpns/app.rb +11 -0
- data/lib/rpush/client/active_record/wpns/notification.rb +11 -0
- data/lib/rpush/client/active_record.rb +33 -0
- data/lib/rpush/client/redis/adm/app.rb +14 -0
- data/lib/rpush/client/redis/adm/notification.rb +11 -0
- data/lib/rpush/client/redis/apns/app.rb +11 -0
- data/lib/rpush/client/redis/apns/feedback.rb +20 -0
- data/lib/rpush/client/redis/apns/notification.rb +11 -0
- data/lib/rpush/client/redis/apns2/app.rb +11 -0
- data/lib/rpush/client/redis/apns2/notification.rb +11 -0
- data/lib/rpush/client/redis/apnsp8/app.rb +11 -0
- data/lib/rpush/client/redis/apnsp8/notification.rb +11 -0
- data/lib/rpush/client/redis/app.rb +29 -0
- data/lib/rpush/client/redis/gcm/app.rb +11 -0
- data/lib/rpush/client/redis/gcm/notification.rb +11 -0
- data/lib/rpush/client/redis/notification.rb +74 -0
- data/lib/rpush/client/redis/pushy/app.rb +16 -0
- data/lib/rpush/client/redis/pushy/notification.rb +18 -0
- data/lib/rpush/client/redis/wns/app.rb +14 -0
- data/lib/rpush/client/redis/wns/badge_notification.rb +15 -0
- data/lib/rpush/client/redis/wns/notification.rb +11 -0
- data/lib/rpush/client/redis/wns/raw_notification.rb +11 -0
- data/lib/rpush/client/redis/wpns/app.rb +11 -0
- data/lib/rpush/client/redis/wpns/notification.rb +11 -0
- data/lib/rpush/client/redis.rb +56 -0
- data/lib/rpush/configuration.rb +115 -0
- data/lib/rpush/daemon/adm/delivery.rb +226 -0
- data/lib/rpush/daemon/adm.rb +9 -0
- data/lib/rpush/daemon/apns/delivery.rb +43 -0
- data/lib/rpush/daemon/apns/feedback_receiver.rb +90 -0
- data/lib/rpush/daemon/apns.rb +17 -0
- data/lib/rpush/daemon/apns2/delivery.rb +127 -0
- data/lib/rpush/daemon/apns2.rb +10 -0
- data/lib/rpush/daemon/apnsp8/delivery.rb +166 -0
- data/lib/rpush/daemon/apnsp8/token.rb +43 -0
- data/lib/rpush/daemon/apnsp8.rb +10 -0
- data/lib/rpush/daemon/app_runner.rb +190 -0
- data/lib/rpush/daemon/batch.rb +138 -0
- data/lib/rpush/daemon/constants.rb +59 -0
- data/lib/rpush/daemon/delivery.rb +46 -0
- data/lib/rpush/daemon/delivery_error.rb +27 -0
- data/lib/rpush/daemon/dispatcher/apns_http2.rb +51 -0
- data/lib/rpush/daemon/dispatcher/apns_tcp.rb +152 -0
- data/lib/rpush/daemon/dispatcher/apnsp8_http2.rb +33 -0
- data/lib/rpush/daemon/dispatcher/http.rb +21 -0
- data/lib/rpush/daemon/dispatcher/tcp.rb +22 -0
- data/lib/rpush/daemon/dispatcher_loop.rb +73 -0
- data/lib/rpush/daemon/errors.rb +18 -0
- data/lib/rpush/daemon/feeder.rb +69 -0
- data/lib/rpush/daemon/gcm/delivery.rb +241 -0
- data/lib/rpush/daemon/gcm.rb +9 -0
- data/lib/rpush/daemon/interruptible_sleep.rb +24 -0
- data/lib/rpush/daemon/loggable.rb +33 -0
- data/lib/rpush/daemon/proc_title.rb +17 -0
- data/lib/rpush/daemon/pushy/delivery.rb +90 -0
- data/lib/rpush/daemon/pushy.rb +9 -0
- data/lib/rpush/daemon/queue_payload.rb +12 -0
- data/lib/rpush/daemon/retry_header_parser.rb +23 -0
- data/lib/rpush/daemon/retryable_error.rb +22 -0
- data/lib/rpush/daemon/ring_buffer.rb +16 -0
- data/lib/rpush/daemon/rpc/client.rb +27 -0
- data/lib/rpush/daemon/rpc/server.rb +82 -0
- data/lib/rpush/daemon/rpc.rb +9 -0
- data/lib/rpush/daemon/service_config_methods.rb +51 -0
- data/lib/rpush/daemon/signal_handler.rb +75 -0
- data/lib/rpush/daemon/store/active_record/reconnectable.rb +80 -0
- data/lib/rpush/daemon/store/active_record.rb +214 -0
- data/lib/rpush/daemon/store/interface.rb +20 -0
- data/lib/rpush/daemon/store/redis.rb +166 -0
- data/lib/rpush/daemon/string_helpers.rb +15 -0
- data/lib/rpush/daemon/synchronizer.rb +62 -0
- data/lib/rpush/daemon/tcp_connection.rb +190 -0
- data/lib/rpush/daemon/wns/badge_request.rb +32 -0
- data/lib/rpush/daemon/wns/delivery.rb +178 -0
- data/lib/rpush/daemon/wns/post_request.rb +33 -0
- data/lib/rpush/daemon/wns/raw_request.rb +22 -0
- data/lib/rpush/daemon/wns/toast_request.rb +54 -0
- data/lib/rpush/daemon/wns.rb +9 -0
- data/lib/rpush/daemon/wpns/delivery.rb +132 -0
- data/lib/rpush/daemon/wpns.rb +9 -0
- data/lib/rpush/daemon.rb +179 -0
- data/lib/rpush/deprecatable.rb +24 -0
- data/lib/rpush/deprecation.rb +26 -0
- data/lib/rpush/embed.rb +41 -0
- data/lib/rpush/logger.rb +92 -0
- data/lib/rpush/multi_json_helper.rb +16 -0
- data/lib/rpush/plugin.rb +44 -0
- data/lib/rpush/push.rb +11 -0
- data/lib/rpush/reflectable.rb +13 -0
- data/lib/rpush/reflection_collection.rb +44 -0
- data/lib/rpush/reflection_public_methods.rb +11 -0
- data/lib/rpush/version.rb +14 -0
- data/lib/rpush.rb +43 -0
- data/lib/tasks/quality.rake +35 -0
- data/lib/tasks/test.rake +69 -0
- data/spec/.rubocop.yml +4 -0
- data/spec/functional/adm_spec.rb +50 -0
- data/spec/functional/apns2_spec.rb +232 -0
- data/spec/functional/apns_spec.rb +162 -0
- data/spec/functional/cli_spec.rb +36 -0
- data/spec/functional/embed_spec.rb +49 -0
- data/spec/functional/gcm_spec.rb +46 -0
- data/spec/functional/new_app_spec.rb +44 -0
- data/spec/functional/pushy_spec.rb +22 -0
- data/spec/functional/retry_spec.rb +42 -0
- data/spec/functional/synchronization_spec.rb +97 -0
- data/spec/functional/wpns_spec.rb +71 -0
- data/spec/functional_spec_helper.rb +32 -0
- data/spec/spec_helper.rb +69 -0
- data/spec/support/active_record_setup.rb +73 -0
- data/spec/support/cert_with_password.pem +90 -0
- data/spec/support/cert_without_password.pem +59 -0
- data/spec/support/config/database.yml +44 -0
- data/spec/support/simplecov_helper.rb +24 -0
- data/spec/support/simplecov_quality_formatter.rb +12 -0
- data/spec/tmp/.gitkeep +0 -0
- data/spec/unit/apns_feedback_spec.rb +28 -0
- data/spec/unit/client/active_record/adm/app_spec.rb +58 -0
- data/spec/unit/client/active_record/adm/notification_spec.rb +43 -0
- data/spec/unit/client/active_record/apns/app_spec.rb +29 -0
- data/spec/unit/client/active_record/apns/feedback_spec.rb +9 -0
- data/spec/unit/client/active_record/apns/notification_spec.rb +324 -0
- data/spec/unit/client/active_record/app_spec.rb +30 -0
- data/spec/unit/client/active_record/gcm/app_spec.rb +4 -0
- data/spec/unit/client/active_record/gcm/notification_spec.rb +67 -0
- data/spec/unit/client/active_record/notification_spec.rb +21 -0
- data/spec/unit/client/active_record/pushy/app_spec.rb +17 -0
- data/spec/unit/client/active_record/pushy/notification_spec.rb +65 -0
- data/spec/unit/client/active_record/wns/badge_notification_spec.rb +15 -0
- data/spec/unit/client/active_record/wns/raw_notification_spec.rb +26 -0
- data/spec/unit/client/active_record/wpns/app_spec.rb +4 -0
- data/spec/unit/client/active_record/wpns/notification_spec.rb +21 -0
- data/spec/unit/configuration_spec.rb +46 -0
- data/spec/unit/daemon/adm/delivery_spec.rb +253 -0
- data/spec/unit/daemon/apns/certificate_expired_error_spec.rb +11 -0
- data/spec/unit/daemon/apns/delivery_spec.rb +108 -0
- data/spec/unit/daemon/apns/feedback_receiver_spec.rb +119 -0
- data/spec/unit/daemon/app_runner_spec.rb +188 -0
- data/spec/unit/daemon/batch_spec.rb +169 -0
- data/spec/unit/daemon/delivery_error_spec.rb +13 -0
- data/spec/unit/daemon/delivery_spec.rb +51 -0
- data/spec/unit/daemon/dispatcher/http_spec.rb +34 -0
- data/spec/unit/daemon/dispatcher/tcp_spec.rb +32 -0
- data/spec/unit/daemon/dispatcher_loop_spec.rb +53 -0
- data/spec/unit/daemon/feeder_spec.rb +96 -0
- data/spec/unit/daemon/gcm/delivery_spec.rb +387 -0
- data/spec/unit/daemon/proc_title_spec.rb +11 -0
- data/spec/unit/daemon/pushy/delivery_spec.rb +159 -0
- data/spec/unit/daemon/retryable_error_spec.rb +14 -0
- data/spec/unit/daemon/service_config_methods_spec.rb +36 -0
- data/spec/unit/daemon/signal_handler_spec.rb +99 -0
- data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +165 -0
- data/spec/unit/daemon/store/active_record_spec.rb +357 -0
- data/spec/unit/daemon/store/redis_spec.rb +365 -0
- data/spec/unit/daemon/tcp_connection_spec.rb +292 -0
- data/spec/unit/daemon/wns/delivery_spec.rb +176 -0
- data/spec/unit/daemon/wns/post_request_spec.rb +117 -0
- data/spec/unit/daemon/wpns/delivery_spec.rb +167 -0
- data/spec/unit/daemon_spec.rb +138 -0
- data/spec/unit/deprecatable_spec.rb +32 -0
- data/spec/unit/deprecation_spec.rb +15 -0
- data/spec/unit/embed_spec.rb +47 -0
- data/spec/unit/logger_spec.rb +127 -0
- data/spec/unit/notification_shared.rb +53 -0
- data/spec/unit/plugin_spec.rb +36 -0
- data/spec/unit/push_spec.rb +34 -0
- data/spec/unit/reflectable_spec.rb +27 -0
- data/spec/unit/reflection_collection_spec.rb +26 -0
- data/spec/unit/rpush_spec.rb +8 -0
- data/spec/unit_spec_helper.rb +26 -0
- metadata +709 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
module Rpush
|
|
2
|
+
module Daemon
|
|
3
|
+
module Wns
|
|
4
|
+
# https://msdn.microsoft.com/en-us/library/windows/apps/hh465435.aspx
|
|
5
|
+
class Delivery < Rpush::Daemon::Delivery
|
|
6
|
+
# Oauth2.0 token endpoint. This endpoint is used to request authorization tokens.
|
|
7
|
+
WPN_TOKEN_URI = URI.parse('https://login.live.com/accesstoken.srf')
|
|
8
|
+
|
|
9
|
+
# Data used to request authorization tokens.
|
|
10
|
+
ACCESS_TOKEN_REQUEST_DATA = { "grant_type" => "client_credentials", "scope" => "notify.windows.com" }
|
|
11
|
+
|
|
12
|
+
MAX_RETRIES = 14
|
|
13
|
+
|
|
14
|
+
FAILURE_MESSAGES = {
|
|
15
|
+
400 => 'One or more headers were specified incorrectly or conflict with another header.',
|
|
16
|
+
401 => 'The cloud service did not present a valid authentication ticket. The OAuth ticket may be invalid.',
|
|
17
|
+
403 => 'The cloud service is not authorized to send a notification to this URI even though they are authenticated.',
|
|
18
|
+
404 => 'The channel URI is not valid or is not recognized by WNS.',
|
|
19
|
+
405 => 'Invalid method (GET, CREATE); only POST (Windows or Windows Phone) or DELETE (Windows Phone only) is allowed.',
|
|
20
|
+
406 => 'The cloud service exceeded its throttle limit.',
|
|
21
|
+
410 => 'The channel expired.',
|
|
22
|
+
413 => 'The notification payload exceeds the 5000 byte size limit.',
|
|
23
|
+
500 => 'An internal failure caused notification delivery to fail.',
|
|
24
|
+
503 => 'The server is currently unavailable.'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
def initialize(app, http, notification, batch)
|
|
28
|
+
@app = app
|
|
29
|
+
@http = http
|
|
30
|
+
@notification = notification
|
|
31
|
+
@batch = batch
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def perform
|
|
35
|
+
handle_response(do_post)
|
|
36
|
+
rescue SocketError => error
|
|
37
|
+
mark_retryable(@notification, Time.now + 10.seconds, error)
|
|
38
|
+
raise
|
|
39
|
+
rescue StandardError => error
|
|
40
|
+
mark_failed(error)
|
|
41
|
+
raise
|
|
42
|
+
ensure
|
|
43
|
+
@batch.notification_processed
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def handle_response(response)
|
|
49
|
+
code = response.code.to_i
|
|
50
|
+
case code
|
|
51
|
+
when 200
|
|
52
|
+
ok(response)
|
|
53
|
+
when 401
|
|
54
|
+
unauthorized
|
|
55
|
+
when 404
|
|
56
|
+
invalid_channel(code)
|
|
57
|
+
when 406
|
|
58
|
+
not_acceptable
|
|
59
|
+
when 410
|
|
60
|
+
invalid_channel(code)
|
|
61
|
+
when 412
|
|
62
|
+
precondition_failed
|
|
63
|
+
when 503
|
|
64
|
+
service_unavailable
|
|
65
|
+
else
|
|
66
|
+
handle_failure(code)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def handle_failure(code, msg = nil)
|
|
71
|
+
unless msg
|
|
72
|
+
msg = FAILURE_MESSAGES.key?(code) ? FAILURE_MESSAGES[code] : Rpush::Daemon::HTTP_STATUS_CODES[code]
|
|
73
|
+
end
|
|
74
|
+
fail Rpush::DeliveryError.new(code, @notification.id, msg)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def ok(response)
|
|
78
|
+
status = status_from_response(response)
|
|
79
|
+
case status[:notification]
|
|
80
|
+
when ["received"]
|
|
81
|
+
mark_delivered
|
|
82
|
+
log_info("#{@notification.id} sent successfully")
|
|
83
|
+
when ["channelthrottled"]
|
|
84
|
+
mark_retryable(@notification, Time.now + (60 * 10))
|
|
85
|
+
log_warn("#{@notification.id} cannot be sent. The Queue is full.")
|
|
86
|
+
when ["dropped"]
|
|
87
|
+
log_error("#{@notification.id} was dropped. Headers: #{status}")
|
|
88
|
+
handle_failure(200, "Notification was received but suppressed by the service (#{status[:error_description]}).")
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def unauthorized
|
|
93
|
+
@notification.app.access_token = nil
|
|
94
|
+
Rpush::Daemon.store.update_app(@notification.app)
|
|
95
|
+
if @notification.retries < MAX_RETRIES
|
|
96
|
+
retry_notification("Token invalid.")
|
|
97
|
+
else
|
|
98
|
+
msg = "Notification failed to be delivered in #{MAX_RETRIES} retries."
|
|
99
|
+
mark_failed(Rpush::DeliveryError.new(nil, @notification.id, msg))
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def invalid_channel(code, msg = nil)
|
|
104
|
+
unless msg
|
|
105
|
+
msg = FAILURE_MESSAGES.key?(code) ? FAILURE_MESSAGES[code] : Rpush::Daemon::HTTP_STATUS_CODES[code]
|
|
106
|
+
end
|
|
107
|
+
reflect(:wns_invalid_channel, @notification, @notification.uri, "#{code}. #{msg}")
|
|
108
|
+
handle_failure(code, msg)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def not_acceptable
|
|
112
|
+
retry_notification("Per-day throttling limit reached.")
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def precondition_failed
|
|
116
|
+
retry_notification("Device unreachable.")
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def service_unavailable
|
|
120
|
+
mark_retryable_exponential(@notification)
|
|
121
|
+
log_warn("Service Unavailable. " + retry_message)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def retry_message
|
|
125
|
+
"Notification #{@notification.id} will be retried after #{@notification.deliver_after.strftime('%Y-%m-%d %H:%M:%S')} (retry #{@notification.retries})."
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def retry_notification(reason)
|
|
129
|
+
deliver_after = Time.now + (60 * 60)
|
|
130
|
+
mark_retryable(@notification, deliver_after)
|
|
131
|
+
log_warn("#{reason} " + retry_message)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def do_post
|
|
135
|
+
post = PostRequest.create(@notification, access_token)
|
|
136
|
+
@http.request(URI.parse(@notification.uri), post)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def status_from_response(response)
|
|
140
|
+
headers = response.to_hash.each_with_object({}) { |e, a| a[e[0].downcase] = e[1] }
|
|
141
|
+
{
|
|
142
|
+
notification: headers["x-wns-status"],
|
|
143
|
+
device_connection: headers["x-wns-deviceconnectionstatus"],
|
|
144
|
+
msg_id: headers["x-wns-msg-id"],
|
|
145
|
+
error_description: headers["x-wns-error-description"],
|
|
146
|
+
debug_trace: headers["x-wns-debug-trace"]
|
|
147
|
+
}
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def access_token
|
|
151
|
+
if @notification.app.access_token.nil? || @notification.app.access_token_expired?
|
|
152
|
+
post = Net::HTTP::Post.new(WPN_TOKEN_URI.path, 'Content-Type' => 'application/x-www-form-urlencoded')
|
|
153
|
+
post.set_form_data(ACCESS_TOKEN_REQUEST_DATA.merge('client_id' => @notification.app.client_id, 'client_secret' => @notification.app.client_secret))
|
|
154
|
+
|
|
155
|
+
handle_access_token(@http.request(WPN_TOKEN_URI, post))
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
@notification.app.access_token
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def handle_access_token(response)
|
|
162
|
+
if response.code.to_i == 200
|
|
163
|
+
update_access_token(JSON.parse(response.body))
|
|
164
|
+
Rpush::Daemon.store.update_app(@notification.app)
|
|
165
|
+
log_info("WNS access token updated: token = #{@notification.app.access_token}, expires = #{@notification.app.access_token_expiration}")
|
|
166
|
+
else
|
|
167
|
+
log_warn("Could not retrieve access token from WNS: #{response.body}")
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def update_access_token(data)
|
|
172
|
+
@notification.app.access_token = data['access_token']
|
|
173
|
+
@notification.app.access_token_expiration = Time.now + data['expires_in'].to_i
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Rpush
|
|
2
|
+
module Daemon
|
|
3
|
+
module Wns
|
|
4
|
+
class PostRequest
|
|
5
|
+
def self.create(notification, access_token)
|
|
6
|
+
stringify_keys(notification.data) unless notification.data.nil?
|
|
7
|
+
|
|
8
|
+
if raw_notification?(notification)
|
|
9
|
+
RawRequest.create(notification, access_token)
|
|
10
|
+
elsif badge_notification?(notification)
|
|
11
|
+
BadgeRequest.create(notification, access_token)
|
|
12
|
+
else
|
|
13
|
+
ToastRequest.create(notification, access_token)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private_class_method
|
|
18
|
+
|
|
19
|
+
def self.raw_notification?(notification)
|
|
20
|
+
notification.class.name.match(/RawNotification/)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.badge_notification?(notification)
|
|
24
|
+
notification.class.name.match(/BadgeNotification/)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.stringify_keys(data)
|
|
28
|
+
data.keys.each { |key| data[key.to_s || key] = data.delete(key) }
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Rpush
|
|
2
|
+
module Daemon
|
|
3
|
+
module Wns
|
|
4
|
+
class RawRequest
|
|
5
|
+
def self.create(notification, access_token)
|
|
6
|
+
body = notification.data.to_json
|
|
7
|
+
uri = URI.parse(notification.uri)
|
|
8
|
+
post = Net::HTTP::Post.new(
|
|
9
|
+
uri.request_uri,
|
|
10
|
+
"Content-Length" => body.length.to_s,
|
|
11
|
+
"Content-Type" => "application/octet-stream",
|
|
12
|
+
"X-WNS-Type" => "wns/raw",
|
|
13
|
+
"X-WNS-RequestForStatus" => "true",
|
|
14
|
+
"Authorization" => "Bearer #{access_token}"
|
|
15
|
+
)
|
|
16
|
+
post.body = body
|
|
17
|
+
post
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Rpush
|
|
2
|
+
module Daemon
|
|
3
|
+
module Wns
|
|
4
|
+
class ToastRequest
|
|
5
|
+
def self.create(notification, access_token)
|
|
6
|
+
body = ToastRequestPayload.new(notification).to_xml
|
|
7
|
+
uri = URI.parse(notification.uri)
|
|
8
|
+
post = Net::HTTP::Post.new(
|
|
9
|
+
uri.request_uri,
|
|
10
|
+
"Content-Length" => body.length.to_s,
|
|
11
|
+
"Content-Type" => "text/xml",
|
|
12
|
+
"X-WNS-Type" => "wns/toast",
|
|
13
|
+
"X-WNS-RequestForStatus" => "true",
|
|
14
|
+
"Authorization" => "Bearer #{access_token}"
|
|
15
|
+
)
|
|
16
|
+
post.body = body
|
|
17
|
+
post
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class ToastRequestPayload
|
|
22
|
+
def initialize(notification)
|
|
23
|
+
@title = notification.data['title'] || ''
|
|
24
|
+
@body = notification.data['body'] || ''
|
|
25
|
+
@launch = notification.data['launch']
|
|
26
|
+
@sound = notification.sound unless notification.sound.eql?("default".freeze)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def to_xml
|
|
30
|
+
launch_string = "" unless @launch
|
|
31
|
+
launch_string = " launch='#{CleanParamString.clean(@launch)}'" if @launch
|
|
32
|
+
audio_string = "" unless @sound
|
|
33
|
+
audio_string = "<audio src='#{CleanParamString.clean(@sound)}'/>" if @sound
|
|
34
|
+
"<toast#{launch_string}>
|
|
35
|
+
<visual version='1' lang='en-US'>
|
|
36
|
+
<binding template='ToastText02'>
|
|
37
|
+
<text id='1'>#{CleanParamString.clean(@title)}</text>
|
|
38
|
+
<text id='2'>#{CleanParamString.clean(@body)}</text>
|
|
39
|
+
</binding>
|
|
40
|
+
</visual>
|
|
41
|
+
#{audio_string}
|
|
42
|
+
</toast>"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
class CleanParamString
|
|
47
|
+
def self.clean(string)
|
|
48
|
+
string.gsub(/&/, "&").gsub(/</, "<") \
|
|
49
|
+
.gsub(/>/, ">").gsub(/'/, "'").gsub(/"/, """)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
module Rpush
|
|
2
|
+
module Daemon
|
|
3
|
+
module Wpns
|
|
4
|
+
# http://msdn.microsoft.com/en-us/library/windowsphone/develop/ff941100%28v=vs.105%29.aspx
|
|
5
|
+
class Delivery < Rpush::Daemon::Delivery
|
|
6
|
+
FAILURE_MESSAGES = {
|
|
7
|
+
400 => 'Bad XML or malformed notification URI.',
|
|
8
|
+
401 => 'Unauthorized to send a notification to this app.'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
def initialize(app, http, notification, batch)
|
|
12
|
+
@app = app
|
|
13
|
+
@http = http
|
|
14
|
+
@notification = notification
|
|
15
|
+
@batch = batch
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def perform
|
|
19
|
+
handle_response(do_post)
|
|
20
|
+
rescue SocketError => error
|
|
21
|
+
mark_retryable(@notification, Time.now + 10.seconds, error)
|
|
22
|
+
raise
|
|
23
|
+
rescue StandardError => error
|
|
24
|
+
mark_failed(error)
|
|
25
|
+
raise
|
|
26
|
+
ensure
|
|
27
|
+
@batch.notification_processed
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def handle_response(response)
|
|
33
|
+
code = response.code.to_i
|
|
34
|
+
case code
|
|
35
|
+
when 200
|
|
36
|
+
ok(response)
|
|
37
|
+
when 406
|
|
38
|
+
not_acceptable
|
|
39
|
+
when 412
|
|
40
|
+
precondition_failed
|
|
41
|
+
when 503
|
|
42
|
+
service_unavailable
|
|
43
|
+
else
|
|
44
|
+
handle_failure(code)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def handle_failure(code, msg = nil)
|
|
49
|
+
unless msg
|
|
50
|
+
msg = FAILURE_MESSAGES.key?(code) ? FAILURE_MESSAGES[code] : Rpush::Daemon::HTTP_STATUS_CODES[code]
|
|
51
|
+
end
|
|
52
|
+
fail Rpush::DeliveryError.new(code, @notification.id, msg)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def ok(response)
|
|
56
|
+
status = status_from_response(response)
|
|
57
|
+
case status[:notification]
|
|
58
|
+
when ["Received"]
|
|
59
|
+
mark_delivered
|
|
60
|
+
log_info("#{@notification.id} sent successfully")
|
|
61
|
+
when ["QueueFull"]
|
|
62
|
+
mark_retryable(@notification, Time.now + (60 * 10))
|
|
63
|
+
log_warn("#{@notification.id} cannot be sent. The Queue is full.")
|
|
64
|
+
when ["Suppressed"]
|
|
65
|
+
handle_failure(200, "Notification was received but suppressed by the service.")
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def not_acceptable
|
|
70
|
+
retry_notification("Per-day throttling limit reached.")
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def precondition_failed
|
|
74
|
+
retry_notification("Device unreachable.")
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def service_unavailable
|
|
78
|
+
mark_retryable_exponential(@notification)
|
|
79
|
+
log_warn("Service Unavailable. " + retry_message)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def retry_message
|
|
83
|
+
"Notification #{@notification.id} will be retried after #{@notification.deliver_after.strftime('%Y-%m-%d %H:%M:%S')} (retry #{@notification.retries})."
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def retry_notification(reason)
|
|
87
|
+
deliver_after = Time.now + (60 * 60)
|
|
88
|
+
mark_retryable(@notification, deliver_after)
|
|
89
|
+
log_warn("#{reason} " + retry_message)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def do_post
|
|
93
|
+
body = notification_to_xml
|
|
94
|
+
post = Net::HTTP::Post.new(URI.parse(@notification.uri).path, "Content-Length" => body.length.to_s,
|
|
95
|
+
"Content-Type" => "text/xml",
|
|
96
|
+
"X-WindowsPhone-Target" => "toast",
|
|
97
|
+
"X-NotificationClass" => '2')
|
|
98
|
+
post.body = body
|
|
99
|
+
@http.request(URI.parse(@notification.uri), post)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def status_from_response(response)
|
|
103
|
+
headers = response.to_hash
|
|
104
|
+
{
|
|
105
|
+
notification: headers["x-notificationstatus"],
|
|
106
|
+
notification_channel: headers["x-subscriptionstatus"],
|
|
107
|
+
device_connection: headers["x-deviceconnectionstatus"]
|
|
108
|
+
}
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def notification_to_xml
|
|
112
|
+
title = clean_param_string(@notification.data['title']) if @notification.data['title'].present?
|
|
113
|
+
body = clean_param_string(@notification.data['body']) if @notification.data['body'].present?
|
|
114
|
+
param = clean_param_string(@notification.data['param']) if @notification.data['param'].present?
|
|
115
|
+
"<?xml version=\"1.0\" encoding=\"utf-8\"?>
|
|
116
|
+
<wp:Notification xmlns:wp=\"WPNotification\">
|
|
117
|
+
<wp:Toast>
|
|
118
|
+
<wp:Text1>#{title}</wp:Text1>
|
|
119
|
+
<wp:Text2>#{body}</wp:Text2>
|
|
120
|
+
<wp:Param>#{param}</wp:Param>
|
|
121
|
+
</wp:Toast>
|
|
122
|
+
</wp:Notification>"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def clean_param_string(string)
|
|
126
|
+
string.gsub(/&/, "&").gsub(/</, "<") \
|
|
127
|
+
.gsub(/>/, ">").gsub(/'/, "'").gsub(/"/, """)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
data/lib/rpush/daemon.rb
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
require 'thread'
|
|
4
|
+
require 'socket'
|
|
5
|
+
require 'pathname'
|
|
6
|
+
require 'openssl'
|
|
7
|
+
require 'net/http/persistent'
|
|
8
|
+
|
|
9
|
+
require 'rpush/daemon/errors'
|
|
10
|
+
require 'rpush/daemon/constants'
|
|
11
|
+
require 'rpush/daemon/loggable'
|
|
12
|
+
require 'rpush/daemon/string_helpers'
|
|
13
|
+
require 'rpush/daemon/interruptible_sleep'
|
|
14
|
+
require 'rpush/daemon/delivery_error'
|
|
15
|
+
require 'rpush/daemon/retryable_error'
|
|
16
|
+
require 'rpush/daemon/delivery'
|
|
17
|
+
require 'rpush/daemon/feeder'
|
|
18
|
+
require 'rpush/daemon/batch'
|
|
19
|
+
require 'rpush/daemon/queue_payload'
|
|
20
|
+
require 'rpush/daemon/synchronizer'
|
|
21
|
+
require 'rpush/daemon/app_runner'
|
|
22
|
+
require 'rpush/daemon/tcp_connection'
|
|
23
|
+
require 'rpush/daemon/dispatcher_loop'
|
|
24
|
+
require 'rpush/daemon/dispatcher/http'
|
|
25
|
+
require 'rpush/daemon/dispatcher/tcp'
|
|
26
|
+
require 'rpush/daemon/dispatcher/apns_tcp'
|
|
27
|
+
require 'rpush/daemon/dispatcher/apns_http2'
|
|
28
|
+
require 'rpush/daemon/dispatcher/apnsp8_http2'
|
|
29
|
+
require 'rpush/daemon/service_config_methods'
|
|
30
|
+
require 'rpush/daemon/retry_header_parser'
|
|
31
|
+
require 'rpush/daemon/ring_buffer'
|
|
32
|
+
require 'rpush/daemon/signal_handler'
|
|
33
|
+
require 'rpush/daemon/proc_title'
|
|
34
|
+
|
|
35
|
+
require 'rpush/daemon/rpc'
|
|
36
|
+
require 'rpush/daemon/rpc/server'
|
|
37
|
+
require 'rpush/daemon/rpc/client'
|
|
38
|
+
|
|
39
|
+
require 'rpush/daemon/store/interface'
|
|
40
|
+
|
|
41
|
+
require 'rpush/daemon/apns/delivery'
|
|
42
|
+
require 'rpush/daemon/apns/feedback_receiver'
|
|
43
|
+
require 'rpush/daemon/apns'
|
|
44
|
+
|
|
45
|
+
require 'rpush/daemon/apns2/delivery'
|
|
46
|
+
require 'rpush/daemon/apns2'
|
|
47
|
+
|
|
48
|
+
require 'rpush/daemon/apnsp8/delivery'
|
|
49
|
+
require 'rpush/daemon/apnsp8/token'
|
|
50
|
+
require 'rpush/daemon/apnsp8'
|
|
51
|
+
|
|
52
|
+
require 'rpush/daemon/gcm/delivery'
|
|
53
|
+
require 'rpush/daemon/gcm'
|
|
54
|
+
|
|
55
|
+
require 'rpush/daemon/wpns/delivery'
|
|
56
|
+
require 'rpush/daemon/wpns'
|
|
57
|
+
|
|
58
|
+
require 'rpush/daemon/wns/post_request'
|
|
59
|
+
require 'rpush/daemon/wns/raw_request'
|
|
60
|
+
require 'rpush/daemon/wns/toast_request'
|
|
61
|
+
require 'rpush/daemon/wns/badge_request'
|
|
62
|
+
require 'rpush/daemon/wns/delivery'
|
|
63
|
+
require 'rpush/daemon/wns'
|
|
64
|
+
|
|
65
|
+
require 'rpush/daemon/adm/delivery'
|
|
66
|
+
require 'rpush/daemon/adm'
|
|
67
|
+
|
|
68
|
+
require 'rpush/daemon/pushy'
|
|
69
|
+
require 'rpush/daemon/pushy/delivery'
|
|
70
|
+
|
|
71
|
+
module Rpush
|
|
72
|
+
module Daemon
|
|
73
|
+
class << self
|
|
74
|
+
attr_accessor :store
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def self.start
|
|
78
|
+
Process.daemon if daemonize?
|
|
79
|
+
write_pid_file
|
|
80
|
+
SignalHandler.start
|
|
81
|
+
common_init
|
|
82
|
+
Synchronizer.sync
|
|
83
|
+
Rpc::Server.start
|
|
84
|
+
|
|
85
|
+
# No further store connections will be made from this thread.
|
|
86
|
+
store.release_connection
|
|
87
|
+
|
|
88
|
+
Rpush.logger.info('Rpush operational.')
|
|
89
|
+
show_welcome_if_needed
|
|
90
|
+
|
|
91
|
+
# Blocking call, returns after Feeder.stop is called from another thread.
|
|
92
|
+
Feeder.start
|
|
93
|
+
|
|
94
|
+
# Wait for shutdown to complete.
|
|
95
|
+
shutdown_lock.synchronize { true }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def self.shutdown
|
|
99
|
+
if Rpush.config.foreground
|
|
100
|
+
# Eat the '^C'
|
|
101
|
+
STDOUT.write("\b\b")
|
|
102
|
+
STDOUT.flush
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
Rpush.logger.info('Shutting down... ', true)
|
|
106
|
+
|
|
107
|
+
shutdown_lock.synchronize do
|
|
108
|
+
Rpc::Server.stop
|
|
109
|
+
Feeder.stop
|
|
110
|
+
AppRunner.stop
|
|
111
|
+
delete_pid_file
|
|
112
|
+
puts ANSI.green { '✔' } if Rpush.config.foreground
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def self.shutdown_lock
|
|
117
|
+
@shutdown_lock ||= Mutex.new
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def self.common_init
|
|
121
|
+
init_store
|
|
122
|
+
init_plugins
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
protected
|
|
126
|
+
|
|
127
|
+
def self.init_store
|
|
128
|
+
return if store
|
|
129
|
+
begin
|
|
130
|
+
name = Rpush.config.client.to_s
|
|
131
|
+
require "rpush/daemon/store/#{name}"
|
|
132
|
+
self.store = Rpush::Daemon::Store.const_get(name.camelcase).new
|
|
133
|
+
rescue StandardError, LoadError => e
|
|
134
|
+
Rpush.logger.error("Failed to load '#{Rpush.config.client}' storage backend.")
|
|
135
|
+
Rpush.logger.error(e)
|
|
136
|
+
exit 1
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def self.init_plugins
|
|
141
|
+
Rpush.plugins.each do |name, plugin|
|
|
142
|
+
plugin.init_block.call
|
|
143
|
+
Rpush.logger.info("[plugin:#{name}] Loaded.")
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def self.daemonize?
|
|
148
|
+
!(Rpush.config.push || Rpush.config.foreground || Rpush.config.embedded || Rpush.jruby?)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def self.write_pid_file
|
|
152
|
+
unless Rpush.config.pid_file.blank?
|
|
153
|
+
begin
|
|
154
|
+
FileUtils.mkdir_p(File.dirname(Rpush.config.pid_file))
|
|
155
|
+
File.open(Rpush.config.pid_file, 'w') { |f| f.puts Process.pid }
|
|
156
|
+
rescue SystemCallError => e
|
|
157
|
+
Rpush.logger.error("Failed to write PID to '#{Rpush.config.pid_file}': #{e.inspect}")
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def self.delete_pid_file
|
|
163
|
+
pid_file = Rpush.config.pid_file
|
|
164
|
+
File.delete(pid_file) if !pid_file.blank? && File.exist?(pid_file)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def self.show_welcome_if_needed
|
|
168
|
+
if Rpush::Daemon::AppRunner.app_ids.count == 0
|
|
169
|
+
puts <<-EOS
|
|
170
|
+
|
|
171
|
+
* #{ANSI.green { 'Is this your first time using Rpush?' }}
|
|
172
|
+
You need to create an App before you can start using Rpush.
|
|
173
|
+
Please refer to the documentation at https://github.com/rpush/rpush
|
|
174
|
+
|
|
175
|
+
EOS
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Rpush
|
|
2
|
+
module Deprecatable
|
|
3
|
+
def self.included(base)
|
|
4
|
+
base.extend ClassMethods
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
module ClassMethods
|
|
8
|
+
def deprecated(method_name, version, msg = nil)
|
|
9
|
+
method_name_as_var = method_name.to_s.tr('=', '_setter_')
|
|
10
|
+
instance_eval do
|
|
11
|
+
alias_method "#{method_name_as_var}_without_warning", method_name
|
|
12
|
+
end
|
|
13
|
+
warning = "#{method_name} is deprecated and will be removed from Rpush #{version}."
|
|
14
|
+
warning << " #{msg}" if msg
|
|
15
|
+
class_eval(<<-RUBY, __FILE__, __LINE__)
|
|
16
|
+
def #{method_name}(*args, &blk)
|
|
17
|
+
Rpush::Deprecation.warn_with_backtrace(#{warning.inspect})
|
|
18
|
+
#{method_name_as_var}_without_warning(*args, &blk)
|
|
19
|
+
end
|
|
20
|
+
RUBY
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Rpush
|
|
2
|
+
class Deprecation
|
|
3
|
+
def self.muted
|
|
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
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.muted?
|
|
12
|
+
Thread.current[:rpush_mute_deprecations] == true
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.warn(msg)
|
|
16
|
+
return if Rpush::Deprecation.muted?
|
|
17
|
+
STDERR.puts "DEPRECATION WARNING: #{msg}"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.warn_with_backtrace(msg)
|
|
21
|
+
return if Rpush::Deprecation.muted?
|
|
22
|
+
trace = "\n\nCALLED FROM:\n" + caller.join("\n")
|
|
23
|
+
warn(msg + trace)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|