Class: Ably::Realtime::Connection::ConnectionManager Private
- Inherits:
-
Object
- Object
- Ably::Realtime::Connection::ConnectionManager
- Defined in:
- lib/ably/realtime/connection/connection_manager.rb
Overview
This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.
ConnectionManager is responsible for all actions relating to underlying connection and transports, such as opening, closing, attempting reconnects etc. Connection state changes are performed by this class and executed from ConnectionStateMachine
This is a private class and should never be used directly by developers as the API is likely to change in future.
Constant Summary collapse
- RESOLVABLE_ERROR_CODES =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Error codes from the server that can potentially be resolved
{ token_expired: Ably::Rest::Middleware::Exceptions::TOKEN_EXPIRED_CODE }
Instance Method Summary collapse
-
#close_connection ⇒ Object
private
Send a Close Models::ProtocolMessage to the server and release the transport.
-
#connected(protocol_message) ⇒ Object
private
Called whenever a new connection is made.
-
#connection_opening_failed(error) ⇒ Object
private
Called by the transport when a connection attempt fails.
-
#destroy_transport ⇒ Object
private
Ensures the underlying transport has been disconnected and all event emitter callbacks removed.
-
#error_received_from_server(error) ⇒ Object
private
ProtocolMessage Error received from server.
-
#fail(error) ⇒ Object
private
Connection has failed.
-
#force_close_connection ⇒ Object
private
Close the underlying transport immediately and set the connection state to closed.
-
#initialize(connection) ⇒ ConnectionManager
constructor
private
A new instance of ConnectionManager.
-
#reconnect_transport ⇒ Object
private
Reconnect the WebsocketTransport if possible, otherwise set up a new transport.
-
#respond_to_transport_disconnected_when_connecting(error) ⇒ Object
private
When a connection is disconnected whilst connecting, attempt reconnect and/or set state to :suspended or :failed.
-
#respond_to_transport_disconnected_whilst_connected(error) ⇒ Object
private
When a connection is disconnected after connecting, attempt reconnect and/or set state to :suspended or :failed.
-
#retry_count_for_state(state) ⇒ Integer
private
Number of consecutive attempts for provided state.
-
#setup_transport {|Ably::Realtime::Connection::WebsocketTransport| ... } ⇒ Object
private
Creates and sets up a new WebsocketTransport available on attribute #transport.
Constructor Details
#initialize(connection) ⇒ ConnectionManager
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns a new instance of ConnectionManager.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 18 def initialize(connection) @connection = connection @timers = Hash.new { |hash, key| hash[key] = [] } @renewing_token = false connection.unsafe_on(:closed) do connection.reset_resume_info end connection.unsafe_once(:connecting) do close_connection_when_reactor_is_stopped end EventMachine.next_tick do # Connect once Connection object is initialised connection.connect if client.auto_connect && connection.can_transition_to?(:connecting) end end |
Instance Method Details
#close_connection ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Send a Close Models::ProtocolMessage to the server and release the transport
126 127 128 129 130 131 132 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 126 def close_connection connection.(action: Ably::Models::ProtocolMessage::ACTION.Close) create_timeout_timer_whilst_in_state(:closing, realtime_request_timeout) do force_close_connection if connection.closing? end end |
#connected(protocol_message) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Called whenever a new connection is made
86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 86 def connected() if connection.key if .connection_id == connection.id logger.debug "ConnectionManager: Connection resumed successfully - ID #{connection.id} and key #{connection.key}" EventMachine.next_tick { connection.resumed } else logger.debug "ConnectionManager: Connection was not resumed, old connection ID #{connection.id} has been updated with new connect ID #{.connection_id} and key #{.connection_key}" detach_attached_channels .error end else logger.debug "ConnectionManager: New connection created with ID #{.connection_id} and key #{.connection_key}" end connection.configure_new .connection_id, .connection_key, .connection_serial end |
#connection_opening_failed(error) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Called by the transport when a connection attempt fails
72 73 74 75 76 77 78 79 80 81 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 72 def connection_opening_failed(error) if error.kind_of?(Ably::Exceptions::IncompatibleClientId) client.connection.transition_state_machine :failed, reason: error return end logger.warn "ConnectionManager: Connection to #{connection.current_host}:#{connection.port} failed; #{error.}" next_state = get_next_retry_state_info connection.transition_state_machine next_state.fetch(:state), retry_in: next_state.fetch(:pause), reason: Ably::Exceptions::ConnectionError.new("Connection failed: #{error.}", nil, 80000) end |
#destroy_transport ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Ensures the underlying transport has been disconnected and all event emitter callbacks removed
104 105 106 107 108 109 110 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 104 def destroy_transport if transport unsubscribe_from_transport_events transport transport.close_connection connection.release_websocket_transport end end |
#error_received_from_server(error) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
ProtocolMessage Error received from server. Some error states can be resolved by the client library.
200 201 202 203 204 205 206 207 208 209 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 200 def error_received_from_server(error) case error.code when RESOLVABLE_ERROR_CODES.fetch(:token_expired) next_state = get_next_retry_state_info connection.transition_state_machine next_state.fetch(:state), retry_in: next_state.fetch(:pause), reason: error else logger.error "ConnectionManager: Error #{error.class.name} code #{error.code} received from server '#{error.}', transitioning to failed state" connection.transition_state_machine :failed, reason: error end end |
#fail(error) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Connection has failed
145 146 147 148 149 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 145 def fail(error) connection.logger.fatal "ConnectionManager: Connection failed - #{error}" connection.manager.destroy_transport connection.unsafe_once(:failed) { connection.emit :error, error } end |
#force_close_connection ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Close the underlying transport immediately and set the connection state to closed
137 138 139 140 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 137 def force_close_connection destroy_transport connection.transition_state_machine :closed end |
#reconnect_transport ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Reconnect the WebsocketTransport if possible, otherwise set up a new transport
115 116 117 118 119 120 121 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 115 def reconnect_transport if !transport || transport.disconnected? setup_transport else transport.reconnect connection.current_host, connection.port end end |
#respond_to_transport_disconnected_when_connecting(error) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
When a connection is disconnected whilst connecting, attempt reconnect and/or set state to :suspended or :failed
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 154 def respond_to_transport_disconnected_when_connecting(error) return unless connection.disconnected? || connection.suspended? # do nothing if state has changed through an explicit request return unless can_retry_connection? # do not always reattempt connection or change state as client may be re-authorising if error.kind_of?(Ably::Models::ErrorInfo) if RESOLVABLE_ERROR_CODES.fetch(:token_expired).include?(error.code) next_state = get_next_retry_state_info logger.debug "ConnectionManager: Transport disconnected because of token expiry, pausing #{next_state.fetch(:pause)}s before reattempting to connect" EventMachine.add_timer(next_state.fetch(:pause)) { renew_token_and_reconnect error } return end end if connection.state == :suspended return if connection_retry_for(:suspended) elsif connection.state == :disconnected return if connection_retry_for(:disconnected) end # Fallback if no other criteria met connection.transition_state_machine :failed, reason: error end |
#respond_to_transport_disconnected_whilst_connected(error) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
When a connection is disconnected after connecting, attempt reconnect and/or set state to :suspended or :failed
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 180 def respond_to_transport_disconnected_whilst_connected(error) unless connection.disconnected? || connection.suspended? logger.warn "ConnectionManager: Connection #{"to #{connection.transport.url}" if connection.transport} was disconnected unexpectedly" else logger.debug "ConnectionManager: Transport disconnected whilst connection in #{connection.state} state" end if error.kind_of?(Ably::Models::ErrorInfo) && !RESOLVABLE_ERROR_CODES.fetch(:token_expired).include?(error.code) connection.emit :error, error logger.error "ConnectionManager: Error in Disconnected ProtocolMessage received from the server - #{error}" end destroy_transport respond_to_transport_disconnected_when_connecting error end |
#retry_count_for_state(state) ⇒ Integer
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Number of consecutive attempts for provided state
214 215 216 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 214 def retry_count_for_state(state) retries_for_state(state, ignore_states: [:connecting]).count end |
#setup_transport {|Ably::Realtime::Connection::WebsocketTransport| ... } ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Creates and sets up a new WebsocketTransport available on attribute #transport
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 41 def setup_transport if transport && !transport.ready_for_release? raise RuntimeError, 'Existing WebsocketTransport is connected, and must be closed first' end unless client.auth.authentication_security_requirements_met? connection.transition_state_machine :failed, reason: Ably::Exceptions::InsecureRequest.new('Cannot use Basic Auth over non-TLS connections', 401, 40103) return end logger.debug 'ConnectionManager: Opening a websocket transport connection' connection.create_websocket_transport.tap do |socket_deferrable| socket_deferrable.callback do |websocket_transport| subscribe_to_transport_events websocket_transport yield websocket_transport if block_given? end socket_deferrable.errback do |error| connection_opening_failed error end end logger.debug "ConnectionManager: Setting up automatic connection timeout timer for #{realtime_request_timeout}s" create_timeout_timer_whilst_in_state(:connecting, realtime_request_timeout) do connection_opening_failed Ably::Exceptions::ConnectionTimeout.new("Connection to Ably timed out after #{realtime_request_timeout}s", nil, 80014) end end |