lib/socrates/core/dispatcher.rb in socrates-0.1.1 vs lib/socrates/core/dispatcher.rb in socrates-0.1.2
- old
+ new
@@ -61,49 +61,64 @@
private
DEFAULT_ERROR_MESSAGE = "Sorry, an error occurred. We'll have to start over..."
+ # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
def fetch_snapshot(client_id)
- state_data =
- if @storage.has_key?(client_id)
- begin
- snapshot = @storage.get(client_id)
- StateData.deserialize(snapshot)
- rescue => e
- @logger.warn "Error while fetching snapshot for client id '#{client_id}', resetting state: #{e.message}"
- @logger.warn e
- end
+ if @storage.has_key?(client_id)
+ begin
+ snapshot = @storage.get(client_id)
+ state_data = StateData.deserialize(snapshot)
+ rescue => e
+ @logger.warn "Error while fetching snapshot for client id '#{client_id}', resetting state: #{e.message}"
+ @logger.warn e
end
+ end
state_data ||= StateData.new
# If the current state is nil or END_OF_CONVERSATION, set it to the default state, which is typically a state
# that waits for an initial command or input from the user (e.g. help, start, etc).
if state_data.state_id.nil? || state_data.state_id == State::END_OF_CONVERSATION
- state_data.state_id = @state_factory.default_state
- state_data.state_action = :listen
+ default_state, default_action = @state_factory.default
+
+ state_data.state_id = default_state
+ state_data.state_action = default_action || :listen
+
+ # Check to see if the last interation was too long ago.
+ elsif state_data_expired?(state_data) && @state_factory.expired(state_data).present?
+ expired_state, expired_action = @state_factory.expired(state_data)
+
+ state_data.state_id = expired_state
+ state_data.state_action = expired_action || :ask
end
state_data
end
+ # rubocop:enable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
def persist_snapshot(client_id, state_data)
+ state_data.reset_elapsed_time
@storage.put(client_id, state_data.serialize)
end
+ def state_data_expired?(state_data)
+ return unless state_data.timestamp.present?
+
+ state_data.elapsed_time > (Config.expired_timeout || 30.minutes)
+ end
+
def instantiate_state(state_data, context)
@state_factory.build(state_data: state_data, adapter: @adapter, context: context)
end
def done_transitioning?(state)
# Stop transitioning if we're waiting for the user to respond (i.e. we're listening).
return true if state.data.state_action == :listen
# Stop transitioning if there's no state to transition to, or the conversation has ended.
- return true if state.data.state_id.nil? || state.data.state_id == State::END_OF_CONVERSATION
-
- false
+ state.data.state_id.nil? || state.data.state_id == State::END_OF_CONVERSATION
end
def handle_action_error(e, client_id, state, context)
@logger.warn "Error while processing action #{state.data.state_id}/#{state.data.state_action}: #{e.message}"
@logger.warn e