ably-rest 0.8.6 → 0.8.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/SPEC.md +1049 -1001
  3. data/lib/submodules/ably-ruby/CHANGELOG.md +75 -3
  4. data/lib/submodules/ably-ruby/LICENSE +2 -2
  5. data/lib/submodules/ably-ruby/README.md +81 -20
  6. data/lib/submodules/ably-ruby/SPEC.md +1209 -693
  7. data/lib/submodules/ably-ruby/ably.gemspec +4 -4
  8. data/lib/submodules/ably-ruby/lib/ably/auth.rb +13 -4
  9. data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +10 -1
  10. data/lib/submodules/ably-ruby/lib/ably/logger.rb +3 -1
  11. data/lib/submodules/ably-ruby/lib/ably/models/cipher_params.rb +114 -0
  12. data/lib/submodules/ably-ruby/lib/ably/models/connection_details.rb +10 -7
  13. data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +3 -3
  14. data/lib/submodules/ably-ruby/lib/ably/models/idiomatic_ruby_wrapper.rb +28 -21
  15. data/lib/submodules/ably-ruby/lib/ably/models/message.rb +19 -17
  16. data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/cipher.rb +10 -9
  17. data/lib/submodules/ably-ruby/lib/ably/models/paginated_result.rb +27 -1
  18. data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +20 -18
  19. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +26 -19
  20. data/lib/submodules/ably-ruby/lib/ably/models/{stat.rb → stats.rb} +21 -19
  21. data/lib/submodules/ably-ruby/lib/ably/models/token_details.rb +14 -12
  22. data/lib/submodules/ably-ruby/lib/ably/models/token_request.rb +16 -14
  23. data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +2 -2
  24. data/lib/submodules/ably-ruby/lib/ably/modules/channels_collection.rb +11 -1
  25. data/lib/submodules/ably-ruby/lib/ably/modules/encodeable.rb +10 -10
  26. data/lib/submodules/ably-ruby/lib/ably/modules/enum.rb +18 -2
  27. data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +3 -3
  28. data/lib/submodules/ably-ruby/lib/ably/modules/model_common.rb +13 -5
  29. data/lib/submodules/ably-ruby/lib/ably/modules/safe_deferrable.rb +1 -1
  30. data/lib/submodules/ably-ruby/lib/ably/modules/safe_yield.rb +2 -2
  31. data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +8 -8
  32. data/lib/submodules/ably-ruby/lib/ably/modules/statesman_monkey_patch.rb +2 -2
  33. data/lib/submodules/ably-ruby/lib/ably/modules/uses_state_machine.rb +4 -2
  34. data/lib/submodules/ably-ruby/lib/ably/realtime.rb +1 -0
  35. data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +6 -2
  36. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +7 -6
  37. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +7 -1
  38. data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +7 -12
  39. data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +9 -2
  40. data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +7 -1
  41. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +19 -8
  42. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +16 -9
  43. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +12 -3
  44. data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +35 -64
  45. data/lib/submodules/ably-ruby/lib/ably/realtime/presence/members_map.rb +23 -9
  46. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +9 -10
  47. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +1 -1
  48. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +16 -4
  49. data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +7 -5
  50. data/lib/submodules/ably-ruby/lib/ably/util/crypto.rb +50 -40
  51. data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
  52. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +4 -4
  53. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +2 -4
  54. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +46 -8
  55. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +20 -20
  56. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +7 -7
  57. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +114 -111
  58. data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +9 -9
  59. data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +5 -5
  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 +1 -1
  62. data/lib/submodules/ably-ruby/spec/acceptance/rest/encoders_spec.rb +4 -4
  63. data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +15 -15
  64. data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +4 -4
  65. data/lib/submodules/ably-ruby/spec/shared/model_behaviour.rb +7 -7
  66. data/lib/submodules/ably-ruby/spec/shared/safe_deferrable_behaviour.rb +4 -4
  67. data/lib/submodules/ably-ruby/spec/unit/models/cipher_params_spec.rb +140 -0
  68. data/lib/submodules/ably-ruby/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +15 -8
  69. data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/cipher_spec.rb +28 -22
  70. data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/json_spec.rb +24 -0
  71. data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +3 -3
  72. data/lib/submodules/ably-ruby/spec/unit/models/token_details_spec.rb +20 -18
  73. data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +2 -2
  74. data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +6 -6
  75. data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +4 -4
  76. data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +1 -1
  77. data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +5 -5
  78. data/lib/submodules/ably-ruby/spec/unit/util/crypto_spec.rb +50 -17
  79. metadata +5 -3
