ably 0.1.6 → 0.2.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.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.travis.yml +9 -0
  4. data/LICENSE.txt +1 -1
  5. data/README.md +8 -1
  6. data/Rakefile +10 -0
  7. data/ably.gemspec +18 -18
  8. data/lib/ably.rb +6 -5
  9. data/lib/ably/auth.rb +11 -14
  10. data/lib/ably/exceptions.rb +18 -15
  11. data/lib/ably/logger.rb +102 -0
  12. data/lib/ably/models/error_info.rb +1 -1
  13. data/lib/ably/models/message.rb +19 -5
  14. data/lib/ably/models/message_encoders/base.rb +107 -0
  15. data/lib/ably/models/message_encoders/base64.rb +39 -0
  16. data/lib/ably/models/message_encoders/cipher.rb +80 -0
  17. data/lib/ably/models/message_encoders/json.rb +33 -0
  18. data/lib/ably/models/message_encoders/utf8.rb +33 -0
  19. data/lib/ably/models/paginated_resource.rb +23 -6
  20. data/lib/ably/models/presence_message.rb +19 -7
  21. data/lib/ably/models/protocol_message.rb +5 -4
  22. data/lib/ably/models/token.rb +2 -2
  23. data/lib/ably/modules/channels_collection.rb +0 -3
  24. data/lib/ably/modules/conversions.rb +3 -3
  25. data/lib/ably/modules/encodeable.rb +68 -0
  26. data/lib/ably/modules/event_emitter.rb +10 -4
  27. data/lib/ably/modules/event_machine_helpers.rb +6 -4
  28. data/lib/ably/modules/http_helpers.rb +7 -2
  29. data/lib/ably/modules/model_common.rb +2 -0
  30. data/lib/ably/modules/state_emitter.rb +10 -1
  31. data/lib/ably/realtime.rb +19 -12
  32. data/lib/ably/realtime/channel.rb +26 -13
  33. data/lib/ably/realtime/client.rb +31 -7
  34. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +14 -3
  35. data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +13 -4
  36. data/lib/ably/realtime/connection.rb +152 -46
  37. data/lib/ably/realtime/connection/connection_manager.rb +168 -0
  38. data/lib/ably/realtime/connection/connection_state_machine.rb +56 -33
  39. data/lib/ably/realtime/connection/websocket_transport.rb +56 -29
  40. data/lib/ably/{models → realtime/models}/nil_channel.rb +1 -1
  41. data/lib/ably/realtime/presence.rb +38 -13
  42. data/lib/ably/rest.rb +7 -5
  43. data/lib/ably/rest/channel.rb +24 -3
  44. data/lib/ably/rest/client.rb +56 -17
  45. data/lib/ably/rest/middleware/encoder.rb +49 -0
  46. data/lib/ably/rest/middleware/exceptions.rb +3 -2
  47. data/lib/ably/rest/middleware/logger.rb +37 -0
  48. data/lib/ably/rest/presence.rb +10 -2
  49. data/lib/ably/util/crypto.rb +57 -29
  50. data/lib/ably/util/pub_sub.rb +11 -0
  51. data/lib/ably/version.rb +1 -1
  52. data/spec/acceptance/realtime/channel_spec.rb +65 -7
  53. data/spec/acceptance/realtime/connection_spec.rb +123 -27
  54. data/spec/acceptance/realtime/message_spec.rb +319 -34
  55. data/spec/acceptance/realtime/presence_history_spec.rb +58 -0
  56. data/spec/acceptance/realtime/presence_spec.rb +160 -18
  57. data/spec/acceptance/rest/auth_spec.rb +93 -49
  58. data/spec/acceptance/rest/base_spec.rb +10 -10
  59. data/spec/acceptance/rest/channel_spec.rb +35 -19
  60. data/spec/acceptance/rest/channels_spec.rb +8 -8
  61. data/spec/acceptance/rest/message_spec.rb +224 -0
  62. data/spec/acceptance/rest/presence_spec.rb +159 -23
  63. data/spec/acceptance/rest/stats_spec.rb +5 -5
  64. data/spec/acceptance/rest/time_spec.rb +4 -4
  65. data/spec/integration/rest/auth.rb +1 -1
  66. data/spec/resources/crypto-data-128.json +56 -0
  67. data/spec/resources/crypto-data-256.json +56 -0
  68. data/spec/rspec_config.rb +39 -0
  69. data/spec/spec_helper.rb +4 -42
  70. data/spec/support/api_helper.rb +1 -1
  71. data/spec/support/event_machine_helper.rb +0 -5
  72. data/spec/support/protocol_msgbus_helper.rb +3 -3
  73. data/spec/support/test_app.rb +3 -3
  74. data/spec/unit/logger_spec.rb +135 -0
  75. data/spec/unit/models/message_encoders/base64_spec.rb +181 -0
  76. data/spec/unit/models/message_encoders/cipher_spec.rb +260 -0
  77. data/spec/unit/models/message_encoders/json_spec.rb +135 -0
  78. data/spec/unit/models/message_encoders/utf8_spec.rb +100 -0
  79. data/spec/unit/models/message_spec.rb +16 -1
  80. data/spec/unit/models/paginated_resource_spec.rb +46 -0
  81. data/spec/unit/models/presence_message_spec.rb +18 -5
  82. data/spec/unit/models/token_spec.rb +1 -1
  83. data/spec/unit/modules/event_emitter_spec.rb +24 -10
  84. data/spec/unit/realtime/channel_spec.rb +3 -3
  85. data/spec/unit/realtime/channels_spec.rb +1 -1
  86. data/spec/unit/realtime/client_spec.rb +44 -2
  87. data/spec/unit/realtime/connection_spec.rb +2 -2
  88. data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +4 -4
  89. data/spec/unit/realtime/presence_spec.rb +1 -1
  90. data/spec/unit/realtime/realtime_spec.rb +3 -3
  91. data/spec/unit/realtime/websocket_transport_spec.rb +24 -0
  92. data/spec/unit/rest/channels_spec.rb +1 -1
  93. data/spec/unit/rest/client_spec.rb +45 -10
  94. data/spec/unit/util/crypto_spec.rb +82 -0
  95. data/spec/unit/{modules → util}/pub_sub_spec.rb +13 -1
  96. metadata +43 -12
  97. data/spec/acceptance/crypto.rb +0 -63
