ably-rest 0.8.2 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -43
- data/SPEC.md +707 -580
- data/lib/submodules/ably-ruby/.travis.yml +1 -0
- data/lib/submodules/ably-ruby/CHANGELOG.md +143 -3
- data/lib/submodules/ably-ruby/README.md +1 -1
- data/lib/submodules/ably-ruby/SPEC.md +842 -520
- data/lib/submodules/ably-ruby/ably.gemspec +1 -1
- data/lib/submodules/ably-ruby/lib/ably/auth.rb +114 -87
- data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +40 -14
- data/lib/submodules/ably-ruby/lib/ably/models/message.rb +3 -5
- data/lib/submodules/ably-ruby/lib/ably/models/paginated_result.rb +3 -12
- data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +8 -2
- data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +15 -3
- data/lib/submodules/ably-ruby/lib/ably/models/stat.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/models/token_details.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/modules/channels_collection.rb +7 -1
- data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/modules/encodeable.rb +6 -3
- data/lib/submodules/ably-ruby/lib/ably/modules/message_pack.rb +2 -2
- data/lib/submodules/ably-ruby/lib/ably/modules/model_common.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +2 -2
- data/lib/submodules/ably-ruby/lib/ably/realtime.rb +1 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +191 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +97 -25
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +11 -3
- data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +22 -6
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +73 -40
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +48 -33
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +17 -3
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +43 -16
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +57 -26
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +3 -1
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +4 -2
- data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -0
- data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +242 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +277 -5
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channels_spec.rb +64 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +26 -5
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +23 -6
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +167 -16
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +9 -8
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +1 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +121 -10
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +13 -1
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +161 -79
- data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +3 -3
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +142 -15
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +23 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +180 -18
- data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +8 -8
- data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +136 -25
- data/lib/submodules/ably-ruby/spec/acceptance/rest/stats_spec.rb +60 -4
- data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +54 -3
- data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +7 -6
- data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +1 -9
- data/lib/submodules/ably-ruby/spec/unit/models/paginated_result_spec.rb +1 -18
- data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +21 -1
- data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +10 -3
- data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +27 -8
- data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +0 -8
- data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +7 -7
- metadata +5 -2
@@ -26,7 +26,7 @@ module Ably::Realtime
|
|
26
26
|
|
27
27
|
# Commence attachment
|
28
28
|
def detach(error = nil)
|
29
|
-
if connection.closed? || connection.connecting?
|
29
|
+
if connection.closed? || connection.connecting? || connection.suspended?
|
30
30
|
channel.transition_state_machine :detached, error
|
31
31
|
elsif can_transition_to?(:detached)
|
32
32
|
send_detach_protocol_message
|
@@ -59,7 +59,7 @@ module Ably::Realtime
|
|
59
59
|
def fail_messages_awaiting_ack(error)
|
60
60
|
# Allow a short time for other queued operations to complete before failing all messages
|
61
61
|
EventMachine.add_timer(0.1) do
|
62
|
-
error = Ably::Exceptions::
|
62
|
+
error = Ably::Exceptions::MessageDeliveryFailed.new("Channel cannot publish messages whilst state is '#{channel.state}'") unless error
|
63
63
|
fail_messages_in_queue connection.__pending_message_ack_queue__, error
|
64
64
|
fail_messages_in_queue connection.__outgoing_message_queue__, error
|
65
65
|
end
|
@@ -123,8 +123,16 @@ module Ably::Realtime
|
|
123
123
|
channel.transition_state_machine :detaching if can_transition_to?(:detaching)
|
124
124
|
end
|
125
125
|
|
126
|
+
connection.unsafe_on(:suspended) do |error|
|
127
|
+
if can_transition_to?(:detaching)
|
128
|
+
channel.transition_state_machine :detaching, Ably::Exceptions::ConnectionSuspended.new('Connection suspended', nil, 80002, error)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
126
132
|
connection.unsafe_on(:failed) do |error|
|
127
|
-
|
133
|
+
if can_transition_to?(:failed)
|
134
|
+
channel.transition_state_machine :failed, Ably::Exceptions::ConnectionFailed.new('Connection failed', nil, 80002, error)
|
135
|
+
end
|
128
136
|
end
|
129
137
|
end
|
130
138
|
|
@@ -34,10 +34,14 @@ module Ably
|
|
34
34
|
# @return [Ably::Rest::Client]
|
35
35
|
attr_reader :rest_client
|
36
36
|
|
37
|
-
# When false the client suppresses messages originating from this connection being echoed back on the same connection.
|
37
|
+
# When false the client suppresses messages originating from this connection being echoed back on the same connection. Defaults to true
|
38
38
|
# @return [Boolean]
|
39
39
|
attr_reader :echo_messages
|
40
40
|
|
41
|
+
# If false, this disables the default behaviour whereby the library queues messages on a connection in the disconnected or connecting states. Defaults to true
|
42
|
+
# @return [Boolean]
|
43
|
+
attr_reader :queue_messages
|
44
|
+
|
41
45
|
# The custom realtime websocket host that is being used if it was provided with the option `:ws_host` when the {Client} was created
|
42
46
|
# @return [String,Nil]
|
43
47
|
attr_reader :custom_realtime_host
|
@@ -52,7 +56,8 @@ module Ably
|
|
52
56
|
|
53
57
|
def_delegators :auth, :client_id, :auth_options
|
54
58
|
def_delegators :@rest_client, :encoders
|
55
|
-
def_delegators :@rest_client, :
|
59
|
+
def_delegators :@rest_client, :use_tls?, :protocol, :protocol_binary?
|
60
|
+
def_delegators :@rest_client, :environment, :custom_host, :custom_port, :custom_tls_port
|
56
61
|
def_delegators :@rest_client, :log_level
|
57
62
|
|
58
63
|
# Creates a {Ably::Realtime::Client Realtime Client} and configures the {Ably::Auth} object for the connection.
|
@@ -75,9 +80,10 @@ module Ably
|
|
75
80
|
#
|
76
81
|
def initialize(options)
|
77
82
|
@rest_client = Ably::Rest::Client.new(options)
|
78
|
-
@auth =
|
83
|
+
@auth = Ably::Realtime::Auth.new(self)
|
79
84
|
@channels = Ably::Realtime::Channels.new(self)
|
80
85
|
@echo_messages = @rest_client.options.fetch(:echo_messages, true) == false ? false : true
|
86
|
+
@queue_messages = @rest_client.options.fetch(:queue_messages, true) == false ? false : true
|
81
87
|
@custom_realtime_host = @rest_client.options[:realtime_host] || @rest_client.options[:ws_host]
|
82
88
|
@auto_connect = @rest_client.options.fetch(:auto_connect, true) == false ? false : true
|
83
89
|
@recover = @rest_client.options[:recover]
|
@@ -174,12 +180,22 @@ module Ably
|
|
174
180
|
|
175
181
|
private
|
176
182
|
def endpoint_for_host(host)
|
177
|
-
|
183
|
+
port = if use_tls?
|
184
|
+
custom_tls_port
|
185
|
+
else
|
186
|
+
custom_port
|
187
|
+
end
|
188
|
+
|
189
|
+
raise ArgumentError, "Custom port must be an Integer or nil" if port && !port.kind_of?(Integer)
|
190
|
+
|
191
|
+
options = {
|
178
192
|
scheme: use_tls? ? 'wss' : 'ws',
|
179
193
|
host: host
|
180
|
-
|
194
|
+
}
|
195
|
+
options.merge!(port: port) if port
|
196
|
+
|
197
|
+
URI::Generic.build(options)
|
181
198
|
end
|
182
199
|
end
|
183
200
|
end
|
184
201
|
end
|
185
|
-
|
@@ -184,16 +184,23 @@ module Ably
|
|
184
184
|
# @return [EventMachine::Deferrable]
|
185
185
|
# @api private
|
186
186
|
def internet_up?
|
187
|
+
url = "http#{'s' if client.use_tls?}:#{Ably::INTERNET_CHECK.fetch(:url)}"
|
187
188
|
EventMachine::DefaultDeferrable.new.tap do |deferrable|
|
188
|
-
EventMachine::HttpRequest.new(
|
189
|
+
EventMachine::HttpRequest.new(url).get.tap do |http|
|
189
190
|
http.errback do
|
190
191
|
yield false if block_given?
|
191
|
-
deferrable.fail
|
192
|
+
deferrable.fail "Unable to connect to #{url}"
|
192
193
|
end
|
193
194
|
http.callback do
|
194
|
-
|
195
|
-
|
196
|
-
|
195
|
+
EventMachine.next_tick do
|
196
|
+
result = http.response_header.status == 200 && http.response.strip == Ably::INTERNET_CHECK.fetch(:ok_text)
|
197
|
+
yield result if block_given?
|
198
|
+
if result
|
199
|
+
deferrable.succeed
|
200
|
+
else
|
201
|
+
deferrable.fail "Unexpected response from #{url} (#{http.response_header.status})"
|
202
|
+
end
|
203
|
+
end
|
197
204
|
end
|
198
205
|
end
|
199
206
|
end
|
@@ -275,7 +282,7 @@ module Ably
|
|
275
282
|
# @!attribute [r] port
|
276
283
|
# @return [Integer] The default port used for this connection
|
277
284
|
def port
|
278
|
-
client.use_tls? ? 443 : 80
|
285
|
+
client.use_tls? ? client.custom_tls_port || 443 : client.custom_port || 80
|
279
286
|
end
|
280
287
|
|
281
288
|
# @!attribute [r] logger
|
@@ -311,48 +318,51 @@ module Ably
|
|
311
318
|
__outgoing_protocol_msgbus__.publish :protocol_message, protocol_message
|
312
319
|
end
|
313
320
|
|
321
|
+
# @return [EventMachine::Deferrable]
|
314
322
|
# @api private
|
315
323
|
def create_websocket_transport
|
316
|
-
|
324
|
+
EventMachine::DefaultDeferrable.new.tap do |websocket_deferrable|
|
325
|
+
# Getting auth params can be blocking so uses a Deferrable
|
326
|
+
client.auth.auth_params.tap do |auth_deferrable|
|
327
|
+
auth_deferrable.callback do |auth_params|
|
328
|
+
url_params = auth_params.merge(
|
329
|
+
timestamp: as_since_epoch(Time.now),
|
330
|
+
format: client.protocol,
|
331
|
+
echo: client.echo_messages
|
332
|
+
)
|
333
|
+
|
334
|
+
if connection_resumable?
|
335
|
+
url_params.merge! resume: key, connection_serial: serial
|
336
|
+
logger.debug "Resuming connection key #{key} with serial #{serial}"
|
337
|
+
elsif connection_recoverable?
|
338
|
+
url_params.merge! recover: connection_recover_parts[:recover], connection_serial: connection_recover_parts[:connection_serial]
|
339
|
+
logger.debug "Recovering connection with key #{client.recover}"
|
340
|
+
once(:connected, :closed, :failed) do
|
341
|
+
client.disable_automatic_connection_recovery
|
342
|
+
end
|
343
|
+
end
|
317
344
|
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
logger.debug "Recovering connection with key #{client.recover}"
|
332
|
-
once(:connected, :closed, :failed) do
|
333
|
-
client.disable_automatic_connection_recovery
|
345
|
+
url = URI(client.endpoint).tap do |endpoint|
|
346
|
+
endpoint.query = URI.encode_www_form(url_params)
|
347
|
+
end.to_s
|
348
|
+
|
349
|
+
determine_host do |host|
|
350
|
+
begin
|
351
|
+
logger.debug "Connection: Opening socket connection to #{host}:#{port} and URL '#{url}'"
|
352
|
+
@transport = EventMachine.connect(host, port, WebsocketTransport, self, url) do |websocket_transport|
|
353
|
+
websocket_deferrable.succeed websocket_transport
|
354
|
+
end
|
355
|
+
rescue EventMachine::ConnectionError => error
|
356
|
+
websocket_deferrable.fail error
|
357
|
+
end
|
334
358
|
end
|
335
359
|
end
|
336
360
|
|
337
|
-
|
338
|
-
|
339
|
-
end
|
340
|
-
|
341
|
-
callback = proc do |url|
|
342
|
-
determine_host do |host|
|
343
|
-
begin
|
344
|
-
logger.debug "Connection: Opening socket connection to #{host}:#{port} and URL '#{url}'"
|
345
|
-
@transport = EventMachine.connect(host, port, WebsocketTransport, self, url) do |websocket_transport|
|
346
|
-
yield websocket_transport if block_given?
|
347
|
-
end
|
348
|
-
rescue EventMachine::ConnectionError => error
|
349
|
-
manager.connection_opening_failed error
|
361
|
+
auth_deferrable.errback do |error|
|
362
|
+
websocket_deferrable.fail error
|
350
363
|
end
|
351
364
|
end
|
352
365
|
end
|
353
|
-
|
354
|
-
# client.auth.auth_params is a blocking call, so defer this into a thread
|
355
|
-
EventMachine.defer blocking_operation, callback
|
356
366
|
end
|
357
367
|
|
358
368
|
# @api private
|
@@ -388,6 +398,13 @@ module Ably
|
|
388
398
|
resume_callbacks.delete(callback)
|
389
399
|
end
|
390
400
|
|
401
|
+
# Returns false if messages cannot be published as a result of message queueing being disabled
|
402
|
+
# @api private
|
403
|
+
def can_publish_messages?
|
404
|
+
connected? ||
|
405
|
+
( (initialized? || connecting? || disconnected?) && client.queue_messages )
|
406
|
+
end
|
407
|
+
|
391
408
|
# As we are using a state machine, do not allow change_state to be used
|
392
409
|
# #transition_state_machine must be used instead
|
393
410
|
private :change_state
|
@@ -451,8 +468,24 @@ module Ably
|
|
451
468
|
client.recover.to_s.match(RECOVER_REGEX)
|
452
469
|
end
|
453
470
|
|
471
|
+
def production?
|
472
|
+
client.environment.nil? || client.environment == :production
|
473
|
+
end
|
474
|
+
|
475
|
+
def custom_port?
|
476
|
+
if client.use_tls?
|
477
|
+
!!client.custom_tls_port
|
478
|
+
else
|
479
|
+
!!client.custom_port
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
def custom_host?
|
484
|
+
!!client.custom_realtime_host
|
485
|
+
end
|
486
|
+
|
454
487
|
def can_use_fallback_hosts?
|
455
|
-
if
|
488
|
+
if production? && !custom_port? && !custom_host?
|
456
489
|
if connecting? && previous_state
|
457
490
|
use_fallback_if_disconnected? || use_fallback_if_suspended?
|
458
491
|
end
|
@@ -53,20 +53,25 @@ module Ably::Realtime
|
|
53
53
|
end
|
54
54
|
|
55
55
|
unless client.auth.authentication_security_requirements_met?
|
56
|
-
connection.transition_state_machine :failed, Ably::Exceptions::
|
56
|
+
connection.transition_state_machine :failed, Ably::Exceptions::InsecureRequest.new('Cannot use Basic Auth over non-TLS connections', 401, 40103)
|
57
57
|
return
|
58
58
|
end
|
59
59
|
|
60
60
|
logger.debug 'ConnectionManager: Opening a websocket transport connection'
|
61
61
|
|
62
|
-
connection.create_websocket_transport do |
|
63
|
-
|
64
|
-
|
62
|
+
connection.create_websocket_transport.tap do |socket_deferrable|
|
63
|
+
socket_deferrable.callback do |websocket_transport|
|
64
|
+
subscribe_to_transport_events websocket_transport
|
65
|
+
yield websocket_transport if block_given?
|
66
|
+
end
|
67
|
+
socket_deferrable.errback do |error|
|
68
|
+
connection_opening_failed error
|
69
|
+
end
|
65
70
|
end
|
66
71
|
|
67
72
|
logger.debug "ConnectionManager: Setting up automatic connection timeout timer for #{TIMEOUTS.fetch(:open)}s"
|
68
73
|
create_timeout_timer_whilst_in_state(:connect, TIMEOUTS.fetch(:open)) do
|
69
|
-
connection_opening_failed Ably::Exceptions::
|
74
|
+
connection_opening_failed Ably::Exceptions::ConnectionTimeout.new("Connection to Ably timed out after #{TIMEOUTS.fetch(:open)}s", nil, 80014)
|
70
75
|
end
|
71
76
|
end
|
72
77
|
|
@@ -161,10 +166,10 @@ module Ably::Realtime
|
|
161
166
|
end
|
162
167
|
|
163
168
|
unless connection_retry_from_suspended_state?
|
164
|
-
return if connection_retry_for(:disconnected
|
169
|
+
return if connection_retry_for(:disconnected)
|
165
170
|
end
|
166
171
|
|
167
|
-
return if connection_retry_for(:suspended
|
172
|
+
return if connection_retry_for(:suspended)
|
168
173
|
|
169
174
|
# Fallback if no other criteria met
|
170
175
|
connection.transition_state_machine :failed, current_transition.metadata
|
@@ -264,10 +269,10 @@ module Ably::Realtime
|
|
264
269
|
#
|
265
270
|
# @return [Boolean] True if a connection attempt has been set up, false if no further connection attempts can be made for this state
|
266
271
|
#
|
267
|
-
def connection_retry_for(from_state
|
272
|
+
def connection_retry_for(from_state)
|
268
273
|
retry_params = CONNECT_RETRY_CONFIG.fetch(from_state)
|
269
274
|
|
270
|
-
if
|
275
|
+
if can_reattempt_connect_for_state?(from_state)
|
271
276
|
if retries_for_state(from_state, ignore_states: [:connecting]).empty?
|
272
277
|
logger.debug "ConnectionManager: Will attempt reconnect immediately as no previous reconnect attempts made in this state"
|
273
278
|
EventMachine.next_tick { connection.connect }
|
@@ -281,6 +286,14 @@ module Ably::Realtime
|
|
281
286
|
end
|
282
287
|
end
|
283
288
|
|
289
|
+
# True if the client library has not exceeded the configured max_time_in_state for the current State
|
290
|
+
# For example, if the state is disconnected, and has been in a cycle of disconnected > connect > disconnected
|
291
|
+
# so long as the time in this cycle of states is less than max_time_in_state, this will return true
|
292
|
+
def can_reattempt_connect_for_state?(state)
|
293
|
+
retry_params = CONNECT_RETRY_CONFIG.fetch(state)
|
294
|
+
time_spent_attempting_state(state, ignore_states: [:connecting]) < retry_params.fetch(:max_time_in_state)
|
295
|
+
end
|
296
|
+
|
284
297
|
# Returns a float representing the amount of time passed since the first consecutive attempt of this state
|
285
298
|
#
|
286
299
|
# @param (see #retries_for_state)
|
@@ -335,9 +348,13 @@ module Ably::Realtime
|
|
335
348
|
connection.transition_state_machine :closed
|
336
349
|
elsif !connection.closed? && !connection.disconnected?
|
337
350
|
exception = if reason
|
338
|
-
Ably::Exceptions::
|
351
|
+
Ably::Exceptions::ConnectionClosed.new(reason)
|
352
|
+
end
|
353
|
+
if connection_retry_from_suspended_state? || !can_reattempt_connect_for_state?(:disconnected)
|
354
|
+
connection.transition_state_machine :suspended, exception
|
355
|
+
else
|
356
|
+
connection.transition_state_machine :disconnected, exception
|
339
357
|
end
|
340
|
-
connection.transition_state_machine :disconnected, exception
|
341
358
|
end
|
342
359
|
end
|
343
360
|
end
|
@@ -350,35 +367,33 @@ module Ably::Realtime
|
|
350
367
|
end
|
351
368
|
|
352
369
|
@renewing_token = true
|
353
|
-
logger.
|
370
|
+
logger.info "ConnectionManager: Token has expired and is renewable, renewing token now"
|
354
371
|
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
rescue StandardError => auth_error
|
359
|
-
connection.transition_state_machine :failed, auth_error
|
360
|
-
nil
|
361
|
-
end
|
362
|
-
end
|
372
|
+
client.auth.authorise.tap do |authorise_deferrable|
|
373
|
+
authorise_deferrable.callback do |token_details|
|
374
|
+
logger.info 'ConnectionManager: Token renewed succesfully following expiration'
|
363
375
|
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
end
|
376
|
+
state_changed_callback = proc do
|
377
|
+
@renewing_token = false
|
378
|
+
connection.off &state_changed_callback
|
379
|
+
end
|
369
380
|
|
370
|
-
|
381
|
+
connection.unsafe_once :connected, :closed, :failed, &state_changed_callback
|
371
382
|
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
383
|
+
if token_details && !token_details.expired?
|
384
|
+
connection.connect
|
385
|
+
else
|
386
|
+
connection.transition_state_machine :failed, error unless connection.failed?
|
387
|
+
end
|
376
388
|
end
|
377
|
-
end
|
378
389
|
|
379
|
-
|
390
|
+
authorise_deferrable.errback do |auth_error|
|
391
|
+
logger.error "ConnectionManager: Error authorising following token expiry: #{auth_error}"
|
392
|
+
connection.transition_state_machine :failed, auth_error
|
393
|
+
end
|
394
|
+
end
|
380
395
|
else
|
381
|
-
logger.error "ConnectionManager: Token has expired and is not renewable"
|
396
|
+
logger.error "ConnectionManager: Token has expired and is not renewable - #{error}"
|
382
397
|
connection.transition_state_machine :failed, error
|
383
398
|
end
|
384
399
|
end
|
@@ -82,6 +82,7 @@ module Ably::Realtime
|
|
82
82
|
|
83
83
|
return deferrable_succeed(deferrable, &success_block) if state == STATE.Entered
|
84
84
|
|
85
|
+
ensure_presence_publishable_on_connection
|
85
86
|
ensure_channel_attached(deferrable) do
|
86
87
|
if entering?
|
87
88
|
once_or_if(STATE.Entered, else: proc { |args| deferrable_fail deferrable, *args }) do
|
@@ -145,6 +146,7 @@ module Ably::Realtime
|
|
145
146
|
|
146
147
|
return deferrable_succeed(deferrable, &success_block) if state == STATE.Left
|
147
148
|
|
149
|
+
ensure_presence_publishable_on_connection
|
148
150
|
ensure_channel_attached(deferrable) do
|
149
151
|
if leaving?
|
150
152
|
once_or_if(STATE.Left, else: proc { |error|deferrable_fail deferrable, *args }) do
|
@@ -201,6 +203,7 @@ module Ably::Realtime
|
|
201
203
|
|
202
204
|
@data = data
|
203
205
|
|
206
|
+
ensure_presence_publishable_on_connection
|
204
207
|
ensure_channel_attached(deferrable) do
|
205
208
|
send_protocol_message_and_transition_state_to(
|
206
209
|
Ably::Models::PresenceMessage::ACTION.Update,
|
@@ -369,6 +372,12 @@ module Ably::Realtime
|
|
369
372
|
end
|
370
373
|
end
|
371
374
|
|
375
|
+
def ensure_presence_publishable_on_connection
|
376
|
+
if !connection.can_publish_messages?
|
377
|
+
raise Ably::Exceptions::MessageQueueingDisabled.new("Message cannot be published. Client is configured to disallow queueing of messages and connection is currently #{connection.state}")
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
372
381
|
def ensure_channel_attached(deferrable = nil)
|
373
382
|
if channel.attached?
|
374
383
|
yield
|
@@ -413,11 +422,12 @@ module Ably::Realtime
|
|
413
422
|
safe_yield block, self, *args if block_given?
|
414
423
|
EventMachine.next_tick { deferrable.fail self, *args } # allow errback to be added to the returned Deferrable
|
415
424
|
deferrable
|
416
|
-
|
425
|
+
end
|
417
426
|
|
418
427
|
def send_presence_action_for_client(action, client_id, options = {}, &success_block)
|
419
|
-
|
428
|
+
ensure_presence_publishable_on_connection
|
420
429
|
|
430
|
+
deferrable = create_deferrable
|
421
431
|
ensure_channel_attached(deferrable) do
|
422
432
|
send_presence_protocol_message(action, client_id, options).tap do |protocol_message|
|
423
433
|
protocol_message.callback { |message| deferrable_succeed deferrable, &success_block }
|
@@ -428,7 +438,7 @@ module Ably::Realtime
|
|
428
438
|
|
429
439
|
def attach_channel_then
|
430
440
|
if channel.detached? || channel.failed?
|
431
|
-
raise Ably::Exceptions::
|
441
|
+
raise Ably::Exceptions::InvalidStateChange.new("Operation is not allowed when channel is in #{channel.state}", 400, 91001)
|
432
442
|
else
|
433
443
|
channel.unsafe_once(Channel::STATE.Attached) { yield }
|
434
444
|
channel.attach
|
@@ -439,6 +449,10 @@ module Ably::Realtime
|
|
439
449
|
channel.client
|
440
450
|
end
|
441
451
|
|
452
|
+
def connection
|
453
|
+
client.connection
|
454
|
+
end
|
455
|
+
|
442
456
|
def rest_presence
|
443
457
|
client.rest_client.channel(channel.name).presence
|
444
458
|
end
|