@@ -60,8 +60,8 @@ module Ably::Realtime
60
60
  # Get the list of presence members
61
61
  #
62
62
  # @param [Hash,String] options an options Hash to filter members
63
- # @option options [String] :client_id optional client_id for the member
64
- # @option options [String] :connection_id optional connection_id for the member
63
+ # @option options [String] :client_id optional client_id filter for the member
64
+ # @option options [String] :connection_id optional connection_id filter for the member
65
65
  # @option options [String] :wait_for_sync defaults to false, if true the get method waits for the initial presence sync following channel attachment to complete before returning the members present
66
66
  #
67
67
  # @yield [Array<Ably::Models::PresenceMessage>] array of present members
@@ -99,12 +99,12 @@ module Ably::Realtime
99
99
  end
100
100
 
101
101
  reset_callbacks = proc do
102
- off &in_sync_callback
103
- off &failed_callback
104
- channel.off &failed_callback
102
+ off(&in_sync_callback)
103
+ off(&failed_callback)
104
+ channel.off(&failed_callback)
105
105
  end
106
106
 
107
- once :in_sync, &in_sync_callback
107
+ once(:in_sync, &in_sync_callback)
108
108
 
109
109
  once(:failed, &failed_callback)
110
110
  channel.unsafe_once(:detaching, :detached, :failed) do |error_reason|
@@ -131,7 +131,21 @@ module Ably::Realtime
131
131
  end
132
132
 
133
133
  private
134
- attr_reader :members, :sync_serial, :presence, :absent_member_cleanup_queue
134
+ def members
135
+ @members
136
+ end
137
+
138
+ def sync_serial
139
+ @sync_serial
140
+ end
141
+
142
+ def presence
143
+ @presence
144
+ end
145
+
146
+ def absent_member_cleanup_queue
147
+ @absent_member_cleanup_queue
148
+ end
135
149
 
136
150
  def channel
137
151
  presence.channel
@@ -156,9 +170,9 @@ module Ably::Realtime
156
170
  end
157
171
 
158
172
  resume_sync_proc = method(:resume_sync).to_proc
159
- connection.on_resume &resume_sync_proc
173
+ connection.on_resume(&resume_sync_proc)
160
174
  once(:in_sync, :failed) do
161
- connection.off_resume &resume_sync_proc
175
+ connection.off_resume(&resume_sync_proc)
162
176
  end
163
177
 
164
178
  once(:in_sync) do
@@ -19,8 +19,7 @@ module Ably
19
19
  # @param client [Ably::Rest::Client]
20
20
  # @param name [String] The name of the channel
21
21
  # @param channel_options [Hash] Channel options, currently reserved for Encryption options
22
- # @option channel_options [Boolean] :encrypted setting this to true for this channel will encrypt & decrypt all messages automatically
23
- # @option channel_options [Hash] :cipher_params A hash of options to configure the encryption. *:key* is required, all other options are optional. See {Ably::Util::Crypto#initialize} for a list of +cipher_params+ options
22
+ # @option channel_options [Hash,Ably::Models::CipherParams] :cipher A hash of options or a {Ably::Models::CipherParams} to configure the encryption. *:key* is required, all other options are optional. See {Ably::Util::Crypto#initialize} for a list of +:cipher+ options
24
23
  #
25
24
  def initialize(client, name, channel_options = {})
26
25
  ensure_utf_8 :name, name
@@ -65,15 +64,15 @@ module Ably
65
64
  end
66
65
 
67
66
  payload = messages.map do |message|
68
- Ably::Models::Message(message.dup).tap do |message|
69
- message.encode self
67
+ Ably::Models::Message(message.dup).tap do |msg|
68
+ msg.encode self
70
69
 
