lib/ably/realtime/connection/connection_state_machine.rb in ably-0.6.2 vs lib/ably/realtime/connection/connection_state_machine.rb in ably-0.7.0
- old
+ new
@@ -1,60 +1,32 @@
-require 'statesman'
+require 'ably/modules/state_machine'
module Ably::Realtime
class Connection
- module StatesmanMonkeyPatch
- # Override Statesman's #before_transition to support :from arrays
- # This can be removed once https://github.com/gocardless/statesman/issues/95 is solved
- def before_transition(options = nil, &block)
- arrayify_transition(options) do |options_without_from_array|
- super *options_without_from_array, &block
- end
- end
-
- def after_transition(options = nil, &block)
- arrayify_transition(options) do |options_without_from_array|
- super *options_without_from_array, &block
- end
- end
-
- private
- def arrayify_transition(options, &block)
- if options.nil?
- yield []
- elsif options.fetch(:from, nil).kind_of?(Array)
- options[:from].each do |from_state|
- yield [options.merge(from: from_state)]
- end
- else
- yield [options]
- end
- end
- end
-
- # Internal class to manage connection state, recovery and state transitions for an {Ably::Realtime::Connection}
+ # Internal class to manage connection state, recovery and state transitions for {Ably::Realtime::Connection}
class ConnectionStateMachine
- include Statesman::Machine
- extend StatesmanMonkeyPatch
+ include Ably::Modules::StateMachine
# States supported by this StateMachine match #{Connection::STATE}s
# :initialized
# :connecting
# :connected
# :disconnected
# :suspended
+ # :closing
# :closed
# :failed
Connection::STATE.each_with_index do |state_enum, index|
state state_enum.to_sym, initial: index == 0
end
- transition :from => :initialized, :to => [:connecting, :closed]
- transition :from => :connecting, :to => [:connected, :failed, :closed, :disconnected]
- transition :from => :connected, :to => [:disconnected, :suspended, :closed, :failed]
- transition :from => :disconnected, :to => [:connecting, :closed, :failed]
- transition :from => :suspended, :to => [:connecting, :closed, :failed]
+ transition :from => :initialized, :to => [:connecting, :closing]
+ transition :from => :connecting, :to => [:connected, :failed, :closing, :disconnected, :suspended]
+ transition :from => :connected, :to => [:disconnected, :suspended, :closing, :failed]
+ transition :from => :disconnected, :to => [:connecting, :closing, :suspended, :failed]
+ transition :from => :suspended, :to => [:connecting, :closing, :failed]
+ transition :from => :closing, :to => [:closed]
transition :from => :closed, :to => [:connecting]
transition :from => :failed, :to => [:connecting]
after_transition do |connection, transition|
connection.synchronize_state_with_statemachine
@@ -66,63 +38,48 @@
after_transition(to: [:connecting], from: [:disconnected, :suspended]) do |connection|
connection.manager.reconnect_transport
end
- before_transition(to: [:connected]) do |connection|
- connection.manager.cancel_connection_retry_timers
+ after_transition(to: [:disconnected, :suspended], from: [:connecting]) do |connection, current_transition|
+ connection.manager.respond_to_transport_disconnected_when_connecting current_transition
end
- after_transition(to: [:disconnected], from: [:connecting]) do |connection, current_transition|
- connection.manager.respond_to_transport_disconnected current_transition
+ after_transition(to: [:disconnected], from: [:connected]) do |connection, current_transition|
+ connection.manager.respond_to_transport_disconnected_whilst_connected current_transition
end
- after_transition(to: [:failed]) do |connection|
+ after_transition(to: [:disconnected, :suspended]) do |connection|
+ connection.manager.destroy_transport # never reuse a transport if the connection has failed
+ end
+
+ after_transition(to: [:failed]) do |connection, current_transition|
+ connection.logger.fatal "ConnectionStateMachine: Connection failed - #{current_transition.metadata}"
connection.manager.destroy_transport
end
- before_transition(to: [:closed], from: [:initialized]) do |connection|
- connection.manager.cancel_initialized_timers
+ after_transition(to: [:closing], from: [:initialized, :disconnected, :suspended]) do |connection|
+ connection.manager.force_close_connection
end
- before_transition(to: [:closed], from: [:connecting, :connected, :disconnected, :suspended]) do |connection|
+ after_transition(to: [:closing], from: [:connecting, :connected]) do |connection|
connection.manager.close_connection
end
- # Override Statesman's #transition_to so that:
- # * log state change failures to {Logger}
- def transition_to(state, *args)
- unless result = super(state, *args)
- logger.fatal "ConnectionStateMachine: Unable to transition from #{current_state} => #{state}"
- end
- result
+ before_transition(to: [:closed], from: [:closing]) do |connection|
+ connection.manager.destroy_transport
end
- def previous_transition
- history[-2]
+ # Transitions responsible for updating connection#error_reason
+ before_transition(to: [:disconnected, :suspended, :failed]) do |connection, current_transition|
+ connection.set_failed_connection_error_reason current_transition.metadata
end
- def previous_state
- previous_transition.to_state if previous_transition
+ before_transition(to: [:connected, :closed]) do |connection, current_transition|
+ connection.set_failed_connection_error_reason nil
end
private
- # TODO: Implement once CLOSED ProtocolMessage is sent back from Ably in response to a CLOSE message
- #
- # FORCE_CONNECTION_CLOSED_TIMEOUT = 5
- #
- # def force_closed_unless_server_acknowledge_closed
- # timeouts[:close_connection] << EventMachine::Timer.new(FORCE_CONNECTION_CLOSED_TIMEOUT) do
- # transition_to :closed
- # end
- # end
- #
- # def clear_force_closed_timeouts
- # timeouts[:close_connection].each do |timeout|
- # timeout.cancel
- # end.clear
- # end
-
def connection
object
end
def logger