stealth 1.1.6 → 2.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +15 -54
- data/CHANGELOG.md +72 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +49 -44
- data/LICENSE +4 -17
- data/README.md +9 -17
- data/VERSION +1 -1
- data/lib/stealth/base.rb +62 -15
- data/lib/stealth/cli.rb +1 -2
- data/lib/stealth/commands/console.rb +1 -1
- data/lib/stealth/configuration.rb +0 -3
- data/lib/stealth/controller/callbacks.rb +1 -1
- data/lib/stealth/controller/catch_all.rb +27 -4
- data/lib/stealth/controller/controller.rb +168 -49
- data/lib/stealth/controller/dev_jumps.rb +41 -0
- data/lib/stealth/controller/dynamic_delay.rb +4 -6
- data/lib/stealth/controller/interrupt_detect.rb +100 -0
- data/lib/stealth/controller/messages.rb +283 -0
- data/lib/stealth/controller/nlp.rb +50 -0
- data/lib/stealth/controller/replies.rb +178 -40
- data/lib/stealth/controller/unrecognized_message.rb +62 -0
- data/lib/stealth/core_ext.rb +5 -0
- data/lib/stealth/{flow/core_ext.rb → core_ext/numeric.rb} +0 -1
- data/lib/stealth/core_ext/string.rb +18 -0
- data/lib/stealth/dispatcher.rb +21 -0
- data/lib/stealth/errors.rb +12 -0
- data/lib/stealth/flow/base.rb +1 -2
- data/lib/stealth/flow/specification.rb +3 -2
- data/lib/stealth/flow/state.rb +3 -3
- data/lib/stealth/generators/builder/Gemfile +4 -3
- data/lib/stealth/generators/builder/bot/controllers/bot_controller.rb +42 -0
- data/lib/stealth/generators/builder/bot/controllers/catch_alls_controller.rb +2 -0
- data/lib/stealth/generators/builder/bot/controllers/goodbyes_controller.rb +2 -0
- data/lib/stealth/generators/builder/bot/controllers/hellos_controller.rb +2 -0
- data/lib/stealth/generators/builder/bot/controllers/interrupts_controller.rb +9 -0
- data/lib/stealth/generators/builder/bot/controllers/unrecognized_messages_controller.rb +9 -0
- data/lib/stealth/generators/builder/config/flow_map.rb +8 -0
- data/lib/stealth/generators/builder/config/initializers/autoload.rb +8 -0
- data/lib/stealth/generators/builder/config/initializers/inflections.rb +16 -0
- data/lib/stealth/generators/builder/config/puma.rb +15 -0
- data/lib/stealth/helpers/redis.rb +40 -0
- data/lib/stealth/lock.rb +83 -0
- data/lib/stealth/logger.rb +27 -18
- data/lib/stealth/nlp/client.rb +22 -0
- data/lib/stealth/nlp/result.rb +57 -0
- data/lib/stealth/reloader.rb +90 -0
- data/lib/stealth/reply.rb +17 -0
- data/lib/stealth/scheduled_reply.rb +3 -3
- data/lib/stealth/server.rb +3 -3
- data/lib/stealth/service_message.rb +3 -2
- data/lib/stealth/service_reply.rb +5 -1
- data/lib/stealth/services/base_reply_handler.rb +2 -2
- data/lib/stealth/session.rb +106 -53
- data/spec/configuration_spec.rb +9 -2
- data/spec/controller/callbacks_spec.rb +23 -28
- data/spec/controller/catch_all_spec.rb +81 -29
- data/spec/controller/controller_spec.rb +444 -43
- data/spec/controller/dynamic_delay_spec.rb +16 -18
- data/spec/controller/helpers_spec.rb +1 -2
- data/spec/controller/interrupt_detect_spec.rb +171 -0
- data/spec/controller/messages_spec.rb +744 -0
- data/spec/controller/nlp_spec.rb +93 -0
- data/spec/controller/replies_spec.rb +446 -11
- data/spec/controller/unrecognized_message_spec.rb +168 -0
- data/spec/dispatcher_spec.rb +79 -0
- data/spec/flow/flow_spec.rb +1 -2
- data/spec/flow/state_spec.rb +14 -3
- data/spec/helpers/redis_spec.rb +77 -0
- data/spec/lock_spec.rb +100 -0
- data/spec/nlp/client_spec.rb +23 -0
- data/spec/nlp/result_spec.rb +57 -0
- data/spec/replies/messages/say_msgs_without_breaks.yml +4 -0
- data/spec/replies/messages/say_randomize_speech.yml +10 -0
- data/spec/replies/messages/say_randomize_text.yml +10 -0
- data/spec/replies/messages/sub1/sub2/say_nested.yml +10 -0
- data/spec/reply_spec.rb +61 -0
- data/spec/scheduled_reply_spec.rb +23 -0
- data/spec/service_reply_spec.rb +1 -2
- data/spec/session_spec.rb +251 -12
- data/spec/spec_helper.rb +21 -0
- data/spec/support/controllers/vaders_controller.rb +24 -0
- data/spec/support/nlp_clients/dialogflow.rb +9 -0
- data/spec/support/nlp_clients/luis.rb +9 -0
- data/spec/support/nlp_results/luis_result.rb +163 -0
- data/spec/version_spec.rb +1 -2
- data/stealth.gemspec +6 -6
- metadata +83 -38
- data/docs/00-introduction.md +0 -37
- data/docs/01-getting-started.md +0 -21
- data/docs/02-local-development.md +0 -40
- data/docs/03-basics.md +0 -171
- data/docs/04-sessions.md +0 -29
- data/docs/05-controllers.md +0 -179
- data/docs/06-models.md +0 -39
- data/docs/07-replies.md +0 -114
- data/docs/08-catchalls.md +0 -49
- data/docs/09-messaging-integrations.md +0 -80
- data/docs/10-nlp-integrations.md +0 -13
- data/docs/11-analytics.md +0 -13
- data/docs/12-commands.md +0 -62
- data/docs/13-deployment.md +0 -50
- data/lib/stealth/generators/builder/config/initializers/.keep +0 -0
data/lib/stealth/cli.rb
CHANGED
@@ -80,7 +80,6 @@ module Stealth
|
|
80
80
|
|
81
81
|
$ > stealth console --engine=pry
|
82
82
|
EOS
|
83
|
-
method_option :environment, desc: 'Path to environment configuration (config/environment.rb)'
|
84
83
|
method_option :engine, desc: "Choose a specific console engine: (#{Stealth::Commands::Console::ENGINES.keys.join('/')})"
|
85
84
|
method_option :help, desc: 'Displays the usage method'
|
86
85
|
def console
|
@@ -114,7 +113,7 @@ module Stealth
|
|
114
113
|
EOS
|
115
114
|
define_method 'sessions:clear' do
|
116
115
|
Stealth.load_environment
|
117
|
-
$redis.flushdb if Stealth.env
|
116
|
+
$redis.flushdb if Stealth.env.development?
|
118
117
|
end
|
119
118
|
|
120
119
|
|
@@ -1,8 +1,6 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require 'thread'
|
5
|
-
|
6
4
|
module Stealth
|
7
5
|
class Configuration < Hash
|
8
6
|
|
@@ -20,7 +18,6 @@ module Stealth
|
|
20
18
|
if setter?(method)
|
21
19
|
self[key] = args.first
|
22
20
|
else
|
23
|
-
super(method, args) && return unless key?(key)
|
24
21
|
self[key]
|
25
22
|
end
|
26
23
|
end
|
@@ -13,7 +13,7 @@ module Stealth
|
|
13
13
|
define_callbacks :action, skip_after_callbacks_if_terminated: true
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
class_methods do
|
17
17
|
def _normalize_callback_options(options)
|
18
18
|
_normalize_callback_option(options, :only, :if)
|
19
19
|
_normalize_callback_option(options, :except, :unless)
|
@@ -9,18 +9,41 @@ module Stealth
|
|
9
9
|
|
10
10
|
included do
|
11
11
|
|
12
|
-
def run_catch_all(
|
12
|
+
def run_catch_all(err:)
|
13
13
|
error_level = fetch_error_level
|
14
|
-
|
14
|
+
|
15
|
+
if err.class == Stealth::Errors::UnrecognizedMessage
|
16
|
+
Stealth::Logger.l(
|
17
|
+
topic: 'catch_all',
|
18
|
+
message: "[Level #{error_level}] for user #{current_session_id} #{err.message}"
|
19
|
+
)
|
20
|
+
else
|
21
|
+
Stealth::Logger.l(
|
22
|
+
topic: 'catch_all',
|
23
|
+
message: "[Level #{error_level}] for user #{current_session_id} #{[err.class, err.message, err.backtrace.join("\n")].join("\n")}"
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Store the reason so it can be accessed by the CatchAllsController
|
28
|
+
current_message.catch_all_reason = {
|
29
|
+
err: err.class,
|
30
|
+
err_msg: err.message
|
31
|
+
}
|
32
|
+
|
33
|
+
# Don't run catch_all from the catch_all controller
|
34
|
+
if current_session.flow_string == 'catch_all'
|
35
|
+
Stealth::Logger.l(topic: 'catch_all', message: "CatchAll triggered for user #{current_session_id} from within CatchAll; ignoring.")
|
36
|
+
return false
|
37
|
+
end
|
15
38
|
|
16
39
|
if defined?(CatchAllsController) && FlowMap.flow_spec[:catch_all].present?
|
17
40
|
catch_all_state = calculate_catch_all_state(error_level)
|
18
41
|
|
19
42
|
if FlowMap.flow_spec[:catch_all].states.keys.include?(catch_all_state.to_sym)
|
20
|
-
step_to flow:
|
43
|
+
step_to flow: :catch_all, state: catch_all_state
|
21
44
|
else
|
22
45
|
# We are out of bounds, do nothing to prevent an infinite loop
|
23
|
-
Stealth::Logger.l(topic:
|
46
|
+
Stealth::Logger.l(topic: 'catch_all', message: "Stopping; we\'ve exceeded the number of defined catch_all states for user #{current_session_id}.")
|
24
47
|
return false
|
25
48
|
end
|
26
49
|
end
|
@@ -7,18 +7,24 @@ module Stealth
|
|
7
7
|
include Stealth::Controller::Callbacks
|
8
8
|
include Stealth::Controller::DynamicDelay
|
9
9
|
include Stealth::Controller::Replies
|
10
|
+
include Stealth::Controller::Messages
|
11
|
+
include Stealth::Controller::UnrecognizedMessage
|
10
12
|
include Stealth::Controller::CatchAll
|
11
13
|
include Stealth::Controller::Helpers
|
14
|
+
include Stealth::Controller::InterruptDetect
|
15
|
+
include Stealth::Controller::DevJumps
|
16
|
+
include Stealth::Controller::Nlp
|
12
17
|
|
13
|
-
attr_reader :current_message, :
|
14
|
-
:
|
15
|
-
|
18
|
+
attr_reader :current_message, :current_service, :flow_controller,
|
19
|
+
:action_name, :current_session_id
|
20
|
+
attr_accessor :nlp_result, :pos
|
16
21
|
|
17
|
-
def initialize(service_message:,
|
22
|
+
def initialize(service_message:, pos: nil)
|
18
23
|
@current_message = service_message
|
19
24
|
@current_service = service_message.service
|
20
|
-
@
|
21
|
-
@
|
25
|
+
@current_session_id = service_message.sender_id
|
26
|
+
@nlp_result = service_message.nlp_result
|
27
|
+
@pos = pos
|
22
28
|
@progressed = false
|
23
29
|
end
|
24
30
|
|
@@ -31,7 +37,7 @@ module Stealth
|
|
31
37
|
end
|
32
38
|
|
33
39
|
def progressed?
|
34
|
-
@progressed
|
40
|
+
@progressed
|
35
41
|
end
|
36
42
|
|
37
43
|
def route
|
@@ -41,104 +47,217 @@ module Stealth
|
|
41
47
|
def flow_controller
|
42
48
|
@flow_controller ||= begin
|
43
49
|
flow_controller = [current_session.flow_string.pluralize, 'controller'].join('_').classify.constantize
|
44
|
-
flow_controller.new(
|
45
|
-
service_message: @current_message,
|
46
|
-
current_flow: current_flow
|
47
|
-
)
|
50
|
+
flow_controller.new(service_message: @current_message, pos: @pos)
|
48
51
|
end
|
49
52
|
end
|
50
53
|
|
51
54
|
def current_session
|
52
|
-
@current_session ||= Stealth::Session.new(
|
55
|
+
@current_session ||= Stealth::Session.new(id: current_session_id)
|
53
56
|
end
|
54
57
|
|
55
58
|
def previous_session
|
56
|
-
@previous_session ||= Stealth::Session.new(
|
59
|
+
@previous_session ||= Stealth::Session.new(
|
60
|
+
id: current_session_id,
|
61
|
+
type: :previous
|
62
|
+
)
|
57
63
|
end
|
58
64
|
|
59
65
|
def action(action: nil)
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
message: "From #{current_session.session} to #{current_session.flow.current_state.redirects_to.session}"
|
66
|
+
begin
|
67
|
+
# Grab a mutual exclusion lock on the session
|
68
|
+
lock_session!(
|
69
|
+
session_slug: Session.slugify(
|
70
|
+
flow: current_session.flow_string,
|
71
|
+
state: current_session.state_string
|
72
|
+
)
|
68
73
|
)
|
69
|
-
step_to(session: current_session.flow.current_state.redirects_to)
|
70
|
-
return
|
71
|
-
end
|
72
74
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
Stealth::Logger.l(
|
79
|
-
|
75
|
+
@action_name = action
|
76
|
+
@action_name ||= current_session.state_string
|
77
|
+
|
78
|
+
# Check if the user needs to be redirected
|
79
|
+
if current_session.flow.current_state.redirects_to.present?
|
80
|
+
Stealth::Logger.l(
|
81
|
+
topic: "redirect",
|
82
|
+
message: "From #{current_session.session} to #{current_session.flow.current_state.redirects_to.session}"
|
83
|
+
)
|
84
|
+
step_to(session: current_session.flow.current_state.redirects_to, pos: @pos)
|
85
|
+
return
|
86
|
+
end
|
87
|
+
|
88
|
+
run_callbacks :action do
|
89
|
+
begin
|
90
|
+
flow_controller.send(@action_name)
|
91
|
+
unless flow_controller.progressed?
|
92
|
+
run_catch_all(reason: 'Did not send replies, update session, or step')
|
93
|
+
end
|
94
|
+
rescue StandardError => e
|
95
|
+
if e.class == Stealth::Errors::UnrecognizedMessage
|
96
|
+
run_unrecognized_message(err: e)
|
97
|
+
else
|
98
|
+
run_catch_all(err: e)
|
99
|
+
end
|
100
|
+
end
|
80
101
|
end
|
102
|
+
ensure
|
103
|
+
# Release mutual exclusion lock on the session
|
104
|
+
release_lock!
|
81
105
|
end
|
82
106
|
end
|
83
107
|
|
84
|
-
def step_to_in(delay, session: nil, flow: nil, state: nil)
|
85
|
-
|
108
|
+
def step_to_in(delay, session: nil, flow: nil, state: nil, slug: nil)
|
109
|
+
if interrupt_detected?
|
110
|
+
run_interrupt_action
|
111
|
+
return :interrupted
|
112
|
+
end
|
113
|
+
|
114
|
+
flow, state = get_flow_and_state(
|
115
|
+
session: session,
|
116
|
+
flow: flow,
|
117
|
+
state: state,
|
118
|
+
slug: slug
|
119
|
+
)
|
86
120
|
|
87
121
|
unless delay.is_a?(ActiveSupport::Duration)
|
88
122
|
raise ArgumentError, "Please specify your step_to_in `delay` parameter using ActiveSupport::Duration, e.g. `1.day` or `5.hours`"
|
89
123
|
end
|
90
124
|
|
91
|
-
Stealth::ScheduledReplyJob.perform_in(delay, current_service, current_session_id, flow, state)
|
125
|
+
Stealth::ScheduledReplyJob.perform_in(delay, current_service, current_session_id, flow, state, current_message.target_id)
|
92
126
|
Stealth::Logger.l(topic: "session", message: "User #{current_session_id}: scheduled session step to #{flow}->#{state} in #{delay} seconds")
|
93
127
|
end
|
94
128
|
|
95
|
-
def step_to_at(timestamp, session: nil, flow: nil, state: nil)
|
96
|
-
|
129
|
+
def step_to_at(timestamp, session: nil, flow: nil, state: nil, slug: nil)
|
130
|
+
if interrupt_detected?
|
131
|
+
run_interrupt_action
|
132
|
+
return :interrupted
|
133
|
+
end
|
134
|
+
|
135
|
+
flow, state = get_flow_and_state(
|
136
|
+
session: session,
|
137
|
+
flow: flow,
|
138
|
+
state: state,
|
139
|
+
slug: slug
|
140
|
+
)
|
97
141
|
|
98
142
|
unless timestamp.is_a?(DateTime)
|
99
143
|
raise ArgumentError, "Please specify your step_to_at `timestamp` parameter as a DateTime"
|
100
144
|
end
|
101
145
|
|
102
|
-
Stealth::ScheduledReplyJob.perform_at(timestamp, current_service, current_session_id, flow, state)
|
146
|
+
Stealth::ScheduledReplyJob.perform_at(timestamp, current_service, current_session_id, flow, state, current_message.target_id)
|
103
147
|
Stealth::Logger.l(topic: "session", message: "User #{current_session_id}: scheduled session step to #{flow}->#{state} at #{timestamp.iso8601}")
|
104
148
|
end
|
105
149
|
|
106
|
-
def step_to(session: nil, flow: nil, state: nil)
|
107
|
-
|
108
|
-
|
150
|
+
def step_to(session: nil, flow: nil, state: nil, slug: nil, pos: nil)
|
151
|
+
if interrupt_detected?
|
152
|
+
run_interrupt_action
|
153
|
+
return :interrupted
|
154
|
+
end
|
155
|
+
|
156
|
+
flow, state = get_flow_and_state(
|
157
|
+
session: session,
|
158
|
+
flow: flow,
|
159
|
+
state: state,
|
160
|
+
slug: slug
|
161
|
+
)
|
162
|
+
|
163
|
+
step(flow: flow, state: state, pos: pos)
|
109
164
|
end
|
110
165
|
|
111
|
-
def update_session_to(session: nil, flow: nil, state: nil)
|
112
|
-
|
166
|
+
def update_session_to(session: nil, flow: nil, state: nil, slug: nil)
|
167
|
+
if interrupt_detected?
|
168
|
+
run_interrupt_action
|
169
|
+
return :interrupted
|
170
|
+
end
|
171
|
+
|
172
|
+
flow, state = get_flow_and_state(
|
173
|
+
session: session,
|
174
|
+
flow: flow,
|
175
|
+
state: state,
|
176
|
+
slug: slug
|
177
|
+
)
|
178
|
+
|
113
179
|
update_session(flow: flow, state: state)
|
114
180
|
end
|
115
181
|
|
182
|
+
def set_back_to(session: nil, flow: nil, state: nil, slug: nil)
|
183
|
+
if interrupt_detected?
|
184
|
+
run_interrupt_action
|
185
|
+
return :interrupted
|
186
|
+
end
|
187
|
+
|
188
|
+
flow, state = get_flow_and_state(
|
189
|
+
session: session,
|
190
|
+
flow: flow,
|
191
|
+
state: state,
|
192
|
+
slug: slug
|
193
|
+
)
|
194
|
+
|
195
|
+
store_back_to_session(flow: flow, state: state)
|
196
|
+
end
|
197
|
+
|
198
|
+
def step_back
|
199
|
+
back_to_session = Stealth::Session.new(
|
200
|
+
id: current_session_id,
|
201
|
+
type: :back_to
|
202
|
+
)
|
203
|
+
|
204
|
+
if back_to_session.blank?
|
205
|
+
raise(
|
206
|
+
Stealth::Errors::InvalidStateTransition,
|
207
|
+
'back_to_session not found; make sure set_back_to was called first'
|
208
|
+
)
|
209
|
+
end
|
210
|
+
|
211
|
+
step_to(session: back_to_session)
|
212
|
+
end
|
213
|
+
|
214
|
+
def do_nothing
|
215
|
+
@progressed = :do_nothing
|
216
|
+
end
|
217
|
+
|
116
218
|
private
|
117
219
|
|
118
220
|
def update_session(flow:, state:)
|
119
|
-
@current_session = Stealth::Session.new(user_id: current_session_id)
|
120
221
|
@progressed = :updated_session
|
121
|
-
@current_session.
|
222
|
+
@current_session = Session.new(id: current_session_id)
|
223
|
+
|
224
|
+
unless current_session.flow_string == flow.to_s && current_session.state_string == state.to_s
|
225
|
+
@current_session.set_session(new_flow: flow, new_state: state)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def store_back_to_session(flow:, state:)
|
230
|
+
back_to_session = Session.new(
|
231
|
+
id: current_session_id,
|
232
|
+
type: :back_to
|
233
|
+
)
|
234
|
+
back_to_session.set_session(new_flow: flow, new_state: state)
|
122
235
|
end
|
123
236
|
|
124
|
-
def step(flow:, state:)
|
237
|
+
def step(flow:, state:, pos: nil)
|
125
238
|
update_session(flow: flow, state: state)
|
126
239
|
@progressed = :stepped
|
127
240
|
@flow_controller = nil
|
128
241
|
@current_flow = current_session.flow
|
242
|
+
@pos = pos
|
129
243
|
|
130
|
-
action(action: state)
|
244
|
+
flow_controller.action(action: state)
|
131
245
|
end
|
132
246
|
|
133
|
-
def get_flow_and_state(session: nil, flow: nil, state: nil)
|
134
|
-
if session.nil? && flow.nil? && state.nil?
|
135
|
-
raise(ArgumentError, "A session, flow, or
|
247
|
+
def get_flow_and_state(session: nil, flow: nil, state: nil, slug: nil)
|
248
|
+
if session.nil? && flow.nil? && state.nil? && slug.nil?
|
249
|
+
raise(ArgumentError, "A session, flow, state, or slug must be specified")
|
136
250
|
end
|
137
251
|
|
138
252
|
if session.present?
|
139
253
|
return session.flow_string, session.state_string
|
140
254
|
end
|
141
255
|
|
256
|
+
if slug.present?
|
257
|
+
flow_state = Session.flow_and_state_from_session_slug(slug: slug)
|
258
|
+
return flow_state[:flow], flow_state[:state]
|
259
|
+
end
|
260
|
+
|
142
261
|
if flow.present?
|
143
262
|
if state.blank?
|
144
263
|
state = FlowMap.flow_spec[flow.to_sym].states.keys.first.to_s
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Stealth
|
5
|
+
class Controller
|
6
|
+
module DevJumps
|
7
|
+
|
8
|
+
DEV_JUMP_REGEX = /\A\/(.*)\/(.*)\z|\A\/\/(.*)\z|\A\/(.*)\z/
|
9
|
+
|
10
|
+
extend ActiveSupport::Concern
|
11
|
+
|
12
|
+
included do
|
13
|
+
private
|
14
|
+
|
15
|
+
def dev_jump_detected?
|
16
|
+
if Stealth.env.development?
|
17
|
+
if current_message.message&.match(DEV_JUMP_REGEX)
|
18
|
+
handle_dev_jump
|
19
|
+
return true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
false
|
24
|
+
end
|
25
|
+
|
26
|
+
def handle_dev_jump
|
27
|
+
_, flow, state = current_message.message.split('/')
|
28
|
+
flow = nil if flow.blank?
|
29
|
+
|
30
|
+
Stealth::Logger.l(
|
31
|
+
topic: 'dev_jump',
|
32
|
+
message: "Dev Jump detected: Flow: #{flow.inspect} State: #{state.inspect}"
|
33
|
+
)
|
34
|
+
|
35
|
+
step_to flow: flow, state: state
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -12,17 +12,15 @@ module Stealth
|
|
12
12
|
LONG_DELAY = 7.0
|
13
13
|
|
14
14
|
included do
|
15
|
-
def dynamic_delay(
|
16
|
-
|
17
|
-
calculate_delay(previous_reply: {})
|
18
|
-
else
|
19
|
-
calculate_delay(previous_reply: service_replies[position - 1])
|
20
|
-
end
|
15
|
+
def dynamic_delay(previous_reply:)
|
16
|
+
calculate_delay(previous_reply: previous_reply)
|
21
17
|
end
|
22
18
|
|
23
19
|
private
|
24
20
|
|
25
21
|
def calculate_delay(previous_reply:)
|
22
|
+
return SHORT_DELAY if previous_reply.blank?
|
23
|
+
|
26
24
|
case previous_reply['reply_type']
|
27
25
|
when 'text'
|
28
26
|
calculate_delay_from_text(previous_reply['text'])
|