71
- next if message.client_id.nil?
72
- if message.client_id == '*'
70
+ next if msg.client_id.nil?
71
+ if msg.client_id == '*'
73
72
  raise Ably::Exceptions::IncompatibleClientId.new('Wildcard client_id is reserved and cannot be used when publishing messages', 400, 40012)
74
73
  end
75
- unless client.auth.can_assume_client_id?(message.client_id)
76
- raise Ably::Exceptions::IncompatibleClientId.new("Cannot publish with client_id '#{message.client_id}' as it is incompatible with the current configured client_id '#{client.client_id}'", 400, 40012)
74
+ unless client.auth.can_assume_client_id?(msg.client_id)
75
+ raise Ably::Exceptions::IncompatibleClientId.new("Cannot publish with client_id '#{msg.client_id}' as it is incompatible with the current configured client_id '#{client.client_id}'", 400, 40012)
77
76
  end
78
77
  end.as_json
79
78
  end
@@ -111,8 +110,8 @@ module Ably
111
110
  response = client.get(url, options)
112
111
 
113
112
  Ably::Models::PaginatedResult.new(response, url, client, paginated_options) do |message|
114
- message.tap do |message|
115
- decode_message message
113
+ message.tap do |msg|
114
+ decode_message msg
116
115
  end
117
116
  end
118
117
  end
@@ -315,7 +315,7 @@ module Ably
315
315
  #
316
316
  # @api private
317
317
  def fallback_connection
318
- unless @fallback_connections
318
+ unless defined?(@fallback_connections) && @fallback_connections
319
319
  @fallback_connections = Ably::FALLBACK_HOSTS.shuffle.map { |host| Faraday.new(endpoint_for_host(host).to_s, connection_options) }
320
320
  end
321
321
  @fallback_index ||= 0
@@ -7,6 +7,8 @@ module Ably
7
7
  # HTTP exceptions raised by Ably due to an error status code
8
8
  # Ably returns JSON/Msgpack error codes and messages so include this if possible in the exception messages
9
9
  class Exceptions < Faraday::Response::Middleware
10
+ TOKEN_EXPIRED_CODE = 40140..40149
11
+
10
12
  def on_complete(env)
11
13
  if env.status >= 400
12
14
  error_status_code = env.status
@@ -28,12 +30,22 @@ module Ably
28
30
 
29
31
  message = 'Unknown server error' if message.to_s.strip == ''
30
32
 
33
+ exception_args = [message, error_status_code, error_code]
34
+
31
35
  if env.status >= 500
32
- raise Ably::Exceptions::ServerError.new(message, error_status_code, error_code)
33
- elsif env.status == 401 && error_code == 40140
34
- raise Ably::Exceptions::TokenExpired.new(message, error_status_code, error_code)
36
+ raise Ably::Exceptions::ServerError.new(*exception_args)
37
+ elsif env.status == 401
38
+ if TOKEN_EXPIRED_CODE.include?(error_code)
39
+ raise Ably::Exceptions::TokenExpired.new(*exception_args)
40
+ else
41
+ raise Ably::Exceptions::UnauthorizedRequest.new(*exception_args)
42
+ end
43
+ elsif env.status == 403
44
+ raise Ably::Exceptions::ForbiddenRequest.new(*exception_args)
45
+ elsif env.status == 404
46
+ raise Ably::Exceptions::ResourceMissing.new(*exception_args)
35
47
  else
36
- raise Ably::Exceptions::InvalidRequest.new(message, error_status_code, error_code)
48
+ raise Ably::Exceptions::InvalidRequest.new(*exception_args)
37
49
  end
38
50
  end
39
51
  end
@@ -23,7 +23,9 @@ module Ably
23
23
  # Obtain the set of members currently present for a channel
24
24
  #
25
25
  # @param [Hash] options the options for the set of members present
26
- # @option options [Integer] :limit Maximum number of members to retrieve up to 1,000, defaults to 100
26
+ # @option options [Integer] :limit Maximum number of members to retrieve up to 1,000, defaults to 100
27
+ # @option options [String] :client_id optional client_id filter for the member
28
+ # @option options [String] :connection_id optional connection_id filter for the member
27
29
  #
