kybus-bot 0.10.0 → 0.11.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/kybus/bot/adapters/debug.rb +7 -4
- data/lib/kybus/bot/adapters/telegram.rb +38 -57
- data/lib/kybus/bot/adapters/telegram_file.rb +2 -2
- data/lib/kybus/bot/adapters/telegram_message.rb +7 -3
- data/lib/kybus/bot/base.rb +73 -59
- data/lib/kybus/bot/command/command_definition.rb +2 -0
- data/lib/kybus/bot/command/command_handler.rb +34 -0
- data/lib/kybus/bot/command/command_state.rb +23 -12
- data/lib/kybus/bot/command/command_state_factory.rb +17 -34
- data/lib/kybus/bot/command/execution_context.rb +1 -1
- data/lib/kybus/bot/command/inline_command_matcher.rb +47 -0
- data/lib/kybus/bot/command/parameter_saver.rb +64 -0
- data/lib/kybus/bot/command/regular_command_matcher.rb +47 -0
- data/lib/kybus/bot/command_executor.rb +41 -73
- data/lib/kybus/bot/dsl_methods.rb +7 -3
- data/lib/kybus/bot/exceptions.rb +16 -0
- data/lib/kybus/bot/forkers/base.rb +61 -0
- data/lib/kybus/bot/forkers/lambda_sqs_forker.rb +41 -0
- data/lib/kybus/bot/forkers/thread_forker.rb +18 -0
- data/lib/kybus/bot/migrator.rb +57 -39
- data/lib/kybus/bot/serialized_message.rb +32 -14
- data/lib/kybus/bot/sidekiq_command_executor.rb +2 -0
- data/lib/kybus/bot/version.rb +1 -1
- metadata +11 -3
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kybus
|
4
|
+
module Bot
|
5
|
+
class ParameterSaver
|
6
|
+
def initialize(executor)
|
7
|
+
@executor = executor
|
8
|
+
end
|
9
|
+
|
10
|
+
def save_token!(message)
|
11
|
+
@executor.execution_context.last_message = message.serialize
|
12
|
+
if @executor.execution_context.expecting_command?
|
13
|
+
command = @executor.channel_factory.command(message.command)
|
14
|
+
set_command(command, message)
|
15
|
+
else
|
16
|
+
save_param!(message)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def save_param!(message)
|
23
|
+
@executor.execution_context.add_param(message.raw_message)
|
24
|
+
save_attachment!(message) if message.has_attachment?
|
25
|
+
end
|
26
|
+
|
27
|
+
def save_attachment!(message)
|
28
|
+
file = @executor.bot.provider.file_builder(message.attachment)
|
29
|
+
@executor.execution_context.add_file(file)
|
30
|
+
end
|
31
|
+
|
32
|
+
def set_command(command, message)
|
33
|
+
if @executor.inline_args && !command
|
34
|
+
search_command_with_inline_arg(message)
|
35
|
+
elsif !@executor.inline_args && !command
|
36
|
+
set_default_command
|
37
|
+
else
|
38
|
+
@executor.execution_context.command = command
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def search_command_with_inline_arg(message)
|
43
|
+
command, values = @executor.channel_factory.command_with_inline_arg(message.raw_message || '')
|
44
|
+
if command
|
45
|
+
set_command_with_values(command, values)
|
46
|
+
else
|
47
|
+
set_default_command
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def set_command_with_values(command, values)
|
52
|
+
@executor.execution_context.command = command
|
53
|
+
values.each do |value|
|
54
|
+
@executor.execution_context.next_param = @executor.execution_context.next_missing_param
|
55
|
+
@executor.execution_context.add_param(value)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def set_default_command
|
60
|
+
@executor.execution_context.command = @executor.channel_factory.default_command
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kybus
|
4
|
+
module Bot
|
5
|
+
class RegularCommandMatcher
|
6
|
+
def initialize(definitions)
|
7
|
+
@definitions = definitions
|
8
|
+
@matchers = build_matchers
|
9
|
+
end
|
10
|
+
|
11
|
+
def find_command(search)
|
12
|
+
@definitions.each do |name, command|
|
13
|
+
matcher = @matchers[name.class]
|
14
|
+
result = matcher&.call(name, command, search)
|
15
|
+
return result if result
|
16
|
+
end
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def build_matchers
|
23
|
+
{
|
24
|
+
String => method(:match_string),
|
25
|
+
Class => method(:match_class),
|
26
|
+
Regexp => method(:match_regexp)
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def match_string(name, command, search)
|
31
|
+
command if name == search
|
32
|
+
end
|
33
|
+
|
34
|
+
def match_class(name, command, search)
|
35
|
+
command if search.is_a?(name)
|
36
|
+
end
|
37
|
+
|
38
|
+
def match_regexp(name, command, search)
|
39
|
+
return unless search.is_a?(String) && name.match?(search)
|
40
|
+
|
41
|
+
storable_command = command.clone
|
42
|
+
storable_command.name = search
|
43
|
+
storable_command
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -4,6 +4,9 @@ require 'forwardable'
|
|
4
4
|
require_relative 'command/command'
|
5
5
|
require_relative 'command/command_definition'
|
6
6
|
require_relative 'command/execution_context'
|
7
|
+
require_relative 'dsl_methods'
|
8
|
+
require_relative 'command/command_handler'
|
9
|
+
require_relative 'command/parameter_saver'
|
7
10
|
|
8
11
|
module Kybus
|
9
12
|
module Bot
|
@@ -11,7 +14,7 @@ module Kybus
|
|
11
14
|
extend Forwardable
|
12
15
|
|
13
16
|
include Kybus::Logger
|
14
|
-
attr_reader :dsl, :bot, :execution_context
|
17
|
+
attr_reader :dsl, :bot, :execution_context, :channel_factory, :inline_args, :error
|
15
18
|
|
16
19
|
def_delegator :execution_context, :save!, :save_execution_context!
|
17
20
|
|
@@ -29,79 +32,32 @@ module Kybus
|
|
29
32
|
@dsl = DSLMethods.new(bot.provider, state, bot)
|
30
33
|
@inline_args = inline_args
|
31
34
|
@precommand_hook = proc {}
|
35
|
+
@parameter_saver = ParameterSaver.new(self)
|
36
|
+
@command_handler = CommandHandler.new(self)
|
32
37
|
end
|
33
38
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
@execution_context = ExecutionContest.new(message.channel_id, @channel_factory)
|
38
|
-
save_token!(message)
|
39
|
-
msg = run_command_or_prepare!
|
40
|
-
save_execution_context!
|
41
|
-
msg
|
42
|
-
end
|
43
|
-
|
44
|
-
def save_param!(message)
|
45
|
-
execution_context.add_param(message.raw_message)
|
46
|
-
return unless message.has_attachment?
|
47
|
-
|
48
|
-
file = bot.provider.file_builder(message.attachment)
|
49
|
-
execution_context.add_file(file)
|
50
|
-
end
|
51
|
-
|
52
|
-
def search_command_with_inline_arg(message)
|
53
|
-
command, values = @channel_factory.command_with_inline_arg(message.raw_message || '')
|
54
|
-
if command
|
55
|
-
execution_context.command = command
|
56
|
-
values.each do |value|
|
57
|
-
execution_context.next_param = execution_context.next_missing_param
|
58
|
-
execution_context.add_param(value)
|
59
|
-
end
|
60
|
-
else
|
61
|
-
execution_context.command = @channel_factory.default_command
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def save_token!(message)
|
66
|
-
execution_context.set_last_message(message.serialize)
|
67
|
-
if execution_context.expecting_command?
|
68
|
-
command = @channel_factory.command(message.command)
|
69
|
-
if @inline_args && !command
|
70
|
-
search_command_with_inline_arg(message)
|
71
|
-
elsif !@inline_args && !command
|
72
|
-
execution_context.command = @channel_factory.default_command
|
73
|
-
else
|
74
|
-
execution_context.command = command
|
75
|
-
end
|
76
|
-
else
|
77
|
-
save_param!(message)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def run_command_or_prepare!
|
82
|
-
if execution_context.ready?
|
83
|
-
@dsl.state = execution_context.state
|
84
|
-
@dsl.instance_eval(&@precommand_hook)
|
85
|
-
msg = run_command!
|
86
|
-
execution_context.clear_command
|
87
|
-
msg
|
39
|
+
def precommand_hook(&)
|
40
|
+
if block_given?
|
41
|
+
@precommand_hook = proc(&)
|
88
42
|
else
|
89
|
-
|
90
|
-
ask_param(param, execution_context.state.command.params_ask_label(param))
|
43
|
+
@precommand_hook
|
91
44
|
end
|
92
45
|
end
|
93
46
|
|
94
|
-
def
|
95
|
-
|
47
|
+
def process_message(message)
|
48
|
+
setup_execution_context(message)
|
49
|
+
@parameter_saver.save_token!(message)
|
50
|
+
msg = @command_handler.run_command_or_prepare!
|
51
|
+
save_execution_context!
|
52
|
+
msg
|
96
53
|
end
|
97
54
|
|
98
55
|
def fallback(error)
|
99
|
-
|
56
|
+
catch_command = @channel_factory.command(error)
|
100
57
|
log_error('Unexpected error', error)
|
101
|
-
execution_context.command =
|
58
|
+
execution_context.command = catch_command if catch_command
|
102
59
|
end
|
103
60
|
|
104
|
-
# Method for triggering command
|
105
61
|
def run_command!
|
106
62
|
execution_context.call!(@dsl)
|
107
63
|
rescue StandardError => e
|
@@ -112,28 +68,40 @@ module Kybus
|
|
112
68
|
end
|
113
69
|
|
114
70
|
def invoke(command, args)
|
115
|
-
|
116
|
-
|
117
|
-
state.store_param(param, value)
|
118
|
-
end
|
119
|
-
run_command_or_prepare!
|
71
|
+
set_state_command(command, args)
|
72
|
+
@command_handler.run_command_or_prepare!
|
120
73
|
end
|
121
74
|
|
122
75
|
def redirect(command_name, args)
|
123
76
|
command = @channel_factory.command(command_name)
|
124
|
-
|
125
|
-
raise "Wrong redirect #{command_name}, #{bot.registered_commands}"
|
126
|
-
end
|
127
|
-
|
77
|
+
validate_redirect(command, command_name, args)
|
128
78
|
invoke(command, args)
|
129
79
|
end
|
130
80
|
|
131
|
-
# Sends a message to get the next parameter from the user
|
132
81
|
def ask_param(param, label = nil)
|
133
82
|
msg = label || "I need you to tell me #{param}"
|
134
|
-
bot.send_message(msg, last_message.channel_id)
|
83
|
+
bot.dsl.send_message(msg, last_message.channel_id)
|
135
84
|
execution_context.next_param = param
|
136
85
|
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def setup_execution_context(message)
|
90
|
+
@execution_context = ExecutionContest.new(message.channel_id, @channel_factory)
|
91
|
+
end
|
92
|
+
|
93
|
+
def set_state_command(command, args)
|
94
|
+
state.command = command
|
95
|
+
command.params.zip(args).each do |param, value|
|
96
|
+
state.store_param(param, value)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def validate_redirect(command, command_name, args)
|
101
|
+
return unless command.nil? || command.params_size != args.size
|
102
|
+
|
103
|
+
raise ::Kybus::Bot::Base::BotError, "Wrong redirect #{command_name}, #{bot.registered_commands}"
|
104
|
+
end
|
137
105
|
end
|
138
106
|
end
|
139
107
|
end
|
@@ -6,7 +6,7 @@ module Kybus
|
|
6
6
|
include Kybus::Logger
|
7
7
|
|
8
8
|
attr_accessor :state
|
9
|
-
attr_reader :provider
|
9
|
+
attr_reader :provider, :args
|
10
10
|
|
11
11
|
def initialize(provider, state, bot)
|
12
12
|
@provider = provider
|
@@ -77,13 +77,17 @@ module Kybus
|
|
77
77
|
state&.command&.name
|
78
78
|
end
|
79
79
|
|
80
|
-
def redirect(*
|
81
|
-
@bot.redirect(*
|
80
|
+
def redirect(*)
|
81
|
+
@bot.redirect(*)
|
82
82
|
end
|
83
83
|
|
84
84
|
def abort(msg = nil)
|
85
85
|
raise ::Kybus::Bot::Base::AbortError, msg
|
86
86
|
end
|
87
|
+
|
88
|
+
def fork(command, arguments = {})
|
89
|
+
@bot.invoke_job(command, arguments)
|
90
|
+
end
|
87
91
|
end
|
88
92
|
end
|
89
93
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kybus
|
4
|
+
module Bot
|
5
|
+
class Base
|
6
|
+
class BotError < StandardError; end
|
7
|
+
class AbortError < BotError; end
|
8
|
+
|
9
|
+
class EmptyMessageError < BotError
|
10
|
+
def initialize
|
11
|
+
super('Message is empty')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kybus
|
4
|
+
module Bot
|
5
|
+
module Forkers
|
6
|
+
class JobNotFound < ::Kybus::Bot::Base::BotError; end
|
7
|
+
class JobNotReady < ::Kybus::Bot::Base::BotError; end
|
8
|
+
|
9
|
+
extend Kybus::DRY::ResourceInjector
|
10
|
+
register(:forkers, {})
|
11
|
+
|
12
|
+
def self.register_forker(name, provider)
|
13
|
+
forkers = resource(:forkers)
|
14
|
+
forkers[name] = provider
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.forker(name)
|
18
|
+
forkers = resource(:forkers)
|
19
|
+
forkers[name]
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.from_config(bot, configs)
|
23
|
+
provider_name = configs&.dig('provider') || 'thread'
|
24
|
+
provider = forker(provider_name)
|
25
|
+
provider.new(bot, configs)
|
26
|
+
end
|
27
|
+
|
28
|
+
class Base
|
29
|
+
include Kybus::Logger
|
30
|
+
|
31
|
+
def initialize(bot, configs)
|
32
|
+
@configs = configs
|
33
|
+
@bot = bot
|
34
|
+
@command_definition = CommandDefinition.new
|
35
|
+
end
|
36
|
+
|
37
|
+
def register_command(command, arguments, &)
|
38
|
+
@command_definition.register_command(command, arguments, &)
|
39
|
+
end
|
40
|
+
|
41
|
+
def fork(command, arguments, dsl)
|
42
|
+
job_definition = @command_definition[command]
|
43
|
+
raise JobNotFound if job_definition.nil?
|
44
|
+
|
45
|
+
raise JobNotReady unless job_definition.ready?(arguments)
|
46
|
+
|
47
|
+
invoke(command, arguments, job_definition, dsl)
|
48
|
+
end
|
49
|
+
|
50
|
+
def handle_job(command, args)
|
51
|
+
job_definition = @command_definition[command]
|
52
|
+
@bot.dsl.instance_eval do
|
53
|
+
@args = args
|
54
|
+
instance_eval(&job_definition.block)
|
55
|
+
end
|
56
|
+
log_info('Job Executed', command:, args:)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kybus
|
4
|
+
module Bot
|
5
|
+
module Forkers
|
6
|
+
class LambdaSQSForker < Base
|
7
|
+
extend Kybus::DRY::ResourceInjector
|
8
|
+
|
9
|
+
def self.register_queue_client(client)
|
10
|
+
register(:sqs, client)
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(bot, configs)
|
14
|
+
super
|
15
|
+
@client = LambdaSQSForker.resource(:sqs)
|
16
|
+
@queue = configs['queue']
|
17
|
+
@queue_url = @client.get_queue_url(queue_name: @queue).queue_url
|
18
|
+
end
|
19
|
+
|
20
|
+
def invoke(command, args, _job_definition, dsl)
|
21
|
+
@client.send_message(queue_url: @queue_url, message_body: make_message(command, args, dsl).to_json)
|
22
|
+
end
|
23
|
+
|
24
|
+
def make_message(command, args, dsl)
|
25
|
+
{
|
26
|
+
job: command,
|
27
|
+
args: args.to_h,
|
28
|
+
state: dsl.state.to_h
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def handle_job(command, args)
|
33
|
+
log_info('Got job from SQS', command:)
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
register_forker('sqs', LambdaSQSForker)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kybus
|
4
|
+
module Bot
|
5
|
+
module Forkers
|
6
|
+
class ThreadForker < Base
|
7
|
+
def invoke(command, args, _job_definition, _dsl)
|
8
|
+
Thread.new do
|
9
|
+
log_info('Forking job', command:)
|
10
|
+
handle_job(command, args)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
register_forker('thread', ThreadForker)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/kybus/bot/migrator.rb
CHANGED
@@ -5,55 +5,73 @@ module Kybus
|
|
5
5
|
module Migrator
|
6
6
|
class << self
|
7
7
|
def run_migrations!(config)
|
8
|
-
|
8
|
+
migrator = migrator_for(config['name'])
|
9
|
+
migrator.run_migrations!(config)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def migrator_for(name)
|
15
|
+
case name
|
9
16
|
when 'sequel'
|
10
|
-
|
17
|
+
SequelMigrator
|
11
18
|
when 'dynamoid'
|
12
|
-
|
19
|
+
DynamoidMigrator
|
13
20
|
else
|
14
|
-
raise "Provider not supported #{
|
21
|
+
raise "Provider not supported #{name}"
|
15
22
|
end
|
16
23
|
end
|
24
|
+
end
|
17
25
|
|
18
|
-
|
26
|
+
class SequelMigrator
|
27
|
+
class << self
|
28
|
+
def run_migrations!(config)
|
29
|
+
require 'sequel'
|
30
|
+
require 'sequel/extensions/migration'
|
19
31
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
String :cmd
|
32
|
-
String :requested_param
|
33
|
-
String :last_message, text: true
|
32
|
+
conn = Sequel.connect(config['endpoint'])
|
33
|
+
conn.create_table?(:bot_sessions) do
|
34
|
+
String :channel_id
|
35
|
+
String :user
|
36
|
+
String :params, text: true
|
37
|
+
String :metadata, text: true
|
38
|
+
String :files, text: true
|
39
|
+
String :cmd
|
40
|
+
String :requested_param
|
41
|
+
String :last_message, text: true
|
42
|
+
end
|
34
43
|
end
|
35
44
|
end
|
45
|
+
end
|
36
46
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
47
|
+
class DynamoidMigrator
|
48
|
+
class << self
|
49
|
+
def run_migrations!(config)
|
50
|
+
repository = Kybus::Storage::Datasource::DynamoidRepository.from_config(
|
51
|
+
'name' => 'dynamoid',
|
52
|
+
'dynamoid_config' => true,
|
53
|
+
'access_key' => config['access_key'],
|
54
|
+
'secret_key' => config['secret_key'],
|
55
|
+
'region' => config['region'],
|
56
|
+
'endpoint' => config['endpoint'],
|
57
|
+
'namespace' => config['namespace'],
|
58
|
+
'table' => 'bot_sessions',
|
59
|
+
'primary_key' => 'channel_id',
|
60
|
+
'fields' => Base::DYNAMOID_FIELDS,
|
61
|
+
'read_capacity' => config['read_capacity'] || 1,
|
62
|
+
'write_capacity' => config['write_capacity'] || 1
|
63
|
+
)
|
64
|
+
|
65
|
+
create_table_if_not_exists(repository)
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def create_table_if_not_exists(repository)
|
71
|
+
return if Dynamoid.adapter.list_tables.include?('bot_sessions')
|
72
|
+
|
73
|
+
repository.model_class.create_table(sync: true)
|
74
|
+
end
|
57
75
|
end
|
58
76
|
end
|
59
77
|
end
|
@@ -2,21 +2,15 @@
|
|
2
2
|
|
3
3
|
module Kybus
|
4
4
|
module Bot
|
5
|
-
# Base
|
5
|
+
# Base implementation for messages from distinct providers
|
6
6
|
class SerializedMessage < Message
|
7
7
|
MANDATORY_FIELDS = %i[channel_id provider message_id user raw_message].freeze
|
8
8
|
|
9
9
|
def initialize(data)
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
missing_keys = MANDATORY_FIELDS.reject { |k| data.keys.include?(k) }
|
16
|
-
raise "BadSerializedMessage: Missing keys `#{missing_keys}', got: #{data}" unless missing_keys.empty?
|
17
|
-
|
18
|
-
@data = data.is_a?(String) ? JSON.parse(data, symbolize_names: true) : data
|
19
|
-
@data[:replied_message] = SerializedMessage.new(@data[:replied_message]) if @data[:replied_message]
|
10
|
+
super()
|
11
|
+
@data = parse_data(data)
|
12
|
+
validate_data!
|
13
|
+
parse_replied_message
|
20
14
|
end
|
21
15
|
|
22
16
|
def self.from_json(json)
|
@@ -32,7 +26,7 @@ module Kybus
|
|
32
26
|
!@data[attachment].nil?
|
33
27
|
end
|
34
28
|
|
35
|
-
def method_missing(method, *_args)
|
29
|
+
def method_missing(method, *_args) # rubocop:disable Style/MissingRespondToMissing
|
36
30
|
@data[method]
|
37
31
|
end
|
38
32
|
|
@@ -40,8 +34,32 @@ module Kybus
|
|
40
34
|
@data.dup
|
41
35
|
end
|
42
36
|
|
43
|
-
def to_json(*
|
44
|
-
@data.to_json(*
|
37
|
+
def to_json(*)
|
38
|
+
@data.to_json(*)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def parse_data(data)
|
44
|
+
data = data.to_h if data.is_a?(SerializedMessage)
|
45
|
+
raise Base::BotError, 'BadSerializedMessage: nil message' if data.nil?
|
46
|
+
|
47
|
+
data = data[:data] if data.is_a?(Hash) && data.key?(:data)
|
48
|
+
data.is_a?(String) ? JSON.parse(data, symbolize_names: true) : data
|
49
|
+
end
|
50
|
+
|
51
|
+
def validate_data!
|
52
|
+
missing_keys = MANDATORY_FIELDS.reject { |k| @data.key?(k) }
|
53
|
+
return if missing_keys.empty?
|
54
|
+
|
55
|
+
raise Base::BotError,
|
56
|
+
"BadSerializedMessage: Missing keys `#{missing_keys}', got: #{@data}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def parse_replied_message
|
60
|
+
return unless @data[:replied_message]
|
61
|
+
|
62
|
+
@data[:replied_message] = SerializedMessage.new(@data[:replied_message])
|
45
63
|
end
|
46
64
|
end
|
47
65
|
end
|