@@ -4,7 +4,7 @@ module Ably::Models
4
4
  include Ably::Modules::ModelCommon
5
5
 
6
6
  DEFAULTS = {
7
- capability: { "*" => ["*"] },
7
+ capability: { '*' => ['*'] },
8
8
  ttl: 60 * 60 # 1 hour
9
9
  }
10
10
 
@@ -49,7 +49,7 @@ module Ably::Models
49
49
  # @!attribute [r] client_id
50
50
  # @return [String] Optional client ID assigned to this token
51
51
  def client_id
52
- hash.fetch(:client_id)
52
+ hash[:client_id]
53
53
  end
54
54
 
55
55
  # @!attribute [r] nonce
@@ -2,9 +2,6 @@ module Ably::Modules
2
2
  # ChannelsCollection module provides common functionality to the Rest and Realtime Channels objects
3
3
  # such as #get, #[], #fetch, and #release
4
4
  module ChannelsCollection
5
- # Initialize a new Channels object
6
- #
7
- # {self} provides simple accessor methods to access a Channel object
8
5
  def initialize(client, channel_klass)
9
6
  @client = client
10
7
  @channel_klass = channel_klass
@@ -12,7 +12,7 @@ module Ably::Modules
12
12
  when Numeric
13
13
  time
14
14
  else
15
- raise ArgumentError, "time argument must be a Numeric or Time object"
15
+ raise ArgumentError, 'time argument must be a Numeric or Time object'
16
16
  end.to_i
17
17
  end
18
18
 
@@ -23,7 +23,7 @@ module Ably::Modules
23
23
  when Time
24
24
  time
25
25
  else
26
- raise ArgumentError, "time argument must be a Numeric or Time object"
26
+ raise ArgumentError, 'time argument must be a Numeric or Time object'
27
27
  end
28
28
  end
29
29
 
@@ -34,7 +34,7 @@ module Ably::Modules
34
34
  when :s # seconds
35
35
  1.0
36
36
  else
37
- raise ArgumentError, "invalid granularity"
37
+ raise ArgumentError, 'invalid granularity'
38
38
  end
39
39
  end
40
40
 