28
30
  # @return [Ably::Models::PaginatedResult<Ably::Models::PresenceMessage>] First {Ably::Models::PaginatedResult page} of {Ably::Models::PresenceMessage} objects accessible with {Ably::Models::PaginatedResult#items #items}.
29
31
  #
@@ -40,8 +42,8 @@ module Ably
40
42
  response = client.get(base_path, options)
41
43
 
42
44
  Ably::Models::PaginatedResult.new(response, base_path, client, paginated_options) do |presence_message|
43
- presence_message.tap do |presence_message|
44
- decode_message presence_message
45
+ presence_message.tap do |message|
46
+ decode_message message
45
47
  end
46
48
  end
47
49
  end
@@ -74,8 +76,8 @@ module Ably
74
76
  response = client.get(url, options)
75
77
 
76
78
  Ably::Models::PaginatedResult.new(response, url, client, paginated_options) do |presence_message|
77
- presence_message.tap do |presence_message|
78
- decode_message presence_message
79
+ presence_message.tap do |message|
80
+ decode_message message
79
81
  end
80
82
  end
81
83
  end
@@ -4,52 +4,65 @@ require 'openssl'
4
4
  module Ably::Util
5
5
  class Crypto
6
6
  DEFAULTS = {
7
- algorithm: 'AES',
8
- mode: 'CBC',
9
- key_length: 128,
7
+ algorithm: 'aes',
8
+ mode: 'cbc',
9
+ key_length: 256,
10
10
  }
11
11
 
12
12
  BLOCK_LENGTH = 16
13
13
 
14
- # Configured options for this Crypto object, see {#initialize} for a list of configured options
14
+ # Configured {Ably::Models::CipherParams} for this Crypto object, see {#initialize} for a list of configureable options
15
15
  #
16
- # @return [Hash]
17
- attr_reader :options
16
+ # @return [Ably::Models::CipherParams]
17
+ attr_reader :cipher_params
18
18
 
19
19
  # Creates a {Ably::Util::Crypto} object
20
20
  #
21
- # @param [Hash] options an options Hash used to configure the Crypto library
22
- # @option options [String] :key Required secret key used for encrypting and decrypting
23
- # @option options [String] :algorithm optional (default AES), specify the encryption algorithm supported by {http://ruby-doc.org/stdlib-2.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html OpenSSL::Cipher}
24
- # @option options [String] :mode optional (default CBC), specify the cipher mode supported by {http://ruby-doc.org/stdlib-2.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html OpenSSL::Cipher}
25
- # @option options [Integer] :key_length optional (default 128), specify the key length of the cipher supported by {http://ruby-doc.org/stdlib-2.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html OpenSSL::Cipher}
26
- # @option options [String] :combined optional (default AES-128-CBC), specify in one option the algorithm, key length and cipher of the cipher supported by {http://ruby-doc.org/stdlib-2.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html OpenSSL::Cipher}
21
+ # @param [Hash] params a Hash used to configure the Crypto library's {Ably::Models::CipherParams}
22
+ # @option params (see Ably::Models::CipherParams#initialize)
27
23
  #
28
24
  # @return [Ably::Util::Crypto]
29
25
  #
30
26
  # @example
31
- # crypto = Ably::Util::Crypto.new(key: 'mysecret')
27
+ # key = Ably::Util::Crypto.generate_random_key
28
+ # crypto = Ably::Util::Crypto.new(key: key)
32
29
  # encrypted = crypto.encrypt('secret text')
33
30
  # crypto.decrypt(decrypted) # => 'secret text'
34
31
  #
35
- def initialize(options)
36
- raise ArgumentError, ':key is required' unless options.has_key?(:key)
37
- @options = DEFAULTS.merge(options).freeze
32
+ def initialize(params)
33
+ @fixed_iv = params.delete(:fixed_iv) if params.kind_of?(Hash)
34
+ @cipher_params = Ably::Models::CipherParams(params)
38
35
  end
39
36
 
40
- # Obtain a default CipherParams. This uses default algorithm, mode and
41
- # padding and key length. A key and IV are generated using the default
42
- # system SecureRandom; the key may be obtained from the returned CipherParams
37
+ # Obtain a default {Ably::Models::CipherParams}. This uses default algorithm, mode and
38
+ # padding and key length. An IV is generated using the default
39
+ # system SecureRandom; the key may be obtained from the returned {Ably::Models::CipherParams}
43
40
  # for out-of-band distribution to other clients.
