kybus-bot 0.5.1 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/kybus/bot/adapters/debug.rb +68 -10
- data/lib/kybus/bot/adapters/discord.rb +9 -9
- data/lib/kybus/bot/adapters/telegram.rb +25 -98
- data/lib/kybus/bot/adapters/telegram_file.rb +59 -0
- data/lib/kybus/bot/adapters/telegram_message.rb +61 -0
- data/lib/kybus/bot/base.rb +39 -210
- data/lib/kybus/bot/{command_definition.rb → command/command.rb} +18 -22
- data/lib/kybus/bot/command/command_definition.rb +29 -0
- data/lib/kybus/bot/command/command_state.rb +76 -0
- data/lib/kybus/bot/command/command_state_factory.rb +69 -0
- data/lib/kybus/bot/command/execution_context.rb +63 -0
- data/lib/kybus/bot/command_executor.rb +131 -0
- data/lib/kybus/bot/dsl_methods.rb +79 -0
- data/lib/kybus/bot/message.rb +5 -8
- data/lib/kybus/bot/test.rb +18 -6
- data/lib/kybus/bot/version.rb +1 -1
- metadata +14 -5
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
require_relative 'command/command'
|
5
|
+
require_relative 'command/command_definition'
|
6
|
+
require_relative 'command/execution_context'
|
7
|
+
|
8
|
+
module Kybus
|
9
|
+
module Bot
|
10
|
+
class CommandExecutor
|
11
|
+
extend Forwardable
|
12
|
+
|
13
|
+
include Kybus::Logger
|
14
|
+
attr_reader :dsl, :bot, :execution_context
|
15
|
+
|
16
|
+
def_delegator :execution_context, :save!, :save_execution_context!
|
17
|
+
|
18
|
+
def state
|
19
|
+
execution_context&.state
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(bot, channel_factory, inline_args)
|
23
|
+
@bot = bot
|
24
|
+
@channel_factory = channel_factory
|
25
|
+
@dsl = DSLMethods.new(bot.provider, state, bot)
|
26
|
+
@inline_args = inline_args
|
27
|
+
@precommand_hook = proc {}
|
28
|
+
end
|
29
|
+
|
30
|
+
# Process a single message, this method can be overwriten to enable
|
31
|
+
# more complex implementations of commands. It receives a message object.
|
32
|
+
def process_message(message)
|
33
|
+
@execution_context = ExecutionContest.new(message.channel_id, @channel_factory)
|
34
|
+
save_token!(message)
|
35
|
+
msg = run_command_or_prepare!
|
36
|
+
save_execution_context!
|
37
|
+
msg
|
38
|
+
end
|
39
|
+
|
40
|
+
def save_param!(message)
|
41
|
+
execution_context.add_param(message.raw_message)
|
42
|
+
return unless message.has_attachment?
|
43
|
+
|
44
|
+
file = bot.provider.file_builder(message.attachment)
|
45
|
+
execution_context.add_file(file)
|
46
|
+
end
|
47
|
+
|
48
|
+
def search_command_with_inline_arg(message)
|
49
|
+
command, values = @channel_factory.command_with_inline_arg(message.raw_message)
|
50
|
+
if command
|
51
|
+
execution_context.command = command
|
52
|
+
values.each do |value|
|
53
|
+
execution_context.next_param = execution_context.next_missing_param
|
54
|
+
execution_context.add_param(value)
|
55
|
+
end
|
56
|
+
else
|
57
|
+
execution_context.command = @channel_factory.default_command
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def save_token!(message)
|
62
|
+
if execution_context.expecting_command?
|
63
|
+
command = @channel_factory.command(message.command)
|
64
|
+
if @inline_args && !command
|
65
|
+
search_command_with_inline_arg(message)
|
66
|
+
elsif !@inline_args && !command
|
67
|
+
execution_context.command = @channel_factory.default_command
|
68
|
+
else
|
69
|
+
execution_context.command = command
|
70
|
+
end
|
71
|
+
else
|
72
|
+
save_param!(message)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def run_command_or_prepare!
|
77
|
+
if execution_context.ready?
|
78
|
+
@dsl.state = execution_context.state
|
79
|
+
@dsl.instance_eval(&@precommand_hook)
|
80
|
+
msg = run_command!
|
81
|
+
execution_context.clear_command
|
82
|
+
msg
|
83
|
+
else
|
84
|
+
param = execution_context.next_missing_param
|
85
|
+
ask_param(param, execution_context.state.command.params_ask_label(param))
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def precommand_hook(&block)
|
90
|
+
@precommand_hook = proc(&block)
|
91
|
+
end
|
92
|
+
|
93
|
+
def fallback(error)
|
94
|
+
catch = @channel_factory.command(error)
|
95
|
+
log_error('Unexpected error', error)
|
96
|
+
execution_context.command = catch if catch
|
97
|
+
end
|
98
|
+
|
99
|
+
# Method for triggering command
|
100
|
+
def run_command!
|
101
|
+
execution_context.call!(@dsl)
|
102
|
+
rescue StandardError => e
|
103
|
+
raise unless fallback(e)
|
104
|
+
|
105
|
+
execution_context.state.store_param(:_last_exception, e)
|
106
|
+
retry
|
107
|
+
end
|
108
|
+
|
109
|
+
def invoke(command_name, args)
|
110
|
+
command = @channel_factory.command(command_name)
|
111
|
+
if command.nil? || command.params_size != args.size
|
112
|
+
raise "Wrong redirect #{command_name}, #{bot.registered_commands}"
|
113
|
+
end
|
114
|
+
|
115
|
+
state.command = command
|
116
|
+
command.params.zip(args).each do |param, value|
|
117
|
+
state.store_param(param, value)
|
118
|
+
end
|
119
|
+
run_command_or_prepare!
|
120
|
+
end
|
121
|
+
|
122
|
+
# Sends a message to get the next parameter from the user
|
123
|
+
def ask_param(param, label = nil)
|
124
|
+
provider = bot.provider
|
125
|
+
msg = label || "I need you to tell me #{param}"
|
126
|
+
bot.send_message(provider.last_message.channel_id, msg)
|
127
|
+
execution_context.next_param = param
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kybus
|
4
|
+
module Bot
|
5
|
+
class DSLMethods
|
6
|
+
attr_accessor :state
|
7
|
+
attr_reader :provider
|
8
|
+
|
9
|
+
def initialize(provider, state, bot)
|
10
|
+
@provider = provider
|
11
|
+
@state = state
|
12
|
+
@bot = bot
|
13
|
+
end
|
14
|
+
|
15
|
+
def send_message(content, channel = nil)
|
16
|
+
raise(Base::EmptyMessageError) unless content
|
17
|
+
|
18
|
+
provider.send_message(channel || current_channel, content)
|
19
|
+
end
|
20
|
+
|
21
|
+
def send_image(content, channel = nil, caption: nil)
|
22
|
+
provider.send_image(channel || current_channel, content, caption)
|
23
|
+
end
|
24
|
+
|
25
|
+
def send_video(content, channel = nil, caption: nil)
|
26
|
+
provider.send_video(channel || current_channel, content, caption)
|
27
|
+
end
|
28
|
+
|
29
|
+
def send_audio(content, channel = nil)
|
30
|
+
provider.send_audio(channel || current_channel, content)
|
31
|
+
end
|
32
|
+
|
33
|
+
def send_document(content, channel = nil)
|
34
|
+
provider.send_document(channel || current_channel, content)
|
35
|
+
end
|
36
|
+
|
37
|
+
def params
|
38
|
+
state.params
|
39
|
+
end
|
40
|
+
|
41
|
+
def files
|
42
|
+
state.files
|
43
|
+
end
|
44
|
+
|
45
|
+
def file(name)
|
46
|
+
(file = files[name]) && provider.file_builder(file)
|
47
|
+
end
|
48
|
+
|
49
|
+
def mention(name)
|
50
|
+
provider.mention(name)
|
51
|
+
end
|
52
|
+
|
53
|
+
def current_user
|
54
|
+
provider.last_message.user
|
55
|
+
end
|
56
|
+
|
57
|
+
def is_private?
|
58
|
+
provider.last_message.is_private?
|
59
|
+
end
|
60
|
+
|
61
|
+
def last_message
|
62
|
+
provider.last_message
|
63
|
+
end
|
64
|
+
|
65
|
+
# returns the current_channel from where the message was sent
|
66
|
+
def current_channel
|
67
|
+
state.channel_id
|
68
|
+
end
|
69
|
+
|
70
|
+
def command_name
|
71
|
+
state&.command&.name
|
72
|
+
end
|
73
|
+
|
74
|
+
def method_missing(method, *args, &block)
|
75
|
+
@bot.send(method, *args, &block)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/kybus/bot/message.rb
CHANGED
@@ -8,17 +8,14 @@ module Kybus
|
|
8
8
|
# Base implementation for messages from distinct providers
|
9
9
|
class Message
|
10
10
|
# Converts the messages into a hash
|
11
|
-
def to_h
|
12
|
-
{
|
13
|
-
text: raw_message,
|
14
|
-
channel: channel_id
|
15
|
-
}
|
16
|
-
end
|
17
|
-
|
18
11
|
# Returns true when the received message is a command. Convention states
|
19
12
|
# that messages should start with '/' to be considered commands
|
20
13
|
def command?
|
21
|
-
|
14
|
+
command&.start_with?('/')
|
15
|
+
end
|
16
|
+
|
17
|
+
def command
|
18
|
+
raw_message&.split(' ')&.first
|
22
19
|
end
|
23
20
|
end
|
24
21
|
end
|
data/lib/kybus/bot/test.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'base'
|
2
4
|
require_relative 'adapters/debug'
|
3
5
|
|
@@ -13,19 +15,29 @@ module Kybus
|
|
13
15
|
'pool_size' => 1,
|
14
16
|
'provider' => {
|
15
17
|
'name' => 'debug',
|
16
|
-
'echo' =>
|
18
|
+
'echo' => false,
|
17
19
|
'channels' => { 'testing' => [] }
|
18
20
|
}
|
19
21
|
}.freeze
|
20
22
|
|
21
|
-
def self.make_test_bot
|
22
|
-
|
23
|
+
def self.make_test_bot(extra_configs = {})
|
24
|
+
conf = CONFIG.merge(extra_configs)
|
25
|
+
conf['provider']['channels'] = { conf['channel_id'] => [] } if conf['channel_id']
|
26
|
+
bot = new(conf)
|
27
|
+
bot.instance_variable_set(:@default_channel_id, conf['provider']['channels'].keys.first)
|
28
|
+
bot
|
23
29
|
end
|
24
30
|
|
25
31
|
def receives(msg, attachments = nil)
|
26
|
-
|
27
|
-
|
28
|
-
|
32
|
+
attachments = Adapter::DebugMessage::DebugFile.new(attachments) if attachments
|
33
|
+
msg = Adapter::DebugMessage.new(msg, @default_channel_id, attachments)
|
34
|
+
log_info('Received message', channel: @default_channel_id, msg:)
|
35
|
+
provider.last_message = msg
|
36
|
+
executor.process_message(msg)
|
37
|
+
end
|
38
|
+
|
39
|
+
def expects(method)
|
40
|
+
executor.dsl.expects(method)
|
29
41
|
end
|
30
42
|
end
|
31
43
|
end
|
data/lib/kybus/bot/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kybus-bot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gilberto Vargas
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-05-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: kybus-core
|
@@ -218,8 +218,16 @@ files:
|
|
218
218
|
- lib/kybus/bot/adapters/debug.rb
|
219
219
|
- lib/kybus/bot/adapters/discord.rb
|
220
220
|
- lib/kybus/bot/adapters/telegram.rb
|
221
|
+
- lib/kybus/bot/adapters/telegram_file.rb
|
222
|
+
- lib/kybus/bot/adapters/telegram_message.rb
|
221
223
|
- lib/kybus/bot/base.rb
|
222
|
-
- lib/kybus/bot/
|
224
|
+
- lib/kybus/bot/command/command.rb
|
225
|
+
- lib/kybus/bot/command/command_definition.rb
|
226
|
+
- lib/kybus/bot/command/command_state.rb
|
227
|
+
- lib/kybus/bot/command/command_state_factory.rb
|
228
|
+
- lib/kybus/bot/command/execution_context.rb
|
229
|
+
- lib/kybus/bot/command_executor.rb
|
230
|
+
- lib/kybus/bot/dsl_methods.rb
|
223
231
|
- lib/kybus/bot/message.rb
|
224
232
|
- lib/kybus/bot/migrator.rb
|
225
233
|
- lib/kybus/bot/test.rb
|
@@ -228,7 +236,8 @@ files:
|
|
228
236
|
homepage: https://github.com/tachomex/kybus
|
229
237
|
licenses:
|
230
238
|
- MIT
|
231
|
-
metadata:
|
239
|
+
metadata:
|
240
|
+
rubygems_mfa_required: 'true'
|
232
241
|
post_install_message:
|
233
242
|
rdoc_options: []
|
234
243
|
require_paths:
|
@@ -244,7 +253,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
244
253
|
- !ruby/object:Gem::Version
|
245
254
|
version: '0'
|
246
255
|
requirements: []
|
247
|
-
rubygems_version: 3.
|
256
|
+
rubygems_version: 3.4.10
|
248
257
|
signing_key:
|
249
258
|
specification_version: 4
|
250
259
|
summary: Provides a framework for building bots with ruby
|