class Ant::Bot::Base
Base
class for bot implementation. It wraps the threads execution, the provider and the state storage inside an object.
Public Class Methods
Configurations needed:
-
pool_size: number of threads created in execution
-
provider: a configuration for a thread provider. See supported adapters
-
name: The bot name
-
repository: Configurations about the state storage
# File lib/ant/bot/base.rb, line 23 def initialize(configs) @pool_size = configs['pool_size'] @provider = Ant::Bot::Adapter.from_config(configs['provider']) @commands = Ant::Bot::CommandDefinition.new # TODO: move this to config @repository = Ant::Storage::Repository.from_config( nil, configs['state_repository'] .merge('primary_key' => 'channel_id', 'table' => 'bot_sessions'), {} ) @factory = Ant::Storage::Factory.new(EmptyModel) @factory.register(:default, :json) @factory.register(:json, @repository) end
Public Instance Methods
Stores a parameter into the status
# File lib/ant/bot/base.rb, line 141 def add_param(value) log_debug('Received new param', param: @state[:requested_param].to_sym, value: value) @state[:params][@state[:requested_param].to_sym] = value.raw_message end
Sends a message to get the next parameter from the user
# File lib/ant/bot/base.rb, line 133 def ask_param(param) log_debug('I\'m going to ask the next param', param: param) @provider.send_message(current_channel, "I need you to tell me #{param}") @state[:requested_param] = param.to_s end
stores the command into state
# File lib/ant/bot/base.rb, line 120 def command=(cmd) log_debug('Message set as command', command: cmd) @state[:cmd] = cmd.raw_message @state[:params] = {} end
Checks if the command is ready to be executed
# File lib/ant/bot/base.rb, line 98 def command_ready? cmd = current_command_object cmd.ready?(current_params) end
returns the current_channel
from where the message was sent
# File lib/ant/bot/base.rb, line 115 def current_channel @state[:channel_id] end
Loads command from state
# File lib/ant/bot/base.rb, line 109 def current_command_object command = @state[:cmd] @commands[command] end
loads parameters from state
# File lib/ant/bot/base.rb, line 104 def current_params @state[:params] || {} end
Private implementation for load message
# File lib/ant/bot/base.rb, line 155 def load_state(channel) data = @factory.get(channel) data[:params] = JSON.parse(data[:params], symbolize_names: true) data rescue Ant::Storage::Exceptions::ObjectNotFound @factory.create(channel_id: channel, params: {}.to_json) end
Loads the state from storage
# File lib/ant/bot/base.rb, line 150 def load_state!(channel) @state = load_state(channel) end
validates which is the following parameter required
# File lib/ant/bot/base.rb, line 128 def next_missing_param current_command_object.next_missing_param(current_params) end
Process a single message, this method can be overwriten to enable more complex implementations of commands. It receives a message object.
# File lib/ant/bot/base.rb, line 63 def process_message(message) run_simple_command!(message) end
DSL method for adding simple commands
# File lib/ant/bot/base.rb, line 88 def register_command(name, params, &block) @commands.register_command(name, params, block) end
Starts the bot execution, this is a blocking call.
# File lib/ant/bot/base.rb, line 46 def run @pool = Array.new(@pool_size) do # TODO: Create a subclass with the context execution Ant::DRY::Daemon.new(@pool_size, true) do message = @provider.read_message process_message(message) end end # TODO: Implement an interface for killing the process @pool.each(&:run) # :nocov: # @pool.each(&:await) # :nocov: # end
Method for triggering command
# File lib/ant/bot/base.rb, line 93 def run_command! current_command_object.execute(current_params) end
Executes a command with the easiest definition. It runs a state machine:
-
If the message is a command, set the status to asking params
-
If the message is a param, stores it
-
If the command is ready to be executed, trigger it.
# File lib/ant/bot/base.rb, line 71 def run_simple_command!(message) load_state!(message.channel_id) log_debug('loaded state', message: message.to_h, state: @state.to_h) if message.command? self.command = message else add_param(message) end if command_ready? run_command! else ask_param(next_missing_param) end save_state! end
Saves the state into storage
# File lib/ant/bot/base.rb, line 164 def save_state! json = @state[:params] @state[:params] = json.to_json @state.store @state[:params] = json end
# File lib/ant/bot/base.rb, line 41 def session @repository.connection end