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