Class: Ant::Bot::Base

Inherits:
Object
  • Object
show all
Includes:
Logger, Storage::Datasource
Defined in:
lib/ant/bot/base.rb

Overview

Base class for bot implementation. It wraps the threads execution, the provider and the state storage inside an object.

Instance Method Summary collapse

Constructor Details

#initialize(configs) ⇒ Base

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



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 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,
    { 'name' => 'json',
      'schema_name' => configs['name'],
      'storage' => 'storage/$name',
      'primary_key' => 'channel_id' },
    {}
  )
  @factory = Ant::Storage::Factory.new(EmptyModel)
  @factory.register(:default, :json)
  @factory.register(:json, @repository)
end

Instance Method Details

#add_param(value) ⇒ Object

Stores a parameter into the status



138
139
140
141
142
143
144
# File 'lib/ant/bot/base.rb', line 138

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

#ask_param(param) ⇒ Object

Sends a message to get the next parameter from the user



130
131
132
133
134
135
# File 'lib/ant/bot/base.rb', line 130

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
end

#command=(cmd) ⇒ Object

stores the command into state



117
118
119
120
121
122
# File 'lib/ant/bot/base.rb', line 117

def command=(cmd)
  log_debug('Message set as command', command: cmd)

  @state[:cmd] = cmd.raw_message
  @state[:params] = {}
end

#command_ready?Boolean

Checks if the command is ready to be executed

Returns:

  • (Boolean)


95
96
97
98
# File 'lib/ant/bot/base.rb', line 95

def command_ready?
  cmd = current_command_object
  cmd.ready?(current_params)
end

#current_channelObject

returns the current_channel from where the message was sent



112
113
114
# File 'lib/ant/bot/base.rb', line 112

def current_channel
  @state[:channel_id]
end

#current_command_objectObject

Loads command from state



106
107
108
109
# File 'lib/ant/bot/base.rb', line 106

def current_command_object
  command = @state[:cmd]
  @commands[command]
end

#current_paramsObject

loads parameters from state



101
102
103
# File 'lib/ant/bot/base.rb', line 101

def current_params
  @state[:params] || {}
end

#load_state(channel) ⇒ Object

Private implementation for load message



152
153
154
155
156
# File 'lib/ant/bot/base.rb', line 152

def load_state(channel)
  @factory.get(channel)
rescue Ant::Storage::Exceptions::ObjectNotFound
  @factory.create(channel_id: channel, params: {})
end

#load_state!(channel) ⇒ Object

Loads the state from storage



147
148
149
# File 'lib/ant/bot/base.rb', line 147

def load_state!(channel)
  @state = load_state(channel)
end

#next_missing_paramObject

validates which is the following parameter required



125
126
127
# File 'lib/ant/bot/base.rb', line 125

def next_missing_param
  current_command_object.next_missing_param(current_params)
end

#process_message(message) ⇒ Object

Process a single message, this method can be overwriten to enable more complex implementations of commands. It receives a message object.



60
61
62
# File 'lib/ant/bot/base.rb', line 60

def process_message(message)
  run_simple_command!(message)
end

#register_command(name, params, &block) ⇒ Object

DSL method for adding simple commands



85
86
87
# File 'lib/ant/bot/base.rb', line 85

def register_command(name, params, &block)
  @commands.register_command(name, params, block)
end

#runObject

Starts the bot execution, this is a blocking call.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/ant/bot/base.rb', line 43

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

#run_command!Object

Method for triggering command



90
91
92
# File 'lib/ant/bot/base.rb', line 90

def run_command!
  current_command_object.execute(current_params)
end

#run_simple_command!(message) ⇒ Object

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.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/ant/bot/base.rb', line 68

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

#save_state!Object

Saves the state into storage



159
160
161
# File 'lib/ant/bot/base.rb', line 159

def save_state!
  @state.store
end