41
+
42
+ # @param [Hash] params a Hash used to configure the Crypto library's {Ably::Models::CipherParams}
43
+ # @option params (see Ably::Models::CipherParams#initialize)
44
+ #
45
+ # @return [Ably::Models::CipherParams] Configured cipher params with :key, :algorithm, :mode, :key_length attributes
46
+ #
47
+ def self.get_default_params(params = {})
48
+ Ably::Models::CipherParams(params)
49
+ end
50
+
51
+ # Generate a random encryption key from the supplied keylength (or the
52
+ # default key_length of 256 if none supplied)
44
53
  #
45
- # @return [Hash] CipherParam options Hash with attributes :key, :algorithn, :mode, :key_length
54
+ # @param [Integer] key_length Optional (default 256) key length for the generated random key. 128 and 256 bit key lengths are supported
55
+ # @return Binary String (byte array) with ASCII_8BIT encoding
46
56
  #
47
- def self.get_default_params(key = nil)
48
- params = DEFAULTS.merge(key: key)
49
- params[:key_length] = key.unpack('b*').first.length if params[:key]
50
- cipher_type = "#{params[:algorithm]}-#{params[:key_length]}-#{params[:mode]}"
51
- params[:key] = OpenSSL::Cipher.new(cipher_type.upcase).random_key unless params[:key]
52
- params
57
+ def self.generate_random_key(key_length = DEFAULTS.fetch(:key_length))
58
+ params = DEFAULTS.merge(key_length: key_length)
59
+ OpenSSL::Cipher.new(cipher_type(params)).random_key
60
+ end
61
+
62
+ # The Cipher algorithm string such as AES-128-CBC
63
+ # @api private
64
+ def self.cipher_type(options)
65
+ Ably::Models::CipherParams.cipher_type(options)
53
66
  end
54
67
 
55
68
  # Encrypt payload using configured Cipher
@@ -58,13 +71,13 @@ module Ably::Util
58
71
  # @param [Hash] encrypt_options an options Hash to configure the encrypt action
59
72
  # @option encrypt_options [String] :iv optionally use the provided Initialization Vector instead of a randomly generated IV
60
73
  #
61
- # @return [String] binary string with {Encoding::ASCII_8BIT} encoding
74
+ # @return [String] binary string with +Encoding::ASCII_8BIT+ encoding
62
75
  #
63
76
  def encrypt(payload, encrypt_options = {})
64
77
  cipher = openssl_cipher
65
78
  cipher.encrypt
66
79
  cipher.key = key
67
- iv = encrypt_options[:iv] || options[:iv] || cipher.random_iv
80
+ iv = encrypt_options[:iv] || fixed_iv || cipher.random_iv
68
81
  cipher.iv = iv
69
82
 
70
83
  iv << cipher.update(payload) << cipher.final
@@ -90,31 +103,28 @@ module Ably::Util
90
103
  decipher.update(encrypted_payload) << decipher.final
91
104
  end
92
105
 
93
- # Generate a random key
94
- # @return [String]
95
- def random_key
96
- openssl_cipher.random_key
97
- end
98
-
99
106
  # Generate a random IV
100
107
  # @return [String]
101
108
  def random_iv
102
109
  openssl_cipher.random_iv
103
110
  end
104
111
 
105
- # The Cipher algorithm string such as AES-128-CBC
112
+ private
113
+ # Used solely for tests to fix the IV instead of randomly generate one
114
+ attr_reader :fixed_iv
115
+
116
+ # Generate a random key
106
117
  # @return [String]
107
- def cipher_type
108
- (options[:combined] || "#{options[:algorithm]}-#{options[:key_length]}-#{options[:mode]}").to_s.upcase
118
+ def random_key
119
+ openssl_cipher.random_key
109
120
  end
110
121
 
111
- private
112
122
  def key
113
- options[:key]
123
+ cipher_params.key
114
124
  end
115
125
 
116
126
  def openssl_cipher
117
- OpenSSL::Cipher.new(cipher_type)
127
+ @openssl_cipher ||= OpenSSL::Cipher.new(cipher_params.cipher_type)
118
128
  end
