ably 0.8.15 → 1.0.0
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 +4 -4
- data/.travis.yml +6 -4
- data/CHANGELOG.md +6 -2
- data/README.md +5 -1
- data/SPEC.md +1473 -852
- data/ably.gemspec +11 -8
- data/lib/ably/auth.rb +90 -53
- data/lib/ably/exceptions.rb +37 -8
- data/lib/ably/logger.rb +10 -1
- data/lib/ably/models/auth_details.rb +42 -0
- data/lib/ably/models/channel_state_change.rb +18 -4
- data/lib/ably/models/connection_details.rb +6 -3
- data/lib/ably/models/connection_state_change.rb +4 -3
- data/lib/ably/models/error_info.rb +1 -1
- data/lib/ably/models/message.rb +17 -1
- data/lib/ably/models/message_encoders/base.rb +103 -82
- data/lib/ably/models/message_encoders/base64.rb +1 -1
- data/lib/ably/models/presence_message.rb +16 -1
- data/lib/ably/models/protocol_message.rb +20 -3
- data/lib/ably/models/token_details.rb +11 -1
- data/lib/ably/models/token_request.rb +16 -6
- data/lib/ably/modules/async_wrapper.rb +7 -3
- data/lib/ably/modules/encodeable.rb +51 -12
- data/lib/ably/modules/enum.rb +17 -7
- data/lib/ably/modules/event_emitter.rb +29 -14
- data/lib/ably/modules/model_common.rb +13 -21
- data/lib/ably/modules/state_emitter.rb +7 -4
- data/lib/ably/modules/state_machine.rb +2 -4
- data/lib/ably/modules/uses_state_machine.rb +7 -3
- data/lib/ably/realtime.rb +2 -0
- data/lib/ably/realtime/auth.rb +102 -42
- data/lib/ably/realtime/channel.rb +68 -26
- data/lib/ably/realtime/channel/channel_manager.rb +154 -65
- data/lib/ably/realtime/channel/channel_state_machine.rb +14 -15
- data/lib/ably/realtime/client.rb +18 -3
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +38 -29
- data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +6 -1
- data/lib/ably/realtime/connection.rb +108 -49
- data/lib/ably/realtime/connection/connection_manager.rb +167 -61
- data/lib/ably/realtime/connection/connection_state_machine.rb +22 -3
- data/lib/ably/realtime/connection/websocket_transport.rb +19 -10
- data/lib/ably/realtime/presence.rb +70 -45
- data/lib/ably/realtime/presence/members_map.rb +201 -36
- data/lib/ably/realtime/presence/presence_manager.rb +30 -6
- data/lib/ably/realtime/presence/presence_state_machine.rb +5 -12
- data/lib/ably/rest.rb +2 -2
- data/lib/ably/rest/channel.rb +5 -5
- data/lib/ably/rest/client.rb +31 -27
- data/lib/ably/rest/middleware/exceptions.rb +1 -3
- data/lib/ably/rest/middleware/logger.rb +2 -2
- data/lib/ably/rest/presence.rb +2 -2
- data/lib/ably/util/pub_sub.rb +1 -1
- data/lib/ably/util/safe_deferrable.rb +26 -0
- data/lib/ably/version.rb +2 -2
- data/spec/acceptance/realtime/auth_spec.rb +470 -111
- data/spec/acceptance/realtime/channel_history_spec.rb +5 -3
- data/spec/acceptance/realtime/channel_spec.rb +1017 -168
- data/spec/acceptance/realtime/client_spec.rb +6 -6
- data/spec/acceptance/realtime/connection_failures_spec.rb +458 -27
- data/spec/acceptance/realtime/connection_spec.rb +424 -105
- data/spec/acceptance/realtime/message_spec.rb +52 -23
- data/spec/acceptance/realtime/presence_history_spec.rb +5 -3
- data/spec/acceptance/realtime/presence_spec.rb +1110 -96
- data/spec/acceptance/rest/auth_spec.rb +222 -59
- data/spec/acceptance/rest/base_spec.rb +1 -1
- data/spec/acceptance/rest/channel_spec.rb +1 -2
- data/spec/acceptance/rest/client_spec.rb +104 -48
- data/spec/acceptance/rest/message_spec.rb +42 -15
- data/spec/acceptance/rest/presence_spec.rb +4 -11
- data/spec/rspec_config.rb +2 -1
- data/spec/shared/client_initializer_behaviour.rb +2 -2
- data/spec/shared/safe_deferrable_behaviour.rb +6 -2
- data/spec/spec_helper.rb +4 -2
- data/spec/support/debug_failure_helper.rb +20 -4
- data/spec/support/event_machine_helper.rb +32 -1
- data/spec/unit/auth_spec.rb +4 -11
- data/spec/unit/logger_spec.rb +28 -2
- data/spec/unit/models/auth_details_spec.rb +49 -0
- data/spec/unit/models/channel_state_change_spec.rb +23 -3
- data/spec/unit/models/connection_details_spec.rb +12 -1
- data/spec/unit/models/connection_state_change_spec.rb +15 -4
- data/spec/unit/models/message_encoders/base64_spec.rb +2 -1
- data/spec/unit/models/message_spec.rb +153 -0
- data/spec/unit/models/presence_message_spec.rb +192 -0
- data/spec/unit/models/protocol_message_spec.rb +64 -6
- data/spec/unit/models/token_details_spec.rb +75 -0
- data/spec/unit/models/token_request_spec.rb +74 -0
- data/spec/unit/modules/async_wrapper_spec.rb +2 -1
- data/spec/unit/modules/enum_spec.rb +69 -0
- data/spec/unit/modules/event_emitter_spec.rb +149 -22
- data/spec/unit/modules/state_emitter_spec.rb +9 -3
- data/spec/unit/realtime/client_spec.rb +1 -1
- data/spec/unit/realtime/connection_spec.rb +8 -5
- data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +1 -1
- data/spec/unit/realtime/presence_spec.rb +4 -3
- data/spec/unit/rest/client_spec.rb +1 -1
- data/spec/unit/util/crypto_spec.rb +3 -3
- metadata +22 -19
data/ably.gemspec
CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_runtime_dependency 'em-http-request', '~> 1.1'
|
23
23
|
spec.add_runtime_dependency 'statesman', '~> 1.0.0'
|
24
24
|
spec.add_runtime_dependency 'faraday', '~> 0.9'
|
25
|
+
|
25
26
|
if RUBY_VERSION.match(/^1/)
|
26
27
|
spec.add_runtime_dependency 'json', '< 2.0'
|
27
28
|
else
|
@@ -32,16 +33,18 @@ Gem::Specification.new do |spec|
|
|
32
33
|
spec.add_runtime_dependency 'addressable', '>= 2.0.0'
|
33
34
|
|
34
35
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
35
|
-
spec.add_development_dependency 'rake'
|
36
|
-
spec.add_development_dependency 'redcarpet'
|
36
|
+
spec.add_development_dependency 'rake', '~> 11.3'
|
37
|
+
spec.add_development_dependency 'redcarpet', '~> 3.3'
|
37
38
|
spec.add_development_dependency 'rspec', '~> 3.2.0' # version lock, see config.around(:example, :event_machine) in event_machine_helper.rb
|
38
|
-
spec.add_development_dependency 'rspec-retry'
|
39
|
-
spec.add_development_dependency 'yard'
|
40
|
-
spec.add_development_dependency 'webmock', '~> 2.3.0'
|
41
|
-
|
42
|
-
spec.add_development_dependency 'coveralls'
|
39
|
+
spec.add_development_dependency 'rspec-retry', '~> 0.4'
|
40
|
+
spec.add_development_dependency 'yard', '~> 0.9'
|
43
41
|
|
44
|
-
|
42
|
+
if RUBY_VERSION.match(/^1/)
|
43
|
+
spec.add_development_dependency 'public_suffix', '~> 1.4.6' # Later versions do not support Ruby 1.9
|
44
|
+
spec.add_development_dependency 'webmock', '2.2'
|
45
|
+
else
|
46
|
+
spec.add_development_dependency 'webmock', '~> 2.2'
|
47
|
+
spec.add_development_dependency 'coveralls'
|
45
48
|
spec.add_development_dependency 'pry'
|
46
49
|
spec.add_development_dependency 'pry-byebug'
|
47
50
|
end
|
data/lib/ably/auth.rb
CHANGED
@@ -30,11 +30,11 @@ module Ably
|
|
30
30
|
|
31
31
|
# Default capability Hash object and TTL in seconds for issued tokens
|
32
32
|
TOKEN_DEFAULTS = {
|
33
|
-
capability: { '*' => ['*'] },
|
34
|
-
ttl: 60 * 60, # 1 hour in seconds
|
35
33
|
renew_token_buffer: 10 # buffer to allow a token to be reissued before the token is considered expired (Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER)
|
36
34
|
}.freeze
|
37
35
|
|
36
|
+
API_KEY_REGEX = /^[\w-]{2,}\.[\w-]{2,}:[\w-]{2,}$/
|
37
|
+
|
38
38
|
attr_reader :options, :token_params, :current_token_details
|
39
39
|
alias_method :auth_options, :options
|
40
40
|
|
@@ -65,8 +65,6 @@ module Ably
|
|
65
65
|
@token_params = token_params.dup
|
66
66
|
@token_option = options[:token] || options[:token_details]
|
67
67
|
|
68
|
-
@options.delete :force # Forcing token auth for every request is not a valid default
|
69
|
-
|
70
68
|
if options[:key] && (options[:key_secret] || options[:key_name])
|
71
69
|
raise ArgumentError, 'key and key_name or key_secret are mutually exclusive. Provider either a key or key_name & key_secret'
|
72
70
|
end
|
@@ -79,7 +77,7 @@ module Ably
|
|
79
77
|
end
|
80
78
|
|
81
79
|
if options[:client_id] == '*'
|
82
|
-
raise ArgumentError, 'A client cannot be configured with a wildcard client_id'
|
80
|
+
raise ArgumentError, 'A client cannot be configured with a wildcard client_id, only a token can have a wildcard client_id privilege'
|
83
81
|
end
|
84
82
|
|
85
83
|
if has_client_id? && !token_creatable_externally? && !token_option
|
@@ -88,12 +86,16 @@ module Ably
|
|
88
86
|
end
|
89
87
|
|
90
88
|
# If a token details object or token string is provided in the initializer
|
91
|
-
# then the client can be
|
89
|
+
# then the client can be authorized immediately using this token
|
92
90
|
if token_option
|
93
91
|
token_details = convert_to_token_details(token_option)
|
94
92
|
if token_details
|
95
|
-
|
96
|
-
|
93
|
+
begin
|
94
|
+
token_details = authorize_with_token(token_details)
|
95
|
+
logger.debug { "Auth: new token passed in to the initializer: #{token_details}" }
|
96
|
+
rescue StandardError => e
|
97
|
+
logger.error { "Auth: Implicit authorization using the provided token failed: #{e}" }
|
98
|
+
end
|
97
99
|
end
|
98
100
|
end
|
99
101
|
|
@@ -107,7 +109,6 @@ module Ably
|
|
107
109
|
#
|
108
110
|
# @param [Hash, nil] token_params the token params used for future token requests. When nil, previously configured token params are used
|
109
111
|
# @param [Hash, nil] auth_options the authentication options used for future token requests. When nil, previously configure authentication options are used
|
110
|
-
# @option auth_options [Boolean] :force obtains a new token even if the current token is valid. If the provided +auth_options+ Hash contains only this +:force+ attribute, the existing configured authentication options are not overwriten
|
111
112
|
# @option (see #request_token)
|
112
113
|
#
|
113
114
|
# @return (see #create_token_request)
|
@@ -115,23 +116,29 @@ module Ably
|
|
115
116
|
# @example
|
116
117
|
# # will issue a simple token request using basic auth
|
117
118
|
# client = Ably::Rest::Client.new(key: 'key.id:secret')
|
118
|
-
# token_details = client.auth.
|
119
|
+
# token_details = client.auth.authorize
|
119
120
|
#
|
120
|
-
# # will use token request from block to
|
121
|
-
# token_details = client.auth.
|
121
|
+
# # will use token request from block to authorize if not already authorized
|
122
|
+
# token_details = client.auth.authorize {}, auth_callback: Proc.new do
|
122
123
|
# # create token_request object
|
123
124
|
# token_request
|
124
125
|
# end
|
125
126
|
#
|
126
|
-
def
|
127
|
-
if auth_options
|
128
|
-
auth_options = options
|
129
|
-
|
130
|
-
|
127
|
+
def authorize(token_params = nil, auth_options = nil)
|
128
|
+
if auth_options.nil?
|
129
|
+
auth_options = options # Use default options
|
130
|
+
|
131
|
+
if options.has_key?(:query_time)
|
132
|
+
@options = options.dup
|
133
|
+
# Query the server time only happens once
|
134
|
+
# the options remain in auth_options though so they are passed to request_token
|
135
|
+
@options.delete(:query_time)
|
136
|
+
@options.freeze
|
137
|
+
end
|
131
138
|
else
|
132
139
|
ensure_valid_auth_attributes auth_options
|
133
140
|
|
134
|
-
auth_options = auth_options.
|
141
|
+
auth_options = auth_options.dup
|
135
142
|
|
136
143
|
if auth_options[:token_params]
|
137
144
|
token_params = auth_options.delete(:token_params).merge(token_params || {})
|
@@ -144,36 +151,39 @@ module Ably
|
|
144
151
|
store_and_delete_basic_auth_key_from_options! auth_options
|
145
152
|
end
|
146
153
|
|
147
|
-
@options = auth_options.
|
154
|
+
@options = auth_options.dup
|
148
155
|
|
149
|
-
#
|
150
|
-
# the
|
156
|
+
# Query the server time only happens once
|
157
|
+
# the options remain in auth_options though so they are passed to request_token
|
151
158
|
@options.delete(:query_time)
|
152
|
-
@options.delete(:force)
|
153
159
|
|
154
160
|
@options.freeze
|
155
161
|
end
|
156
162
|
|
163
|
+
# Unless provided, defaults are used
|
157
164
|
unless token_params.nil?
|
158
|
-
@token_params = token_params
|
165
|
+
@token_params = token_params.dup
|
166
|
+
# Timestamp is only valid for this request
|
167
|
+
@token_params.delete(:timestamp)
|
159
168
|
@token_params.freeze
|
160
169
|
end
|
161
170
|
|
162
|
-
|
163
|
-
|
164
|
-
end
|
171
|
+
authorize_with_token(request_token(token_params || @token_params, auth_options)).tap do |new_token_details|
|
172
|
+
logger.debug { "Auth: new token following authorisation: #{new_token_details}" }
|
165
173
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
# If authorise was forced allow a block to be called so that the realtime library
|
170
|
-
# can force upgrade the authorisation
|
171
|
-
if auth_options[:force] && block_given?
|
174
|
+
# If authorize the realtime library required auth, then yield the token in a block
|
175
|
+
if block_given?
|
172
176
|
yield new_token_details
|
173
177
|
end
|
174
178
|
end
|
175
179
|
end
|
176
180
|
|
181
|
+
# @deprecated Use {#authorize} instead
|
182
|
+
def authorise(*args, &block)
|
183
|
+
logger.warn { "Auth#authorise is deprecated and will be removed in 1.0. Please use Auth#authorize instead" }
|
184
|
+
authorize(*args, &block)
|
185
|
+
end
|
186
|
+
|
177
187
|
# Request a {Ably::Models::TokenDetails} which can be used to make authenticated token based requests
|
178
188
|
#
|
179
189
|
# @param [Hash] auth_options (see #create_token_request)
|
@@ -216,9 +226,21 @@ module Ably
|
|
216
226
|
auth_options = self.options.merge(auth_options)
|
217
227
|
|
218
228
|
token_request = if auth_callback = auth_options.delete(:auth_callback)
|
219
|
-
|
229
|
+
begin
|
230
|
+
Timeout::timeout(client.auth_request_timeout) do
|
231
|
+
auth_callback.call(token_params)
|
232
|
+
end
|
233
|
+
rescue StandardError => err
|
234
|
+
raise Ably::Exceptions::AuthenticationFailed.new("auth_callback failed: #{err.message}", nil, nil, err, fallback_status: 500, fallback_code: 80019)
|
235
|
+
end
|
220
236
|
elsif auth_url = auth_options.delete(:auth_url)
|
221
|
-
|
237
|
+
begin
|
238
|
+
Timeout::timeout(client.auth_request_timeout) do
|
239
|
+
token_request_from_auth_url(auth_url, auth_options, token_params)
|
240
|
+
end
|
241
|
+
rescue StandardError => err
|
242
|
+
raise Ably::Exceptions::AuthenticationFailed.new("auth_url failed: #{err.message}", nil, nil, err, fallback_status: 500, fallback_code: 80019)
|
243
|
+
end
|
222
244
|
else
|
223
245
|
create_token_request(token_params, auth_options)
|
224
246
|
end
|
@@ -263,7 +285,7 @@ module Ably
|
|
263
285
|
def create_token_request(token_params = {}, auth_options = {})
|
264
286
|
ensure_valid_auth_attributes auth_options
|
265
287
|
|
266
|
-
auth_options = auth_options.
|
288
|
+
auth_options = auth_options.dup
|
267
289
|
token_params = (auth_options[:token_params] || {}).merge(token_params)
|
268
290
|
|
269
291
|
split_api_key_into_key_and_secret! auth_options if auth_options[:key]
|
@@ -276,20 +298,26 @@ module Ably
|
|
276
298
|
timestamp = token_params.delete(:timestamp) || current_time
|
277
299
|
timestamp = Time.at(timestamp) if timestamp.kind_of?(Integer)
|
278
300
|
|
279
|
-
|
280
|
-
(token_params[:ttl] || TOKEN_DEFAULTS.fetch(:ttl)),
|
281
|
-
Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER + TOKEN_DEFAULTS.fetch(:renew_token_buffer) # never issue a token that will be immediately considered expired due to the buffer
|
282
|
-
].max
|
301
|
+
|
283
302
|
|
284
303
|
token_request = {
|
285
304
|
keyName: request_key_name,
|
286
|
-
clientId: token_params[:client_id] || auth_options[:client_id] || client_id,
|
287
|
-
ttl: (ttl * 1000).to_i,
|
288
305
|
timestamp: (timestamp.to_f * 1000).round,
|
289
|
-
capability: token_params[:capability] || TOKEN_DEFAULTS.fetch(:capability),
|
290
306
|
nonce: token_params[:nonce] || SecureRandom.hex.force_encoding('UTF-8')
|
291
307
|
}
|
292
308
|
|
309
|
+
token_client_id = token_params[:client_id] || auth_options[:client_id] || client_id
|
310
|
+
token_request[:clientId] = token_client_id if token_client_id
|
311
|
+
|
312
|
+
if token_params[:ttl]
|
313
|
+
token_ttl = [
|
314
|
+
token_params[:ttl],
|
315
|
+
Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER + TOKEN_DEFAULTS.fetch(:renew_token_buffer) # never issue a token that will be immediately considered expired due to the buffer
|
316
|
+
].max
|
317
|
+
token_request[:ttl] = (token_ttl * 1000).to_i
|
318
|
+
end
|
319
|
+
|
320
|
+
token_request[:capability] = token_params[:capability] if token_params[:capability]
|
293
321
|
if token_request[:capability].is_a?(Hash)
|
294
322
|
lexicographic_ordered_capabilities = Hash[
|
295
323
|
token_request[:capability].sort_by { |key, value| key }.map do |key, value|
|
@@ -347,7 +375,7 @@ module Ably
|
|
347
375
|
end
|
348
376
|
|
349
377
|
# Auth header string used in HTTP requests to Ably
|
350
|
-
# Will
|
378
|
+
# Will reauthorize implicitly if required and capable
|
351
379
|
#
|
352
380
|
# @return [String] HTTP authentication value used in HTTP_AUTHORIZATION header
|
353
381
|
def auth_header
|
@@ -359,7 +387,7 @@ module Ably
|
|
359
387
|
end
|
360
388
|
|
361
389
|
# Auth params used in URI endpoint for Realtime connections
|
362
|
-
# Will
|
390
|
+
# Will reauthorize implicitly if required and capable
|
363
391
|
#
|
364
392
|
# @return [Hash] Auth params for a new Realtime connection
|
365
393
|
def auth_params
|
@@ -427,7 +455,7 @@ module Ably
|
|
427
455
|
|
428
456
|
# If client_id is defined and not a wildcard, prevent it changing, this is not supported
|
429
457
|
if client_id && client_id != '*' && new_client_id != client_id
|
430
|
-
raise Ably::Exceptions::IncompatibleClientId.new("Client ID is immutable once configured for a client. Client ID cannot be changed to '#{new_client_id}'"
|
458
|
+
raise Ably::Exceptions::IncompatibleClientId.new("Client ID is immutable once configured for a client. Client ID cannot be changed to '#{new_client_id}'")
|
431
459
|
end
|
432
460
|
@client_id_validated = true
|
433
461
|
@client_id = new_client_id
|
@@ -449,6 +477,14 @@ module Ably
|
|
449
477
|
@token_option
|
450
478
|
end
|
451
479
|
|
480
|
+
def authorize_when_necessary
|
481
|
+
if current_token_details && !current_token_details.expired?
|
482
|
+
return current_token_details
|
483
|
+
else
|
484
|
+
authorize
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
452
488
|
# Returns the current device clock time unless the
|
453
489
|
# the server time has previously been requested with query_time: true
|
454
490
|
# and the @server_time_offset is configured
|
@@ -530,16 +566,17 @@ module Ably
|
|
530
566
|
@key_secret = options.delete(:key_secret)
|
531
567
|
end
|
532
568
|
|
533
|
-
# Returns the current token if it exists or
|
569
|
+
# Returns the current token if it exists or authorizes and retrieves a token
|
534
570
|
def token_auth_string
|
535
571
|
if !current_token_details && token_option
|
572
|
+
logger.debug { "Auth: Token auth string missing, authorizing implicitly now" }
|
536
573
|
# A TokenRequest was configured in the ClientOptions +:token field+ and no current token exists
|
537
574
|
# Note: If a Token or TokenDetails is provided in the initializer, the token is stored in +current_token_details+
|
538
|
-
|
575
|
+
authorize_with_token send_token_request(token_option)
|
539
576
|
current_token_details.token
|
540
577
|
else
|
541
|
-
#
|
542
|
-
|
578
|
+
# Authorize will use the current token if one exists and is not expired, otherwise a new token will be issued
|
579
|
+
authorize_when_necessary.token
|
543
580
|
end
|
544
581
|
end
|
545
582
|
|
@@ -587,7 +624,7 @@ module Ably
|
|
587
624
|
)
|
588
625
|
end
|
589
626
|
|
590
|
-
# Retrieve a token request from a specified URL, expects a JSON response
|
627
|
+
# Retrieve a token request from a specified URL, expects a JSON or text response
|
591
628
|
#
|
592
629
|
# @return [Hash]
|
593
630
|
def token_request_from_auth_url(auth_url, auth_options, token_params)
|
@@ -615,10 +652,10 @@ module Ably
|
|
615
652
|
end
|
616
653
|
|
617
654
|
# Use the provided token to authenticate immediately and store the token details in +current_token_details+
|
618
|
-
def
|
655
|
+
def authorize_with_token(new_token_details)
|
619
656
|
if new_token_details && !new_token_details.from_token_string?
|
620
657
|
if !token_client_id_allowed?(new_token_details.client_id)
|
621
|
-
raise Ably::Exceptions::IncompatibleClientId.new("Client ID '#{new_token_details.client_id}' in the token is incompatible with the current client ID '#{client_id}'"
|
658
|
+
raise Ably::Exceptions::IncompatibleClientId.new("Client ID '#{new_token_details.client_id}' in the token is incompatible with the current client ID '#{client_id}'")
|
622
659
|
end
|
623
660
|
configure_client_id new_token_details.client_id
|
624
661
|
end
|
@@ -645,7 +682,7 @@ module Ably
|
|
645
682
|
|
646
683
|
response = client.post("/keys/#{token_request.key_name}/requestToken",
|
647
684
|
token_request.attributes, send_auth_header: false,
|
648
|
-
|
685
|
+
disable_automatic_reauthorize: true)
|
649
686
|
|
650
687
|
Ably::Models::TokenDetails.new(response.body)
|
651
688
|
end
|
data/lib/ably/exceptions.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
module Ably
|
2
2
|
module Exceptions
|
3
|
+
TOKEN_EXPIRED_CODE = 40140..40149
|
4
|
+
INVALID_CLIENT_ID = 40012
|
5
|
+
|
3
6
|
# Base Ably exception class that contains status and code values used by Ably
|
4
7
|
# Refer to https://github.com/ably/ably-common/blob/master/protocol/errors.json
|
5
8
|
#
|
@@ -11,10 +14,17 @@ module Ably
|
|
11
14
|
# @return [String] Ably specific error code
|
12
15
|
class BaseAblyException < StandardError
|
13
16
|
attr_reader :status, :code
|
14
|
-
|
17
|
+
|
18
|
+
def initialize(message, status = nil, code = nil, base_exception = nil, options = {})
|
15
19
|
super message
|
20
|
+
|
21
|
+
@base_exception = base_exception
|
16
22
|
@status = status
|
23
|
+
@status ||= base_exception.status if base_exception && base_exception.respond_to?(:status)
|
24
|
+
@status ||= options[:fallback_status]
|
17
25
|
@code = code
|
26
|
+
@code ||= base_exception.code if base_exception && base_exception.respond_to?(:code)
|
27
|
+
@code ||= options[:fallback_code]
|
18
28
|
end
|
19
29
|
|
20
30
|
def to_s
|
@@ -23,10 +33,19 @@ module Ably
|
|
23
33
|
additional_info = []
|
24
34
|
additional_info << "code: #{code}" if code
|
25
35
|
additional_info << "http status: #{status}" if status
|
36
|
+
additional_info << "base exception: #{@base_exception.class}" if @base_exception
|
26
37
|
message << "(#{additional_info.join(', ')})"
|
27
38
|
end
|
28
39
|
message.join(' ')
|
29
40
|
end
|
41
|
+
|
42
|
+
def as_json
|
43
|
+
{
|
44
|
+
message: "#{self.class}: #{message}",
|
45
|
+
status: @status,
|
46
|
+
code: @code
|
47
|
+
}.delete_if { |key, val| val.nil? }
|
48
|
+
end
|
30
49
|
end
|
31
50
|
|
32
51
|
# An invalid request was received by Ably
|
@@ -52,16 +71,15 @@ module Ably
|
|
52
71
|
|
53
72
|
# Connection error from Realtime or REST service
|
54
73
|
class ConnectionError < BaseAblyException
|
55
|
-
def initialize(message, status = nil, code = nil,
|
56
|
-
super message, status, code
|
57
|
-
@base_error = base_error
|
74
|
+
def initialize(message, status = nil, code = nil, base_exception = nil, options = {})
|
75
|
+
super message, status, code, base_exception, options
|
58
76
|
end
|
59
77
|
|
60
78
|
def to_s
|
61
79
|
message = [super]
|
62
|
-
if @
|
63
|
-
message << "#{@
|
64
|
-
if @
|
80
|
+
if @base_exception
|
81
|
+
message << "#{@base_exception}"
|
82
|
+
if @base_exception.respond_to?(:message) && @base_exception.message.match(/certificate verify failed/i)
|
65
83
|
message << "See https://goo.gl/eKvfcR to resolve this issue."
|
66
84
|
end
|
67
85
|
end
|
@@ -84,9 +102,13 @@ module Ably
|
|
84
102
|
# Connection failed
|
85
103
|
class ConnectionFailed < ConnectionError; end
|
86
104
|
|
105
|
+
class AuthenticationFailed < ConnectionError; end
|
106
|
+
|
87
107
|
# Invalid State Change error on a {https://github.com/gocardless/statesman Statesman State Machine}
|
88
108
|
class InvalidStateChange < BaseAblyException; end
|
89
109
|
|
110
|
+
class InvalidState < BaseAblyException; end
|
111
|
+
|
90
112
|
# A generic Ably exception taht supports a status & code.
|
91
113
|
# See https://github.com/ably/ably-common/blob/master/protocol/errors.json for a list of Ably errors
|
92
114
|
class Standard < BaseAblyException; end
|
@@ -121,6 +143,13 @@ module Ably
|
|
121
143
|
# When a channel is detached / failed, certain operations are not permitted such as publishing messages
|
122
144
|
class ChannelInactive < BaseAblyException; end
|
123
145
|
|
124
|
-
class IncompatibleClientId < BaseAblyException
|
146
|
+
class IncompatibleClientId < BaseAblyException
|
147
|
+
def initialize(messages, status = 400, code = INVALID_CLIENT_ID, *args)
|
148
|
+
super(message, status, code, *args)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Token request has missing or invalid attributes
|
153
|
+
class InvalidTokenRequest < BaseAblyException; end
|
125
154
|
end
|
126
155
|
end
|
data/lib/ably/logger.rb
CHANGED
@@ -34,7 +34,16 @@ module Ably
|
|
34
34
|
# @return {Integer}
|
35
35
|
attr_reader :log_level
|
36
36
|
|
37
|
-
|
37
|
+
# Catch exceptiosn in blocks passed to the logger, log the error and continue
|
38
|
+
%w(fatal error warn info debug).each do |method_name|
|
39
|
+
define_method(method_name) do |*args, &block|
|
40
|
+
begin
|
41
|
+
logger.public_send(method_name, *args, &block)
|
42
|
+
rescue StandardError => e
|
43
|
+
logger.error "Logger: Failed to log #{method_name} block - #{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
38
47
|
|
39
48
|
private
|
40
49
|
def client
|