@@ -0,0 +1,68 @@
1
+ require 'base64'
2
+
3
+ module Ably::Modules
4
+ # Provides methods to allow this model's `data` property to be encoded and decoded based on the `encoding` property.
5
+ #
6
+ # This module expects the following:
7
+ # - A #hash method that returns the underlying hash object
8
+ # - A #set_hash_object(hash) method that updates the underlying hash object
9
+ # - A #raw_hash_object attribute that returns the original hash used to create this object
10
+ #
11
+ module Encodeable
12
+ # Encode a message using the channel options and register encoders for the client
13
+ # @param channel [Ably::Realtime::Channel]
14
+ # @return [void]
15
+ # @api private
16
+ def encode(channel)
17
+ apply_encoders :encode, channel
18
+ end
19
+
20
+ # Decode a message using the channel options and registered encoders for the client
21
+ # @param channel [Ably::Realtime::Channel]
22
+ # @return [void]
23
+ # @api private
24
+ def decode(channel)
25
+ apply_encoders :decode, channel
26
+ end
27
+
28
+ # The original encoding of this message when it was received as a raw message from the Ably service
29
+ # @return [String,nil]
30
+ # @api private
31
+ def original_encoding
32
+ raw_hash_object['encoding']
33
+ end
34
+
35
+ private
36
+ def decode_binary_data_before_to_json(message)
37
+ if message[:data].kind_of?(String) && message[:data].encoding == ::Encoding::ASCII_8BIT
38
+ message[:data] = ::Base64.encode64(message[:data])
39
+ message[:encoding] = [message[:encoding], 'base64'].compact.join('/')
40
+ end
41
+ end
42
+
43
+ def apply_encoders(method, channel)
44
+ max_encoding_length = 512
45
+ message_hash = hash.dup
46
+
47
+ begin
48
+ if message_hash[:encoding].to_s.length > max_encoding_length
49
+ raise Ably::Exceptions::EncoderError("Encoding error, encoding value is too long: '#{message_hash[:encoding]}'", nil, 92100)
50
+ end
51
+
52
+ previous_encoding = message_hash[:encoding]
53
+ channel.client.encoders.each do |encoder|
54
+ encoder.send method, message_hash, channel.options
55
+ end
56
+ end until previous_encoding == message_hash[:encoding]
57
+
58
+ set_hash_object message_hash
59
+ rescue Ably::Exceptions::CipherError => cipher_error
60
+ channel.client.logger.error "Encoder error #{cipher_error.code} trying to #{method} message: #{cipher_error.message}"
61
+ if channel.respond_to?(:trigger)
62
+ channel.trigger :error, cipher_error
63
+ else
64
+ raise cipher_error
65
+ end
66
+ end
67
+ end
68
+ end
@@ -42,7 +42,7 @@ module Ably
42
42
  #
43
43
  # @param [Array<String>] event_names event name
44
44
  #
45
- # @return <void>
45
+ # @return [void]
46
46
  def on(*event_names, &block)
47
47
  event_names.each do |event_name|
48
48
  callbacks[callbacks_event_coerced(event_name)] << proc_for_block(block)
@@ -53,7 +53,7 @@ module Ably
53
53
  #
54
54
  # @param [Array<String>] event_names event name
55
55
  #
56
- # @return <void>
56
+ # @return [void]
57
57
  def once(*event_names, &block)
58
58
  event_names.each do |event_name|
59
59
  callbacks[callbacks_event_coerced(event_name)] << proc_for_block(block, delete_once_run: true)
@@ -72,9 +72,15 @@ module Ably
72
72
  #
73
73
  # @param [Array<String>] event_names event name
74
74
  #
75
- # @return <void>
75
+ # @return [void]
76
76
  def off(*event_names, &block)
77
- event_names.each do |event_name|
77
+ keys = if event_names.empty?
78
+ callbacks.keys
79
+ else
80
+ event_names
81
+ end
82
+
83
+ keys.each do |event_name|
78
84
  if block_given?
79
85
  callbacks[callbacks_event_coerced(event_name)].delete_if { |proc_hash| proc_hash[:block] == block }
80
86
  else
@@ -10,11 +10,13 @@ module Ably::Modules
10
10
  # non_blocking_loop_while(less_than_3) do
11
11
  # x += 1
12
12
  # end
13
- def non_blocking_loop_while(lambda, &execution_block)
14
- if lambda.call
15
- yield
13
+ def non_blocking_loop_while(lambda_condition, &execution_block)
14
+ if lambda_condition.call
16
15
  EventMachine.next_tick do