119
129
  end
120
130
  end
@@ -1,3 +1,3 @@
1
1
  module Ably
2
- VERSION = '0.8.6'
2
+ VERSION = '0.8.9'
3
3
  end
@@ -19,7 +19,7 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
19
19
  let(:options) { { :protocol => :json } }
20
20
 
21
21
  it 'returns a SafeDeferrable that catches exceptions in callbacks and logs them' do
22
- channel.publish('event', payload) do |message|
22
+ channel.publish('event', payload) do
23
23
  history = channel.history
24
24
  expect(history).to be_a(Ably::Util::SafeDeferrable)
25
25
  history.callback do |page|
@@ -32,7 +32,7 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
32
32
 
33
33
  context 'with a single client publishing and receiving' do
34
34
  it 'retrieves realtime history' do
35
- channel.publish('event', payload) do |message|
35
+ channel.publish('event', payload) do
36
36
  channel.history do |page|
37
37
  expect(page.items.length).to eql(1)
38
38
  expect(page.items[0].data).to eql(payload)
@@ -44,8 +44,8 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
44
44
 
45
45
  context 'with two clients publishing messages on the same channel' do
46
46
  it 'retrieves realtime history on both channels' do
47
- channel.publish('event', payload) do |message|
48
- channel2.publish('event', payload) do |message|
47
+ channel.publish('event', payload) do
48
+ channel2.publish('event', payload) do
49
49
  channel.history do |page|
50
50
  expect(page.items.length).to eql(2)
51
51
  expect(page.items.map(&:data).uniq).to eql([payload])
@@ -481,8 +481,6 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
481
481
  end
482
482
 
483
483
  it 'retains channel subscription state' do
484
- messages_received = false
485
-
486
484
  channel.subscribe('event') do |message|
487
485
  expect(message.data).to eql('message')
488
486
  stop_reactor
@@ -712,6 +710,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
712
710
  context 'when the Internet is up' do
713
711
  before do
714
712
  allow(connection).to receive(:internet_up?).and_yield(true)
713
+ @suspended = 0
715
714
  end
716
715
 
717
716
  it 'uses a fallback host on every subsequent disconnected attempt until suspended' do
@@ -740,14 +739,13 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
740
739
  expect(host).to eql(expected_host)
741
740
  else
742
741
  expect(custom_hosts).to include(host)
743
- fallback_hosts_used << host if @suspended
742
+ fallback_hosts_used << host if @suspended > 0
744
743
  end
745
744
  request += 1
746
745
  raise EventMachine::ConnectionError
747
746
  end
748
747
 
749
748
  connection.on(:suspended) do
750
- @suspended ||= 0
751
749
  @suspended += 1
752
750
 
753
751
  if @suspended > 3
@@ -141,7 +141,7 @@ describe Ably::Realtime::Connection, :event_machine do
141
141
  started_at = Time.now.to_f
142
142
  connection.once(:disconnected) do
143
143
  connection.once(:disconnected) do |connection_state_change|
144
- expect(connection_state_change.reason.code).to eql(40140) # token expired
144
+ expect(connection_state_change.reason.code).to eql(40142) # token expired
145
145
  expect(Time.now.to_f - started_at).to be < 1000
146
146
  expect(auth_requests.count).to eql(2)
147
147
  stop_reactor
@@ -156,7 +156,7 @@ describe Ably::Realtime::Connection, :event_machine do
156
156
  started_at = Time.now.to_f
157
157
  disconnect_count = 0
158
158
  connection.on(:disconnected) do |connection_state_change|
159
- expect(connection_state_change.reason.code).to eql(40140) # token expired
159
+ expect(connection_state_change.reason.code).to eql(40142) # token expired
160
160
  disconnect_count += 1
161
161
  if disconnect_count == 6
162
162
  expect(Time.now.to_f - started_at).to be > 4 * 0.5 # at least 4 0.5 second pauses should have happened
@@ -207,7 +207,7 @@ describe Ably::Realtime::Connection, :event_machine do
207
207
  expect(original_token).to_not be_expired
208
208
  started_at = Time.now
209
209
  connection.once(:disconnected) do |connection_state_change|
