lib/ably/realtime/connection/connection_state_machine.rb in ably-0.1.6 vs lib/ably/realtime/connection/connection_state_machine.rb in ably-0.2.0

- old
+ new

@@ -3,17 +3,32 @@ 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, &block) - if options.fetch(:from, nil).kind_of?(Array) + 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| - super(options.merge(from: from_state), &block) + yield [options.merge(from: from_state)] end else - super + yield [options] end end end # Internal class to manage connection state, recovery and state transitions for an {Ably::Realtime::Connection} @@ -32,63 +47,67 @@ 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] + transition :from => :connecting, :to => [:connected, :failed, :closed, :disconnected] transition :from => :connected, :to => [:disconnected, :suspended, :closed, :failed] - transition :from => :disconnected, :to => [:connecting, :closed] - transition :from => :suspended, :to => [:connecting, :closed] + transition :from => :disconnected, :to => [:connecting, :closed, :failed] + transition :from => :suspended, :to => [:connecting, :closed, :failed] transition :from => :closed, :to => [:connecting] transition :from => :failed, :to => [:connecting] - before_transition(to: [:connecting], from: [:initialized, :closed, :failed]) do |connection| - connection.setup_transport do |transport| - # Transition this StateMachine once the transport is connected or disconnected - # Invalid state changes are simply ignored and logged - transport.on(:disconnected) do - connection.transition_state_machine :disconnected - end - end + after_transition do |connection, transition| + connection.synchronize_state_with_statemachine end - before_transition(to: [:connecting], from: [:disconnected, :suspended]) do |connection| - connection.reconnect_transport + after_transition(to: [:connecting], from: [:initialized, :closed, :failed]) do |connection| + connection.manager.setup_transport end + 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 + end + + after_transition(to: [:disconnected], from: [:connecting]) do |connection, current_transition| + connection.manager.respond_to_transport_disconnected current_transition + end + after_transition(to: [:failed]) do |connection| - connection.transport.disconnect + connection.manager.destroy_transport end before_transition(to: [:closed], from: [:initialized]) do |connection| - connection.timers.fetch(:initializer, []).each(&:cancel) + connection.manager.cancel_initialized_timers end before_transition(to: [:closed], from: [:connecting, :connected, :disconnected, :suspended]) do |connection| - connection.send_protocol_message action: Ably::Models::ProtocolMessage::ACTION.Close - connection.transport.disconnect + connection.manager.close_connection end - after_transition do |connection, transition| - connection.change_state transition.to_state + # 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 end - def initialize(connection) - @connection = connection - super(connection) + def previous_transition + history[-2] end - # Override Statesman's #transition_to to simply log state change failures - def transition_to(*args) - unless super(*args) - logger.debug "Unable to transition to #{args[0]} from #{current_state}" - end + def previous_state + previous_transition.to_state if previous_transition end private - attr_reader :connection - # 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 @@ -100,9 +119,13 @@ # def clear_force_closed_timeouts # timeouts[:close_connection].each do |timeout| # timeout.cancel # end.clear # end + + def connection + object + end def logger connection.logger end end