17
- non_blocking_loop_while(lambda, &execution_block)
16
+ if lambda_condition.call # ensure condition is still met following #next_tick
17
+ yield
18
+ non_blocking_loop_while(lambda_condition, &execution_block)
19
+ end
18
20
  end
19
21
  end
20
22
  end
@@ -1,7 +1,9 @@
1
1
  require 'base64'
2
2
 
3
+ require 'ably/rest/middleware/encoder'
3
4
  require 'ably/rest/middleware/external_exceptions'
4
5
  require 'ably/rest/middleware/fail_if_unsupported_mime_type'
6
+ require 'ably/rest/middleware/logger'
5
7
  require 'ably/rest/middleware/parse_json'
6
8
  require 'ably/rest/middleware/parse_message_pack'
7
9
 
@@ -19,14 +21,17 @@ module Ably::Modules
19
21
 
20
22
  def setup_outgoing_middleware(builder)
21
23
  # Convert request params to "www-form-urlencoded"
22
- builder.use Faraday::Request::UrlEncoded
24
+ builder.use Ably::Rest::Middleware::Encoder
23
25
  end
24
26
 
25
- def setup_incoming_middleware(builder, options = {})
27
+ def setup_incoming_middleware(builder, logger, options = {})
28
+ builder.use Ably::Rest::Middleware::Logger, logger
29
+
26
30
  # Parse JSON / MsgPack response bodies. ParseJson must be first (default) parsing middleware
27
31
  if options[:fail_if_unsupported_mime_type] == true
28
32
  builder.use Ably::Rest::Middleware::FailIfUnsupportedMimeType
29
33
  end
34
+
30
35
  builder.use Ably::Rest::Middleware::ParseJson
31
36
  builder.use Ably::Rest::Middleware::ParseMessagePack
32
37
  end
@@ -1,3 +1,5 @@
1
+ require 'base64'
2
+
1
3
  module Ably::Modules
2
4
  # Common model functionality shared across many {Ably::Models}
3
5
  module ModelCommon
@@ -3,6 +3,9 @@ module Ably::Modules
3
3
  # the instance variable @state is used exclusively, the {Enum} STATE is defined prior to inclusion of this
4
4
  # module, and the class is an {EventEmitter}. It then emits state changes.
5
5
  #
6
+ # It also ensures the EventEmitter is configured to retrict permitted events to the
7
+ # the available STATEs and :error.
8
+ #
6
9
  # @example
7
10
  # class Connection
8
11
  # include Ably::Modules::EventEmitter
@@ -54,7 +57,13 @@ module Ably::Modules
54
57
 
55
58
  private
56
59
  def self.included(klass)
57
- klass.configure_event_emitter coerce_into: Proc.new { |event| klass::STATE(event) }
60
+ klass.configure_event_emitter coerce_into: Proc.new { |event|
61
+ if event == :error
62
+ :error
63
+ else
64
+ klass::STATE(event)
65
+ end
66
+ }
58
67
 
59
68
  klass::STATE.each do |state_predicate|
60
69
  klass.instance_eval do
data/lib/ably/realtime.rb CHANGED
@@ -1,22 +1,29 @@
1
- require "eventmachine"
2
- require "websocket/driver"
1
+ require 'eventmachine'
2
+ require 'websocket/driver'
3
3
 
4
- require "ably/modules/event_emitter"
4
+ require 'ably/modules/event_emitter'
5
5
 
6
- require "ably/realtime/channel"
7
- require "ably/realtime/channels"
8
- require "ably/realtime/client"
9
- require "ably/realtime/connection"
10
- require "ably/realtime/connection/connection_state_machine"
11
- require "ably/realtime/connection/websocket_transport"
12
- require "ably/realtime/presence"
6
+ require 'ably/realtime/channel'
7
+ require 'ably/realtime/channels'
8
+ require 'ably/realtime/client'
9
+ require 'ably/realtime/connection'
10
+ require 'ably/realtime/connection/connection_manager'
11
+ require 'ably/realtime/connection/connection_state_machine'
12
+ require 'ably/realtime/connection/websocket_transport'
13
+ require 'ably/realtime/presence'
13
14
 
14
15
  Dir.glob(File.expand_path("models/*.rb", File.dirname(__FILE__))).each do |file|
15
16
  require file
16
17
  end
17
18
 
