ably-rest 0.9.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ably-rest.gemspec +2 -1
- data/lib/submodules/ably-ruby/.travis.yml +6 -4
- data/lib/submodules/ably-ruby/CHANGELOG.md +52 -61
- data/lib/submodules/ably-ruby/README.md +10 -0
- data/lib/submodules/ably-ruby/SPEC.md +1473 -852
- data/lib/submodules/ably-ruby/ably.gemspec +2 -1
- data/lib/submodules/ably-ruby/lib/ably/auth.rb +57 -25
- data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +34 -8
- data/lib/submodules/ably-ruby/lib/ably/logger.rb +10 -1
- data/lib/submodules/ably-ruby/lib/ably/models/auth_details.rb +42 -0
- data/lib/submodules/ably-ruby/lib/ably/models/channel_state_change.rb +18 -4
- data/lib/submodules/ably-ruby/lib/ably/models/connection_details.rb +6 -3
- data/lib/submodules/ably-ruby/lib/ably/models/connection_state_change.rb +4 -3
- data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/models/message.rb +12 -1
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base.rb +101 -97
- data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +13 -1
- data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +20 -3
- data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +7 -3
- data/lib/submodules/ably-ruby/lib/ably/modules/enum.rb +17 -7
- data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +29 -14
- data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +7 -4
- data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +2 -4
- data/lib/submodules/ably-ruby/lib/ably/modules/uses_state_machine.rb +7 -3
- data/lib/submodules/ably-ruby/lib/ably/realtime.rb +2 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +79 -31
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +62 -26
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +154 -65
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +14 -15
- data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +16 -3
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +38 -29
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +6 -1
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +108 -49
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +165 -59
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +22 -3
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +19 -10
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +67 -45
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence/members_map.rb +198 -36
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence/presence_manager.rb +30 -6
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence/presence_state_machine.rb +5 -12
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +3 -3
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +21 -8
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +1 -3
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/logger.rb +2 -2
- data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/util/pub_sub.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/util/safe_deferrable.rb +26 -0
- data/lib/submodules/ably-ruby/lib/ably/version.rb +2 -2
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +416 -99
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +5 -3
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +1011 -160
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +2 -2
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +458 -27
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +436 -97
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +52 -23
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +5 -3
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +1160 -105
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +151 -22
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +88 -27
- data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +42 -15
- data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +4 -4
- data/lib/submodules/ably-ruby/spec/rspec_config.rb +2 -1
- data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +2 -2
- data/lib/submodules/ably-ruby/spec/shared/safe_deferrable_behaviour.rb +6 -2
- data/lib/submodules/ably-ruby/spec/support/debug_failure_helper.rb +20 -4
- data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +32 -1
- data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +4 -11
- data/lib/submodules/ably-ruby/spec/unit/logger_spec.rb +28 -2
- data/lib/submodules/ably-ruby/spec/unit/models/auth_details_spec.rb +49 -0
- data/lib/submodules/ably-ruby/spec/unit/models/channel_state_change_spec.rb +23 -3
- data/lib/submodules/ably-ruby/spec/unit/models/connection_details_spec.rb +12 -1
- data/lib/submodules/ably-ruby/spec/unit/models/connection_state_change_spec.rb +15 -4
- data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +34 -2
- data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +73 -2
- data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +64 -6
- data/lib/submodules/ably-ruby/spec/unit/models/token_details_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/models/token_request_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +2 -1
- data/lib/submodules/ably-ruby/spec/unit/modules/enum_spec.rb +69 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +149 -22
- data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +9 -3
- data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +8 -5
- data/lib/submodules/ably-ruby/spec/unit/realtime/incoming_message_dispatcher_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +4 -3
- data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/util/crypto_spec.rb +3 -3
- metadata +7 -5
@@ -38,11 +38,12 @@ Gem::Specification.new do |spec|
|
|
38
38
|
spec.add_development_dependency 'rspec', '~> 3.2.0' # version lock, see config.around(:example, :event_machine) in event_machine_helper.rb
|
39
39
|
spec.add_development_dependency 'rspec-retry', '~> 0.4'
|
40
40
|
spec.add_development_dependency 'yard', '~> 0.9'
|
41
|
-
spec.add_development_dependency 'webmock', '~> 2.0'
|
42
41
|
|
43
42
|
if RUBY_VERSION.match(/^1/)
|
44
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
45
|
else
|
46
|
+
spec.add_development_dependency 'webmock', '~> 2.2'
|
46
47
|
spec.add_development_dependency 'coveralls'
|
47
48
|
spec.add_development_dependency 'pry'
|
48
49
|
spec.add_development_dependency 'pry-byebug'
|
@@ -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
|
|
@@ -77,7 +77,7 @@ module Ably
|
|
77
77
|
end
|
78
78
|
|
79
79
|
if options[:client_id] == '*'
|
80
|
-
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'
|
81
81
|
end
|
82
82
|
|
83
83
|
if has_client_id? && !token_creatable_externally? && !token_option
|
@@ -90,8 +90,12 @@ module Ably
|
|
90
90
|
if token_option
|
91
91
|
token_details = convert_to_token_details(token_option)
|
92
92
|
if token_details
|
93
|
-
|
94
|
-
|
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
|
95
99
|
end
|
96
100
|
end
|
97
101
|
|
@@ -123,10 +127,18 @@ module Ably
|
|
123
127
|
def authorize(token_params = nil, auth_options = nil)
|
124
128
|
if auth_options.nil?
|
125
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
|
126
138
|
else
|
127
139
|
ensure_valid_auth_attributes auth_options
|
128
140
|
|
129
|
-
auth_options = auth_options.
|
141
|
+
auth_options = auth_options.dup
|
130
142
|
|
131
143
|
if auth_options[:token_params]
|
132
144
|
token_params = auth_options.delete(:token_params).merge(token_params || {})
|
@@ -139,7 +151,7 @@ module Ably
|
|
139
151
|
store_and_delete_basic_auth_key_from_options! auth_options
|
140
152
|
end
|
141
153
|
|
142
|
-
@options = auth_options.
|
154
|
+
@options = auth_options.dup
|
143
155
|
|
144
156
|
# Query the server time only happens once
|
145
157
|
# the options remain in auth_options though so they are passed to request_token
|
@@ -150,12 +162,14 @@ module Ably
|
|
150
162
|
|
151
163
|
# Unless provided, defaults are used
|
152
164
|
unless token_params.nil?
|
153
|
-
@token_params = token_params
|
165
|
+
@token_params = token_params.dup
|
166
|
+
# Timestamp is only valid for this request
|
167
|
+
@token_params.delete(:timestamp)
|
154
168
|
@token_params.freeze
|
155
169
|
end
|
156
170
|
|
157
|
-
authorize_with_token(request_token(@token_params, auth_options)).tap do |new_token_details|
|
158
|
-
logger.debug "Auth: new token following authorisation: #{new_token_details}"
|
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}" }
|
159
173
|
|
160
174
|
# If authorize the realtime library required auth, then yield the token in a block
|
161
175
|
if block_given?
|
@@ -166,7 +180,7 @@ module Ably
|
|
166
180
|
|
167
181
|
# @deprecated Use {#authorize} instead
|
168
182
|
def authorise(*args, &block)
|
169
|
-
logger.warn "Auth#authorise is deprecated and will be removed in 1.0. Please use Auth#authorize instead"
|
183
|
+
logger.warn { "Auth#authorise is deprecated and will be removed in 1.0. Please use Auth#authorize instead" }
|
170
184
|
authorize(*args, &block)
|
171
185
|
end
|
172
186
|
|
@@ -212,9 +226,21 @@ module Ably
|
|
212
226
|
auth_options = self.options.merge(auth_options)
|
213
227
|
|
214
228
|
token_request = if auth_callback = auth_options.delete(:auth_callback)
|
215
|
-
|
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
|
216
236
|
elsif auth_url = auth_options.delete(:auth_url)
|
217
|
-
|
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
|
218
244
|
else
|
219
245
|
create_token_request(token_params, auth_options)
|
220
246
|
end
|
@@ -259,7 +285,7 @@ module Ably
|
|
259
285
|
def create_token_request(token_params = {}, auth_options = {})
|
260
286
|
ensure_valid_auth_attributes auth_options
|
261
287
|
|
262
|
-
auth_options = auth_options.
|
288
|
+
auth_options = auth_options.dup
|
263
289
|
token_params = (auth_options[:token_params] || {}).merge(token_params)
|
264
290
|
|
265
291
|
split_api_key_into_key_and_secret! auth_options if auth_options[:key]
|
@@ -272,20 +298,26 @@ module Ably
|
|
272
298
|
timestamp = token_params.delete(:timestamp) || current_time
|
273
299
|
timestamp = Time.at(timestamp) if timestamp.kind_of?(Integer)
|
274
300
|
|
275
|
-
|
276
|
-
(token_params[:ttl] || TOKEN_DEFAULTS.fetch(:ttl)),
|
277
|
-
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
|
278
|
-
].max
|
301
|
+
|
279
302
|
|
280
303
|
token_request = {
|
281
304
|
keyName: request_key_name,
|
282
|
-
clientId: token_params[:client_id] || auth_options[:client_id] || client_id,
|
283
|
-
ttl: (ttl * 1000).to_i,
|
284
305
|
timestamp: (timestamp.to_f * 1000).round,
|
285
|
-
capability: token_params[:capability] || TOKEN_DEFAULTS.fetch(:capability),
|
286
306
|
nonce: token_params[:nonce] || SecureRandom.hex.force_encoding('UTF-8')
|
287
307
|
}
|
288
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]
|
289
321
|
if token_request[:capability].is_a?(Hash)
|
290
322
|
lexicographic_ordered_capabilities = Hash[
|
291
323
|
token_request[:capability].sort_by { |key, value| key }.map do |key, value|
|
@@ -423,7 +455,7 @@ module Ably
|
|
423
455
|
|
424
456
|
# If client_id is defined and not a wildcard, prevent it changing, this is not supported
|
425
457
|
if client_id && client_id != '*' && new_client_id != client_id
|
426
|
-
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}'")
|
427
459
|
end
|
428
460
|
@client_id_validated = true
|
429
461
|
@client_id = new_client_id
|
@@ -537,7 +569,7 @@ module Ably
|
|
537
569
|
# Returns the current token if it exists or authorizes and retrieves a token
|
538
570
|
def token_auth_string
|
539
571
|
if !current_token_details && token_option
|
540
|
-
logger.debug "Auth: Token auth string missing, authorizing implicitly now"
|
572
|
+
logger.debug { "Auth: Token auth string missing, authorizing implicitly now" }
|
541
573
|
# A TokenRequest was configured in the ClientOptions +:token field+ and no current token exists
|
542
574
|
# Note: If a Token or TokenDetails is provided in the initializer, the token is stored in +current_token_details+
|
543
575
|
authorize_with_token send_token_request(token_option)
|
@@ -592,7 +624,7 @@ module Ably
|
|
592
624
|
)
|
593
625
|
end
|
594
626
|
|
595
|
-
# 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
|
596
628
|
#
|
597
629
|
# @return [Hash]
|
598
630
|
def token_request_from_auth_url(auth_url, auth_options, token_params)
|
@@ -623,7 +655,7 @@ module Ably
|
|
623
655
|
def authorize_with_token(new_token_details)
|
624
656
|
if new_token_details && !new_token_details.from_token_string?
|
625
657
|
if !token_client_id_allowed?(new_token_details.client_id)
|
626
|
-
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}'")
|
627
659
|
end
|
628
660
|
configure_client_id new_token_details.client_id
|
629
661
|
end
|
@@ -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,7 +143,11 @@ 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
|
125
151
|
|
126
152
|
# Token request has missing or invalid attributes
|
127
153
|
class InvalidTokenRequest < BaseAblyException; end
|
@@ -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
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Ably::Models
|
2
|
+
# Convert auth details attributes to a {AuthDetails} object
|
3
|
+
#
|
4
|
+
# @param attributes (see #initialize)
|
5
|
+
#
|
6
|
+
# @return [AuthDetails]
|
7
|
+
def self.AuthDetails(attributes)
|
8
|
+
case attributes
|
9
|
+
when AuthDetails
|
10
|
+
return attributes
|
11
|
+
else
|
12
|
+
AuthDetails.new(attributes || {})
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# AuthDetails are included in an +AUTH+ {Ably::Models::ProtocolMessage#auth} attribute
|
17
|
+
# to provide the realtime service with new token authentication details following a re-auth workflow
|
18
|
+
#
|
19
|
+
class AuthDetails
|
20
|
+
include Ably::Modules::ModelCommon
|
21
|
+
|
22
|
+
# @param attributes [Hash]
|
23
|
+
# @option attributes [String] :access_token token string
|
24
|
+
#
|
25
|
+
def initialize(attributes = {})
|
26
|
+
@hash_object = IdiomaticRubyWrapper(attributes.clone)
|
27
|
+
self.attributes.freeze
|
28
|
+
end
|
29
|
+
|
30
|
+
%w(access_token).each do |attribute|
|
31
|
+
define_method attribute do
|
32
|
+
attributes[attribute.to_sym]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# @!attribute [r] attributes
|
37
|
+
# @return [Hash] Access the token details Hash object ruby'fied to use symbolized keys
|
38
|
+
def attributes
|
39
|
+
@hash_object
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -8,31 +8,45 @@ module Ably::Models
|
|
8
8
|
# @return [Connection::STATE] Previous channel state
|
9
9
|
# @!attribute [r] reason
|
10
10
|
# @return [Ably::Models::ErrorInfo] Object describing the reason for a state change when not initiated by the consumer of the client library
|
11
|
+
# @!attribute [r] resumed
|
12
|
+
# @return [Boolean] True when a channel is resumed, false when continuity on the channel is no longer provided indicating that the developer is now responsible for recovering lost messages on this channel through other means, such as using the hisory API
|
11
13
|
#
|
12
14
|
class ChannelStateChange
|
13
15
|
include Ably::Modules::ModelCommon
|
14
16
|
|
15
17
|
def initialize(hash_object)
|
16
|
-
unless (hash_object.keys - [:current, :previous, :reason, :protocol_message]).empty?
|
17
|
-
raise ArgumentError, 'Invalid attributes, expecting :current, :previous, :reason'
|
18
|
+
unless (hash_object.keys - [:current, :previous, :event, :reason, :resumed, :protocol_message]).empty?
|
19
|
+
raise ArgumentError, 'Invalid attributes, expecting :current, :previous, :event, :reason, :resumed'
|
18
20
|
end
|
19
21
|
|
20
22
|
@hash_object = {
|
21
23
|
current: hash_object.fetch(:current),
|
22
24
|
previous: hash_object.fetch(:previous),
|
25
|
+
event: hash_object[:event],
|
23
26
|
reason: hash_object[:reason],
|
24
|
-
protocol_message: hash_object[:protocol_message]
|
27
|
+
protocol_message: hash_object[:protocol_message],
|
28
|
+
resumed: hash_object[:resumed]
|
25
29
|
}
|
26
30
|
rescue KeyError => e
|
27
31
|
raise ArgumentError, e
|
28
32
|
end
|
29
33
|
|
30
|
-
%w(current previous reason
|
34
|
+
%w(current previous event reason).each do |attribute|
|
31
35
|
define_method attribute do
|
32
36
|
@hash_object[attribute.to_sym]
|
33
37
|
end
|
34
38
|
end
|
35
39
|
|
40
|
+
def resumed
|
41
|
+
!!@hash_object[:resumed]
|
42
|
+
end
|
43
|
+
alias_method :resumed?, :resumed
|
44
|
+
|
45
|
+
# @api private
|
46
|
+
def protocol_message
|
47
|
+
@hash_object[:protocol_message]
|
48
|
+
end
|
49
|
+
|
36
50
|
def to_s
|
37
51
|
"ChannelStateChange: current state #{current}, previous state #{previous}"
|
38
52
|
end
|
@@ -27,18 +27,21 @@ module Ably::Models
|
|
27
27
|
# @option attributes [Integer] :max_message_size maximum individual message size in bytes
|
28
28
|
# @option attributes [Integer] :max_frame_size maximum size for a single frame of data sent to Ably. This restriction applies to a {Ably::Models::ProtocolMessage} sent over a realtime connection, or the total body size for a REST request
|
29
29
|
# @option attributes [Integer] :max_inbound_rate maximum allowable number of requests per second from a client
|
30
|
+
# @option attributes [Integer] :max_idle_interval is the maximum length of time in seconds that the server will allow no activity to occur in the server->client direction. After such a period of inactivity, the server will send a @HEARTBEAT@ or transport-level ping to the client. If the value is 0, the server will allow arbitrarily-long levels of inactivity.
|
30
31
|
# @option attributes [Integer] :connection_state_ttl duration in seconds that Ably will persist the connection state when a Realtime client is abruptly disconnected
|
31
32
|
# @option attributes [String] :server_id unique identifier of the Ably server where the connection is established
|
32
33
|
#
|
33
34
|
def initialize(attributes = {})
|
34
35
|
@hash_object = IdiomaticRubyWrapper(attributes.clone)
|
35
|
-
|
36
|
-
|
36
|
+
[:connection_state_ttl, :max_idle_interval].each do |duration_field|
|
37
|
+
if self.attributes[duration_field]
|
38
|
+
self.attributes[duration_field] = (self.attributes[duration_field].to_f / 1000).round
|
39
|
+
end
|
37
40
|
end
|
38
41
|
self.attributes.freeze
|
39
42
|
end
|
40
43
|
|
41
|
-
%w(client_id connection_key max_message_size max_frame_size max_inbound_rate connection_state_ttl server_id).each do |attribute|
|
44
|
+
%w(client_id connection_key max_message_size max_frame_size max_inbound_rate connection_state_ttl max_idle_interval server_id).each do |attribute|
|
42
45
|
define_method attribute do
|
43
46
|
attributes[attribute.to_sym]
|
44
47
|
end
|
@@ -15,13 +15,14 @@ module Ably::Models
|
|
15
15
|
include Ably::Modules::ModelCommon
|
16
16
|
|
17
17
|
def initialize(hash_object)
|
18
|
-
unless (hash_object.keys - [:current, :previous, :retry_in, :reason, :protocol_message]).empty?
|
19
|
-
raise ArgumentError, 'Invalid attributes, expecting :current, :previous, :retry_in, :reason'
|
18
|
+
unless (hash_object.keys - [:current, :previous, :event, :retry_in, :reason, :protocol_message]).empty?
|
19
|
+
raise ArgumentError, 'Invalid attributes, expecting :current, :previous, :event, :retry_in, :reason'
|
20
20
|
end
|
21
21
|
|
22
22
|
@hash_object = {
|
23
23
|
current: hash_object.fetch(:current),
|
24
24
|
previous: hash_object.fetch(:previous),
|
25
|
+
event: hash_object[:event],
|
25
26
|
retry_in: hash_object[:retry_in],
|
26
27
|
reason: hash_object[:reason],
|
27
28
|
protocol_message: hash_object[:protocol_message]
|
@@ -30,7 +31,7 @@ module Ably::Models
|
|
30
31
|
raise ArgumentError, e
|
31
32
|
end
|
32
33
|
|
33
|
-
%w(current previous retry_in reason protocol_message).each do |attribute|
|
34
|
+
%w(current previous event retry_in reason protocol_message).each do |attribute|
|
34
35
|
define_method attribute do
|
35
36
|
@hash_object[attribute.to_sym]
|
36
37
|
end
|