bot_framework 0.1.0beta → 0.1.0beta2
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/.travis.yml +4 -1
- data/README.md +14 -1
- data/appveyor.yml +20 -0
- data/bot_framework.gemspec +6 -0
- data/examples/dialog/basic_first_run.rb +12 -0
- data/examples/ruby_conf/Gemfile +8 -0
- data/examples/ruby_conf/Gemfile.lock +85 -0
- data/examples/ruby_conf/bot.rb +88 -0
- data/examples/ruby_conf/config.ru +6 -0
- data/examples/ruby_conf/speaker_data.yaml +41 -0
- data/examples/simple_regex/Gemfile +6 -0
- data/examples/simple_regex/Gemfile.lock +63 -0
- data/examples/simple_regex/bot.rb +35 -0
- data/examples/simple_regex/config.ru +6 -0
- data/images/emulator1.png +0 -0
- data/images/emulator2.png +0 -0
- data/lib/bot_framework.rb +12 -0
- data/lib/bot_framework/api_base.rb +6 -4
- data/lib/bot_framework/bot.rb +47 -2
- data/lib/bot_framework/connector.rb +13 -5
- data/lib/bot_framework/console_connector.rb +17 -0
- data/lib/bot_framework/dialogs/action_set.rb +66 -0
- data/lib/bot_framework/dialogs/dialog.rb +25 -0
- data/lib/bot_framework/dialogs/entity_recognizer.rb +123 -0
- data/lib/bot_framework/dialogs/luis_recognizer.rb +72 -0
- data/lib/bot_framework/dialogs/reg_exp_recognizer.rb +41 -0
- data/lib/bot_framework/dialogs/simple_dialog.rb +29 -0
- data/lib/bot_framework/events/event_emitter.rb +6 -0
- data/lib/bot_framework/message.rb +80 -0
- data/lib/bot_framework/models/object.rb +0 -1
- data/lib/bot_framework/prompt.rb +62 -0
- data/lib/bot_framework/server.rb +1 -1
- data/lib/bot_framework/session.rb +407 -0
- data/lib/bot_framework/simple_prompt_recognizer.rb +4 -0
- data/lib/bot_framework/token_validator.rb +6 -4
- data/lib/bot_framework/universal_bot.rb +7 -0
- data/lib/bot_framework/version.rb +1 -1
- metadata +100 -4
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative 'action_set'
|
2
|
+
module BotFramework
|
3
|
+
module Dialogs
|
4
|
+
class RegExpRecognizer
|
5
|
+
attr_accessor :intent, :expressions
|
6
|
+
def initialize(intent,expressions)
|
7
|
+
@intent = intent
|
8
|
+
if expressions.is_a? Regexp
|
9
|
+
@expressions = {'*': expressions}
|
10
|
+
else
|
11
|
+
@expressions = expressions || {}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def recognize(context)
|
16
|
+
raise ArgumentError, "context must be a hash" unless context.is_a? Hash
|
17
|
+
result = {score: 0.0, intent: nil}
|
18
|
+
if context.fetch(:message, {}).fetch(:text, nil)
|
19
|
+
utterance = context[:message][:text]
|
20
|
+
locale = context[:message][:locale] || :*
|
21
|
+
exp = @expressions[locale] ? @expressions[locale] : @expressions[:*]
|
22
|
+
if exp
|
23
|
+
matches = exp.match(utterance)
|
24
|
+
if matches
|
25
|
+
matched = matches.to_s
|
26
|
+
result[:score] = matched.length / utterance.length
|
27
|
+
result[:intent] = intent
|
28
|
+
result[:expression] = exp
|
29
|
+
result[:matched] = matches
|
30
|
+
end
|
31
|
+
yield nil, result
|
32
|
+
else
|
33
|
+
yield(ExpressionNotFoundForLocale, nil)
|
34
|
+
end
|
35
|
+
else
|
36
|
+
yield(nil, result)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative '../session'
|
2
|
+
require_relative 'action_set'
|
3
|
+
module BotFramework
|
4
|
+
# Abstract class for dialog
|
5
|
+
module Dialogs
|
6
|
+
class SimpleDialog < Dialog
|
7
|
+
def initialize
|
8
|
+
raise 'No block given' unless block_given?
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def begin(session, _opts = {})
|
13
|
+
reply_recieved(session)
|
14
|
+
end
|
15
|
+
|
16
|
+
def reply_recieved(_session, _recognize_result = {})
|
17
|
+
raise NotImplementedError
|
18
|
+
end
|
19
|
+
|
20
|
+
def dialog_resumed(session, result)
|
21
|
+
session.error(result[:error]) if result[:error]
|
22
|
+
end
|
23
|
+
|
24
|
+
def recognize(_context)
|
25
|
+
yield nil, { score: 0.1 }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module BotFramework
|
2
|
+
class Message
|
3
|
+
TEXT_FORMAT = {
|
4
|
+
plain: 'plain',
|
5
|
+
markdown: 'markdown',
|
6
|
+
xml: 'xml'
|
7
|
+
}.freeze
|
8
|
+
ATTACHMENT_LAYOUT = {
|
9
|
+
list: 'list',
|
10
|
+
carousel: 'carousel'
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
def initialize(_session = nil)
|
14
|
+
@data = {}
|
15
|
+
@data[:type] = 'consts.MessageType' # FIXME
|
16
|
+
@data[:agent] = 'consts.agent'
|
17
|
+
if @session
|
18
|
+
m = @session.message
|
19
|
+
@data[:source] = m[:source] if m[:source]
|
20
|
+
@data[:text_locale] = m[:text_locale] if m[:text_locale]
|
21
|
+
@data[:address] = m[:address] if m[:address]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def text_locale(locale)
|
26
|
+
@data[:text_locale] = locale
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def text_format(style)
|
31
|
+
@data[:text_format] = style
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def text(text, *_args)
|
36
|
+
@data[:text] = text.present? ? format_text(text) : ''
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def ntext(msg, _msg_plural, count)
|
41
|
+
fmt = count == 1 ? self.class.random_prompt(msg) : self.class.random_prmpt(message_plural)
|
42
|
+
fmt = @session.get_text(fmt) if @session
|
43
|
+
@data[:text] = fmt, count # FIXME
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
def compose(prompts, *args)
|
48
|
+
if prompts
|
49
|
+
@data[:text] = Message.compose_prompt(@session, prompts, *args)
|
50
|
+
self
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def summary; end
|
55
|
+
|
56
|
+
def attachment_layout; end
|
57
|
+
|
58
|
+
def attachments; end
|
59
|
+
|
60
|
+
def add_attachment; end
|
61
|
+
|
62
|
+
def entities; end
|
63
|
+
|
64
|
+
def add_entity; end
|
65
|
+
|
66
|
+
def address; end
|
67
|
+
|
68
|
+
def timestamp; end
|
69
|
+
|
70
|
+
def source_event; end
|
71
|
+
|
72
|
+
def to_message; end
|
73
|
+
|
74
|
+
class << self
|
75
|
+
def random_prompt; end
|
76
|
+
|
77
|
+
def compose_prompt; end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module BotFramework
|
2
|
+
class Prompt < Dialog
|
3
|
+
@@options = {
|
4
|
+
recognizer: BotFramework::SimplePromptRecognizer.new,
|
5
|
+
prompt_after_action: true
|
6
|
+
}
|
7
|
+
|
8
|
+
@@default_retry_prompt = {
|
9
|
+
text: 'default_text',
|
10
|
+
number: 'default_number',
|
11
|
+
confirm: 'daefault_confirm',
|
12
|
+
choice: 'default_choice',
|
13
|
+
time: 'default_time',
|
14
|
+
attachment: 'default_file'
|
15
|
+
}
|
16
|
+
|
17
|
+
def self.configure(_options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def begin(session, options = {})
|
21
|
+
options[:prompt_after_action] = options[:prompt_after_action] || options[:prompt_after_action]
|
22
|
+
options[:retry_count] = 0
|
23
|
+
options.each do |option|
|
24
|
+
# Store in dialog data
|
25
|
+
end
|
26
|
+
send_prompt(session, options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def reply_received(session, args = {}); end
|
30
|
+
|
31
|
+
def dialog_resumed; end
|
32
|
+
|
33
|
+
def recognize; end
|
34
|
+
|
35
|
+
def send_prompt(session, options); end
|
36
|
+
|
37
|
+
def create_prompt; end
|
38
|
+
|
39
|
+
def self.text
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.number
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.confirm
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.choice
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.time
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.attachment
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.disambiguate
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
end
|
62
|
+
end
|
data/lib/bot_framework/server.rb
CHANGED
@@ -0,0 +1,407 @@
|
|
1
|
+
module BotFramework
|
2
|
+
class Session # < Events::EventEmitter
|
3
|
+
attr_accessor :library, :message, :user_data, :conversation_data, :private_conversation_data,
|
4
|
+
:session_state, :dialog_state, :localizer
|
5
|
+
def initialize(options)
|
6
|
+
super
|
7
|
+
@library = options[:library]
|
8
|
+
@localizer = options[:localizer]
|
9
|
+
@msg_sent = false
|
10
|
+
@is_reset = false
|
11
|
+
@last_send_time = Time.now # TODO: Move to proc?
|
12
|
+
@batch = []
|
13
|
+
@batch_timer = Timers::Group.new
|
14
|
+
@batch_started = false
|
15
|
+
@sending_batch = false
|
16
|
+
@in_middleware = false
|
17
|
+
@_locale = nil
|
18
|
+
|
19
|
+
@options = options || {
|
20
|
+
on_save: nil,
|
21
|
+
on_send: nil,
|
22
|
+
library: nil,
|
23
|
+
localizer: nil,
|
24
|
+
middleware: nil,
|
25
|
+
dialog_id: nil,
|
26
|
+
dialog_args: nil,
|
27
|
+
auto_batch_delay: nil,
|
28
|
+
dialog_error_message: nil,
|
29
|
+
actions: nil
|
30
|
+
}
|
31
|
+
@auto_batch_delay = 250 unless options[:auto_batch_delay].is_a? Integer
|
32
|
+
@timers = Timers::Group.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_recognize_context
|
36
|
+
{
|
37
|
+
message: message,
|
38
|
+
user_data: user_data,
|
39
|
+
conversation_data: conversation_data,
|
40
|
+
private_conversation_data: private_conversation_data,
|
41
|
+
localizer: localizer,
|
42
|
+
dialog_stack: dialog_stack,
|
43
|
+
preferred_locale: preferred_locale,
|
44
|
+
get_text: get_text,
|
45
|
+
nget_text: nget_text,
|
46
|
+
locale: preferred_locale
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def dispatch(session_state, message)
|
51
|
+
index = 0
|
52
|
+
session = self
|
53
|
+
now = Time.now
|
54
|
+
middleware = @options[:middleware] || []
|
55
|
+
|
56
|
+
_next = lambda do
|
57
|
+
handler = middleware[index] if index < middleware.length
|
58
|
+
if handler
|
59
|
+
index += 1
|
60
|
+
handler(session, _next)
|
61
|
+
else
|
62
|
+
@in_middleware = false
|
63
|
+
@session_state[:last_acess] = now
|
64
|
+
done
|
65
|
+
end
|
66
|
+
end
|
67
|
+
session_state ||= { call_stack: [], last_acess: Time.now, version: 0.0 }
|
68
|
+
# Making sure that dialog is properly initialized
|
69
|
+
cur = cur_dialog
|
70
|
+
self.dialog_data = cur.state if cur
|
71
|
+
# Dispatch message
|
72
|
+
message ||= { text: '' }
|
73
|
+
message[:type] ||= 'message'
|
74
|
+
# Ensure that localized prompts are loaded
|
75
|
+
# TODO
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
def error(_error)
|
80
|
+
logger.info 'Session error'
|
81
|
+
if options[:dialog_error_message]
|
82
|
+
end_conversation(options[:dialog_error_message])
|
83
|
+
else
|
84
|
+
# TODO: Add localisation
|
85
|
+
locale = preferred_locale
|
86
|
+
end_conversation 'Error in conversation'
|
87
|
+
end
|
88
|
+
|
89
|
+
# TODO: Log error
|
90
|
+
end
|
91
|
+
|
92
|
+
def preferred_locale(locale = nil)
|
93
|
+
if locale
|
94
|
+
@_locale = locale
|
95
|
+
@user_data['BotBuilder.Data.PreferredLocale'] = locale if @user_data
|
96
|
+
@localizer.load if @localizer # TODO
|
97
|
+
elsif !@_locale
|
98
|
+
if @user_data && @user_data['BotBuilder.Data.PreferredLocale']
|
99
|
+
@_locale = @user_data['BotBuilder.Data.PreferredLocale']
|
100
|
+
elsif @message && @message[:text_locale]
|
101
|
+
@_locale = @message[:text_locale]
|
102
|
+
elsif @localizer
|
103
|
+
@_locale = @localizer[:default_locale]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
@_locale
|
107
|
+
end
|
108
|
+
|
109
|
+
# Gets and formats localized text string
|
110
|
+
def gettext(message_id, options = {})
|
111
|
+
# TODO
|
112
|
+
# stub
|
113
|
+
end
|
114
|
+
|
115
|
+
# Gets and formats the singular/plural form of a localized text string.
|
116
|
+
def ngettext(message_id, message_id_plural, count); end
|
117
|
+
|
118
|
+
# Manually save current session state
|
119
|
+
def save
|
120
|
+
logger.info 'Session.save'
|
121
|
+
start_batch
|
122
|
+
self
|
123
|
+
end
|
124
|
+
|
125
|
+
def send(message, args = [])
|
126
|
+
args.unshift(@cur_library_name, message)
|
127
|
+
send_localized(args, message)
|
128
|
+
end
|
129
|
+
|
130
|
+
def send_localized(_localization_namspace, message, _args = [])
|
131
|
+
# TODO: Incomplete
|
132
|
+
@msg_sent = true
|
133
|
+
m = { text: message }
|
134
|
+
prepare_message(m)
|
135
|
+
@batch << m
|
136
|
+
self
|
137
|
+
end
|
138
|
+
|
139
|
+
# Sends a typing indicator to the user
|
140
|
+
def send_typing
|
141
|
+
@msg_sent = true
|
142
|
+
m = { type: 'typing' }
|
143
|
+
m = prepare_message(m)
|
144
|
+
@batch.push(m)
|
145
|
+
logger.info 'Send Typing'
|
146
|
+
send_batch
|
147
|
+
end
|
148
|
+
|
149
|
+
def send_batch
|
150
|
+
logger.info "Sending batch with elements #{@batch.count}"
|
151
|
+
return if sending_batch?
|
152
|
+
# TODO: timer
|
153
|
+
@batch_timer = nil
|
154
|
+
batch = @batch
|
155
|
+
@batch_started = false
|
156
|
+
@sending_batch = true
|
157
|
+
cur = cur_dialog
|
158
|
+
cur.state = @dialog_data
|
159
|
+
options[:on_save] = proc do |err|
|
160
|
+
if err
|
161
|
+
@sending_batch = false
|
162
|
+
case (err.code || '')
|
163
|
+
when 'EBADMSG'
|
164
|
+
when 'EMSGSIZE'
|
165
|
+
# Something went wrong , let's reset everything
|
166
|
+
@user_data = {}
|
167
|
+
@batch = []
|
168
|
+
end_conversation(@options[:dialog_error_message] || 'Something went wrong and we need to startover')
|
169
|
+
end
|
170
|
+
yield(err) if block_given?
|
171
|
+
else
|
172
|
+
if batch.length
|
173
|
+
options[:on_send].call(batch) do |err|
|
174
|
+
@sending_batch = false
|
175
|
+
start_batch if @batch_started # What is this :o
|
176
|
+
yield(err) if block_given?
|
177
|
+
end
|
178
|
+
else
|
179
|
+
@sending_batch = false
|
180
|
+
start_batch if @batch_started
|
181
|
+
yield(err) if block_given?
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# Begin a new dialog
|
188
|
+
def begin_dialog(id, args = nil)
|
189
|
+
logger.info "Beginning new dialog #{id}"
|
190
|
+
id = resolve_dialog_id(id)
|
191
|
+
dialog = find_dialog(id)
|
192
|
+
raise "Dialog #{id} Not found" unless dialog
|
193
|
+
push_dialog(id: id, state: {})
|
194
|
+
start_batch
|
195
|
+
dialog.begin(self, args)
|
196
|
+
self
|
197
|
+
end
|
198
|
+
|
199
|
+
def replace_dialog(id, args = nil)
|
200
|
+
logger.info "Session replace dialog #{id}"
|
201
|
+
id = resolve_dialog_id(id)
|
202
|
+
dialog = find_dialog(id)
|
203
|
+
raise "Dialog #{id} Not found" unless dialog
|
204
|
+
|
205
|
+
# Update the stack and start dialog
|
206
|
+
pop_dialog
|
207
|
+
push_dialog(id: id, state: {})
|
208
|
+
start_batch
|
209
|
+
dialog.begin(self, args)
|
210
|
+
self
|
211
|
+
end
|
212
|
+
|
213
|
+
# End conversation with the user
|
214
|
+
def end_conversation(message = nil, _args = {})
|
215
|
+
if message
|
216
|
+
# TODO: sent message
|
217
|
+
end
|
218
|
+
# Clear private conversation data
|
219
|
+
@private_conversation_data = {}
|
220
|
+
|
221
|
+
# Clear stack and save
|
222
|
+
logger.info 'End conversation'
|
223
|
+
ss = @session_state
|
224
|
+
ss.call_stack = []
|
225
|
+
send_batch
|
226
|
+
self
|
227
|
+
end
|
228
|
+
|
229
|
+
def end_dialog(message = nil, args = {})
|
230
|
+
if message
|
231
|
+
# TODO: end_dialog_with_result
|
232
|
+
end
|
233
|
+
cur = cur_dialog
|
234
|
+
if cur
|
235
|
+
if message
|
236
|
+
m = if (message.is_a? String) || (message.is_a? Array)
|
237
|
+
create_message(cur_library_name, message, args)
|
238
|
+
else
|
239
|
+
message
|
240
|
+
end
|
241
|
+
@msg_sent = true
|
242
|
+
prepare_message(m)
|
243
|
+
@batch.push(m)
|
244
|
+
end
|
245
|
+
|
246
|
+
# Pop the dialog of the stack and resume the parent
|
247
|
+
logger.info 'Session.end_dialog'
|
248
|
+
child_id = cur.id
|
249
|
+
cur = pop_dialog
|
250
|
+
start_batch
|
251
|
+
if cur
|
252
|
+
dialog = find_dialog(cur.id)
|
253
|
+
if dialog
|
254
|
+
dialog.dialog_resumed(self, resumed: :completed, response: true, child_id: child_id)
|
255
|
+
else
|
256
|
+
# Bad dialog !! , we should never reach here
|
257
|
+
raise "Can't resume , missing parent"
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
# Ends current dialog and returns a value to the caller
|
264
|
+
def end_dialog_with_result(result)
|
265
|
+
# Validate call stack
|
266
|
+
cur = cur_dialog
|
267
|
+
if cur
|
268
|
+
# Validate the result
|
269
|
+
result ||= {}
|
270
|
+
result[:resumed] ||= :completed
|
271
|
+
result.child_id = cur.id
|
272
|
+
logger.info 'Session.end_dialog_with_result'
|
273
|
+
|
274
|
+
# Pop dialog of the stack and resume parent dialog
|
275
|
+
cur = pop_dialog
|
276
|
+
start_batch
|
277
|
+
if cur
|
278
|
+
dialog = find_dialog(cur.id)
|
279
|
+
if dialog
|
280
|
+
dialog.dialog_resumed(self, result)
|
281
|
+
else
|
282
|
+
# Bad dialog state
|
283
|
+
raise "Can't resume , missing parent dialog"
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
self
|
288
|
+
end
|
289
|
+
|
290
|
+
def cancel_dialog; end
|
291
|
+
|
292
|
+
def reset; end
|
293
|
+
|
294
|
+
############### Dialog Stack Management ############################33
|
295
|
+
|
296
|
+
# Gets and Sets current dialog stack
|
297
|
+
def dialog_stack(new_stack = nil)
|
298
|
+
if new_stack
|
299
|
+
# Update stack and dialog data
|
300
|
+
|
301
|
+
stack = @session_state[:call_stack] = new_stack || []
|
302
|
+
@dialog_data = stack.empty? nil || stack.last
|
303
|
+
else
|
304
|
+
# Copy over dialog data to slack
|
305
|
+
stack = @session_state[:call_stack] || []
|
306
|
+
stack.last.state = @dialog_data || {}
|
307
|
+
end
|
308
|
+
stack
|
309
|
+
end
|
310
|
+
|
311
|
+
# Clears the current Dialog stack
|
312
|
+
def clear_dialog_stack
|
313
|
+
@session_state[:call_stack] = []
|
314
|
+
@dialog_data = nil
|
315
|
+
end
|
316
|
+
|
317
|
+
# Enumerates all a stacks dialog entries in either a forward or reverse direction.
|
318
|
+
def self.forEachDialogStackEntry(stack)
|
319
|
+
stack.each { |item| yield(item) }
|
320
|
+
end
|
321
|
+
|
322
|
+
# Searches a dialog stack for a specific dialog, in either a forward or reverse direction, returning its index.
|
323
|
+
def self.findEachDialogStackEntry(stack, dialog_id)
|
324
|
+
stack.each_with_index do |item, index|
|
325
|
+
return index if item[:id] = dialog_id
|
326
|
+
end
|
327
|
+
-1
|
328
|
+
end
|
329
|
+
|
330
|
+
# Returns a active stack entry or nil
|
331
|
+
def self.active_dialog_stack_entry(stack)
|
332
|
+
stack.last || nil
|
333
|
+
end
|
334
|
+
|
335
|
+
# Pushes a new dialog into stack and return it as active dialog
|
336
|
+
def self.push_dialog_stack_entry(statck, entry)
|
337
|
+
entry[:state] ||= {}
|
338
|
+
statck ||= []
|
339
|
+
stack.push(entry)
|
340
|
+
entry
|
341
|
+
end
|
342
|
+
|
343
|
+
# Pop active dialog out of the stack
|
344
|
+
def self.pop_dialog_stack_entry(stack)
|
345
|
+
stack.pop if stack
|
346
|
+
Session.active_dialog_stack_entry(stack)
|
347
|
+
end
|
348
|
+
|
349
|
+
# Deletes all dialog stack entries starting with the specified index and returns the new active dialog.
|
350
|
+
def self.prune_dialog_stack(_stack, _start)
|
351
|
+
end
|
352
|
+
|
353
|
+
# Ensures that all of the entries on a dialog stack reference valid dialogs within a library hierarchy.
|
354
|
+
def self.validate_dialog_stack(_stack, _root)
|
355
|
+
end
|
356
|
+
|
357
|
+
## Message routing
|
358
|
+
#########################
|
359
|
+
|
360
|
+
# Dispatches handling of the current message to the active dialog stack entry.
|
361
|
+
def route_to_active_dialog; end
|
362
|
+
|
363
|
+
private
|
364
|
+
|
365
|
+
def start_batch
|
366
|
+
@batch_started = true
|
367
|
+
unless @sending_batch
|
368
|
+
@batch_timer.cancel if @batch_timer
|
369
|
+
# TODO: send_batch after config[:auto_batch_delay] seconds
|
370
|
+
@batch_timer = @timers.after(config[:auto_batch_delay]) do
|
371
|
+
send_batch
|
372
|
+
end
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
def create_message; end
|
377
|
+
|
378
|
+
def prepare_message(msg)
|
379
|
+
msg[:type] ||= 'message'
|
380
|
+
msg[:address] ||= message[:address]
|
381
|
+
msg[:text_locale] ||= message[:text_locale]
|
382
|
+
msg
|
383
|
+
end
|
384
|
+
|
385
|
+
def vget_text; end
|
386
|
+
|
387
|
+
def validate_call_stack; end
|
388
|
+
|
389
|
+
def resolve_dialog_id; end
|
390
|
+
|
391
|
+
def cur_library_name; end
|
392
|
+
|
393
|
+
def find_dialog; end
|
394
|
+
|
395
|
+
def push_dialog; end
|
396
|
+
|
397
|
+
def pop_dialog; end
|
398
|
+
|
399
|
+
def delete_dialogs; end
|
400
|
+
|
401
|
+
def cur_dialog
|
402
|
+
ss = @session_sate
|
403
|
+
cur = ss.call_stack.last unless ss.call_stack.empty?
|
404
|
+
cur
|
405
|
+
end
|
406
|
+
end
|
407
|
+
end
|