18
- require "ably/realtime/client/incoming_message_dispatcher"
19
- require "ably/realtime/client/outgoing_message_dispatcher"
19
+ Dir.glob(File.expand_path("realtime/models/*.rb", File.dirname(__FILE__))).each do |file|
20
+ require file
21
+ end
22
+
23
+ require 'ably/models/message_encoders/base'
24
+
25
+ require 'ably/realtime/client/incoming_message_dispatcher'
26
+ require 'ably/realtime/client/outgoing_message_dispatcher'
20
27
 
21
28
  module Ably
22
29
  # Realtime provides the top-level class to be instanced for the Ably Realtime library
@@ -25,6 +25,12 @@ module Ably
25
25
  #
26
26
  # @!attribute [r] state
27
27
  # @return {Ably::Realtime::Connection::STATE} channel state
28
+ # @!attribute [r] client
29
+ # @return {Ably::Realtime::Client} Ably client associated with this channel
30
+ # @!attribute [r] name
31
+ # @return {String} channel name
32
+ # @!attribute [r] options
33
+ # @return {Hash} channel options configured for this channel, see {#initialize} for channel_options
28
34
  #
29
35
  class Channel
30
36
  include Ably::Modules::Conversions
@@ -49,9 +55,12 @@ module Ably
49
55
 
50
56
  # Initialize a new Channel object
51
57
  #
52
- # @param client [Ably::Rest::Client]
53
- # @param name [String] The name of the channel
54
- # @param channel_options [Hash] Channel options, currently reserved for future Encryption options
58
+ # @param client [Ably::Rest::Client]
59
+ # @param name [String] The name of the channel
60
+ # @param channel_options [Hash] Channel options, currently reserved for Encryption options
61
+ # @option channel_options [Boolean] :encrypted setting this to true for this channel will encrypt & decrypt all messages automatically
62
+ # @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
63
+ #
55
64
  def initialize(client, name, channel_options = {})
56
65
  @client = client
57
66
  @name = name
@@ -120,6 +129,7 @@ module Ably
120
129
  # to need to call attach explicitly.
121
130
  #
122
131
  # @yield [Ably::Realtime::Channel] Block is called as soon as this channel is in the Attached state
132
+ # @return [void]
123
133
  #
124
134
  def attach(&block)
125
135
  if attached?
@@ -136,6 +146,7 @@ module Ably
136
146
  # Detach this channel, and call the block if provided when in a Detached or Failed state
137
147
  #
138
148
  # @yield [Ably::Realtime::Channel] Block is called as soon as this channel is in the Detached or Failed state
149
+ # @return [void]
139
150
  #
140
151
  def detach(&block)
141
152
  if detached? || failed?
@@ -172,7 +183,7 @@ module Ably
172
183
  # @api private
173
184
  def __incoming_msgbus__
174
185
  @__incoming_msgbus__ ||= Ably::Util::PubSub.new(
175
- coerce_into: Proc.new { |event| Models::ProtocolMessage::ACTION(event) }
186
+ coerce_into: Proc.new { |event| Ably::Models::ProtocolMessage::ACTION(event) }
176
187
  )
177
188
  end
178
189
 
@@ -181,6 +192,8 @@ module Ably
181
192
 
182
193
  def setup_event_handlers
183
194
  __incoming_msgbus__.subscribe(:message) do |message|
195
+ message.decode self
196
+
184
197
  subscriptions[:all].each { |cb| cb.call(message) }
185
198
  subscriptions[message.name].each { |cb| cb.call(message) }
186
199
  end
@@ -224,18 +237,18 @@ module Ably
224
237
 
225
238
  def send_messages_within_protocol_message(messages)
226
239
  client.connection.send_protocol_message(
227
- action: Models::ProtocolMessage::ACTION.Message.to_i,
240
+ action: Ably::Models::ProtocolMessage::ACTION.Message.to_i,
228
241
  channel: name,
229
242
  messages: messages
230
243
  )
231
244
  end
232
245
 
233
246
  def send_attach_protocol_message
234
- send_state_change_protocol_message Models::ProtocolMessage::ACTION.Attach
247
+ send_state_change_protocol_message Ably::Models::ProtocolMessage::ACTION.Attach
235
248
  end
236
249
 
237
250
  def send_detach_protocol_message
238
- send_state_change_protocol_message Models::ProtocolMessage::ACTION.Detach
251
+ send_state_change_protocol_message Ably::Models::ProtocolMessage::ACTION.Detach
239
252
  end
240
253
 
241
254
  def send_state_change_protocol_message(state)
