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.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/ably-rest.gemspec +2 -1
  3. data/lib/submodules/ably-ruby/.travis.yml +6 -4
  4. data/lib/submodules/ably-ruby/CHANGELOG.md +52 -61
  5. data/lib/submodules/ably-ruby/README.md +10 -0
  6. data/lib/submodules/ably-ruby/SPEC.md +1473 -852
  7. data/lib/submodules/ably-ruby/ably.gemspec +2 -1
  8. data/lib/submodules/ably-ruby/lib/ably/auth.rb +57 -25
  9. data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +34 -8
  10. data/lib/submodules/ably-ruby/lib/ably/logger.rb +10 -1
  11. data/lib/submodules/ably-ruby/lib/ably/models/auth_details.rb +42 -0
  12. data/lib/submodules/ably-ruby/lib/ably/models/channel_state_change.rb +18 -4
  13. data/lib/submodules/ably-ruby/lib/ably/models/connection_details.rb +6 -3
  14. data/lib/submodules/ably-ruby/lib/ably/models/connection_state_change.rb +4 -3
  15. data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +1 -1
  16. data/lib/submodules/ably-ruby/lib/ably/models/message.rb +12 -1
  17. data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base.rb +101 -97
  18. data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +13 -1
  19. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +20 -3
  20. data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +7 -3
  21. data/lib/submodules/ably-ruby/lib/ably/modules/enum.rb +17 -7
  22. data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +29 -14
  23. data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +7 -4
  24. data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +2 -4
  25. data/lib/submodules/ably-ruby/lib/ably/modules/uses_state_machine.rb +7 -3
  26. data/lib/submodules/ably-ruby/lib/ably/realtime.rb +2 -0
  27. data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +79 -31
  28. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +62 -26
  29. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +154 -65
  30. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +14 -15
  31. data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +16 -3
  32. data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +38 -29
  33. data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +6 -1
  34. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +108 -49
  35. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +165 -59
  36. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +22 -3
  37. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +19 -10
  38. data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +67 -45
  39. data/lib/submodules/ably-ruby/lib/ably/realtime/presence/members_map.rb +198 -36
  40. data/lib/submodules/ably-ruby/lib/ably/realtime/presence/presence_manager.rb +30 -6
  41. data/lib/submodules/ably-ruby/lib/ably/realtime/presence/presence_state_machine.rb +5 -12
  42. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +3 -3
  43. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +21 -8
  44. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +1 -3
  45. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/logger.rb +2 -2
  46. data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -1
  47. data/lib/submodules/ably-ruby/lib/ably/util/pub_sub.rb +1 -1
  48. data/lib/submodules/ably-ruby/lib/ably/util/safe_deferrable.rb +26 -0
  49. data/lib/submodules/ably-ruby/lib/ably/version.rb +2 -2
  50. data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +416 -99
  51. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +5 -3
  52. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +1011 -160
  53. data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +2 -2
  54. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +458 -27
  55. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +436 -97
  56. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +52 -23
  57. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +5 -3
  58. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +1160 -105
  59. data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +151 -22
  60. data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +1 -1
  61. data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +88 -27
  62. data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +42 -15
  63. data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +4 -4
  64. data/lib/submodules/ably-ruby/spec/rspec_config.rb +2 -1
  65. data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +2 -2
  66. data/lib/submodules/ably-ruby/spec/shared/safe_deferrable_behaviour.rb +6 -2
  67. data/lib/submodules/ably-ruby/spec/support/debug_failure_helper.rb +20 -4
  68. data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +32 -1
  69. data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +4 -11
  70. data/lib/submodules/ably-ruby/spec/unit/logger_spec.rb +28 -2
  71. data/lib/submodules/ably-ruby/spec/unit/models/auth_details_spec.rb +49 -0
  72. data/lib/submodules/ably-ruby/spec/unit/models/channel_state_change_spec.rb +23 -3
  73. data/lib/submodules/ably-ruby/spec/unit/models/connection_details_spec.rb +12 -1
  74. data/lib/submodules/ably-ruby/spec/unit/models/connection_state_change_spec.rb +15 -4
  75. data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +34 -2
  76. data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +73 -2
  77. data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +64 -6
  78. data/lib/submodules/ably-ruby/spec/unit/models/token_details_spec.rb +1 -1
  79. data/lib/submodules/ably-ruby/spec/unit/models/token_request_spec.rb +1 -1
  80. data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +2 -1
  81. data/lib/submodules/ably-ruby/spec/unit/modules/enum_spec.rb +69 -0
  82. data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +149 -22
  83. data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +9 -3
  84. data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +1 -1
  85. data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +8 -5
  86. data/lib/submodules/ably-ruby/spec/unit/realtime/incoming_message_dispatcher_spec.rb +1 -1
  87. data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +4 -3
  88. data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +1 -1
  89. data/lib/submodules/ably-ruby/spec/unit/util/crypto_spec.rb +3 -3
  90. 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
- token_details = authorize_with_token(token_details)
94
- logger.debug "Auth: new token passed in to the initializer: #{token_details}"
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.clone
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.clone
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
- auth_callback.call(token_params)
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
- token_request_from_auth_url(auth_url, auth_options, token_params)
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.clone
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
- ttl = [
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}'", 400, 40012)
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}'", 400, 40012)
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
- def initialize(message, status = nil, code = nil)
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, base_error = 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 @base_error
63
- message << "#{@base_error}"
64
- if @base_error.respond_to?(:message) && @base_error.message.match(/certificate verify failed/i)
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; end
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
- def_delegators :logger, :fatal, :error, :warn, :info, :debug
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 protocol_message).each do |attribute|
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
- if self.attributes[:connection_state_ttl]
36
- self.attributes[:connection_state_ttl] = (self.attributes[:connection_state_ttl].to_f / 1000).round
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