210
- expect(connection_state_change.reason.code).to eq(40140) # Token expired
210
+ expect(connection_state_change.reason.code).to eq(40142) # Token expired
211
211
 
212
212
  # Token has expired, so now ensure it is not used again
213
213
  stub_const 'Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER', original_token_expiry_buffer
@@ -333,7 +333,7 @@ describe Ably::Realtime::Connection, :event_machine do
333
333
  expect(expired_token_details).to be_expired
334
334
  connection.once(:connected) { raise 'Connection should never connect as token has expired' }
335
335
  connection.once(:failed) do
336
- expect(client.connection.error_reason.code).to eql(40140)
336
+ expect(client.connection.error_reason.code).to eql(40142)
337
337
  stop_reactor
338
338
  end
339
339
  end
@@ -800,6 +800,41 @@ describe Ably::Realtime::Connection, :event_machine do
800
800
  end
801
801
  end
802
802
 
803
+ context '#details' do
804
+ let(:connection) { client.connection }
805
+
806
+ it 'is nil before connected' do
807
+ connection.on(:connecting) do
808
+ expect(connection.details).to eql(nil)
809
+ stop_reactor
810
+ end
811
+ end
812
+
813
+ it 'contains the ConnectionDetails object once connected' do
814
+ connection.on(:connected) do
815
+ expect(connection.details).to be_a(Ably::Models::ConnectionDetails)
816
+ expect(connection.details.connection_key).to_not be_nil
817
+ expect(connection.details.server_id).to_not be_nil
818
+ stop_reactor
819
+ end
820
+ end
821
+
822
+ it 'contains the new ConnectionDetails object once a subsequent connection is created' do
823
+ connection.once(:connected) do
824
+ expect(connection.details.connection_key).to_not be_nil
825
+ old_key = connection.details.connection_key
826
+ connection.close do
827
+ connection.once(:connected) do
828
+ expect(connection.details.connection_key).to_not be_nil
829
+ expect(connection.details.connection_key).to_not eql(old_key)
830
+ stop_reactor
831
+ end
832
+ connection.connect
833
+ end
834
+ end
835
+ end
836
+ end
837
+
803
838
  context 'recovery' do
804
839
  let(:channel_name) { random_str }
805
840
  let(:channel) { client.channel(channel_name) }
@@ -813,7 +848,8 @@ describe Ably::Realtime::Connection, :event_machine do
813
848
  log_level: :none,
814
849
  disconnected_retry_timeout: 0.1,
815
850
  suspended_retry_timeout: 0.1,
816
- connection_state_ttl: 0.2
851
+ connection_state_ttl: 0.2,
852
+ realtime_request_timeout: 5
817
853
  )
818
854
  end
819
855
 
@@ -889,7 +925,8 @@ describe Ably::Realtime::Connection, :event_machine do
889
925
 
890
926
  context "opening a new connection using a recently disconnected connection's #recovery_key" do
891
927
  context 'connection#id and connection#key after recovery' do
892
- it 'remains the same' do
928
+ it 'remains the same for id and party for key' do
929
+ connection_key_consistent_part_regex = /.*?!(\w{5,})-/
893
930
  previous_connection_id = nil
894
931
  previous_connection_key = nil
895
932
 
@@ -902,8 +939,9 @@ describe Ably::Realtime::Connection, :event_machine do
902
939
  connection.once(:failed) do
903
940
  recover_client = auto_close Ably::Realtime::Client.new(default_options.merge(recover: client.connection.recovery_key))
904
941
  recover_client.connection.on(:connected) do
905
- expect(recover_client.connection.key[/^\w{5,}-/, 0]).to_not be_nil
906
- expect(recover_client.connection.key[/^\w{5,}-/, 0]).to eql(previous_connection_key[/^\w{5,}-/, 0])
942
+ expect(recover_client.connection.key[connection_key_consistent_part_regex, 1]).to_not be_nil
943
+ expect(recover_client.connection.key[connection_key_consistent_part_regex, 1]).to eql(
944
+ previous_connection_key[connection_key_consistent_part_regex, 1])
907
945
  expect(recover_client.connection.id).to eql(previous_connection_id)
908
946
  stop_reactor
909
947
  end