@@ -246,13 +259,13 @@ module Ably
246
259
  end
247
260
 
248
261
  def create_message(name, data)
249
- model = {
250
- name: name,
251
- data: data
252
- }
253
- model.merge!(clientId: client.client_id) if client.client_id
262
+ message = { name: name }
263
+ message.merge!(data: data) unless data.nil?
264
+ message.merge!(clientId: client.client_id) if client.client_id
254
265
 
255
- Models::Message.new(model, nil)
266
+ Ably::Models::Message.new(message, nil).tap do |message|
267
+ message.encode self
268
+ end
256
269
  end
257
270
 
258
271
  def rest_channel
@@ -16,6 +16,12 @@ module Ably
16
16
  # @return [Ably::Rest::Client] The {Ably::Rest::Client REST client} instantiated with the same credentials and configuration that is used for all REST operations such as authentication
17
17
  # @!attribute [r] echo_messages
18
18
  # @return [Boolean] If false, suppresses messages originating from this connection being echoed back on the same connection. Defaults to true
19
+ # @!attribute [r] encoders
20
+ # (see Ably::Rest::Client#encoders)
21
+ # @!attribute [r] protocol
22
+ # (see Ably::Rest::Client#protocol)
23
+ # @!attribute [r] protocol_binary?
24
+ # (see Ably::Rest::Client#protocol_binary?)
19
25
  class Client
20
26
  extend Forwardable
21
27
 
@@ -23,8 +29,9 @@ module Ably
23
29
 
24
30
  attr_reader :channels, :auth, :rest_client, :echo_messages
25
31
  def_delegators :auth, :client_id, :auth_options
26
- def_delegators :@rest_client, :environment, :use_tls?, :protocol
27
- def_delegators :@rest_client, :logger, :log_level
32
+ def_delegators :@rest_client, :encoders
33
+ def_delegators :@rest_client, :environment, :use_tls?, :protocol, :protocol_binary?
34
+ def_delegators :@rest_client, :log_level
28
35
  def_delegators :@rest_client, :time, :stats
29
36
 
30
37
  # Creates a {Ably::Realtime::Client Realtime Client} and configures the {Ably::Auth} object for the connection.
@@ -49,10 +56,11 @@ module Ably
49
56
  # client = Ably::Realtime::Client.new(api_key: 'key.id:secret', client_id: 'john')
50
57
  #
51
58
  def initialize(options, &auth_block)
52
- @rest_client = Ably::Rest::Client.new(options, &auth_block)
53
- @auth = @rest_client.auth
54
- @channels = Ably::Realtime::Channels.new(self)
55
- @echo_messages = @rest_client.options.fetch(:echo_messages, true) == false ? false : true
59
+ @rest_client = Ably::Rest::Client.new(options, &auth_block)
60
+ @auth = @rest_client.auth
61
+ @channels = Ably::Realtime::Channels.new(self)
62
+ @echo_messages = @rest_client.options.fetch(:echo_messages, true) == false ? false : true
63
+ @custom_socket_host = @rest_client.options[:ws_host]
56
64
  end
57
65
 
58
66
  # Return a {Ably::Realtime::Channel Realtime Channel} for the given name
@@ -84,7 +92,7 @@ module Ably
84
92
  def endpoint
85
93
  URI::Generic.build(
86
94
  scheme: use_tls? ? "wss" : "ws",
87
- host: [environment, DOMAIN].compact.join('-')
95
+ host: custom_socket_host || [environment, DOMAIN].compact.join('-')
88
96
  )
89
97
  end
90
98
 
@@ -93,6 +101,22 @@ module Ably
93
101
  def connection
94
102
  @connection ||= Connection.new(self)
95
103
  end
104
+
105
+ # @!attribute [r] custom_socket_host
106
+ # @return [String,nil] Returns the custom socket host that is being used if it was provided with the option :ws_host when the {Client} was created
107
+ def custom_socket_host
108
+ @custom_socket_host
109
+ end
110
+
111
+ # (see Ably::Rest::Client#register_encoder)
112
+ def register_encoder(encoder)
113
+ rest_client.register_encoder encoder
114
+ end
115
+
116
+ # (see Ably::Rest::Client#logger)
117
+ def logger
118
+ @logger ||= Ably::Logger.new(self, log_level, rest_client.logger.custom_logger)
119
+ end
96
120
  end
97
121
  end
98
122
  end