@@ -9,6 +9,7 @@ var sprintf = require('sprintf-js');
99var events = require ( 'events' ) ;
1010var msg = require ( './Message' ) ;
1111var logger = require ( './logger' ) ;
12+ var async = require ( 'async' ) ;
1213var Session = ( function ( _super ) {
1314 __extends ( Session , _super ) ;
1415 function Session ( options ) {
@@ -109,6 +110,15 @@ var Session = (function (_super) {
109110 this . startBatch ( ) ;
110111 return this ;
111112 } ;
113+ Session . prototype . sendTyping = function ( ) {
114+ this . msgSent = true ;
115+ var m = { type : 'typing' } ;
116+ this . prepareMessage ( m ) ;
117+ this . batch . push ( m ) ;
118+ logger . info ( this , 'session.sendTyping()' ) ;
119+ this . startBatch ( ) ;
120+ return this ;
121+ } ;
112122 Session . prototype . messageSent = function ( ) {
113123 return this . msgSent ;
114124 } ;
@@ -174,61 +184,83 @@ var Session = (function (_super) {
174184 return this . endDialogWithResult ( message ) ;
175185 }
176186 var cur = this . curDialog ( ) ;
177- if ( ! cur ) {
178- console . error ( 'ERROR: Too many calls to session.endDialog().' ) ;
179- return this ;
180- }
181- var m ;
182- if ( message ) {
183- if ( typeof message == 'string' || Array . isArray ( message ) ) {
184- m = this . createMessage ( message , args ) ;
185- }
186- else if ( message . toMessage ) {
187- m = message . toMessage ( ) ;
188- }
189- else {
190- m = message ;
191- }
192- this . msgSent = true ;
193- this . prepareMessage ( m ) ;
194- this . batch . push ( m ) ;
195- }
196- logger . info ( this , 'session.endDialog()' ) ;
197- var childId = cur . id ;
198- cur = this . popDialog ( ) ;
199- this . startBatch ( ) ;
200187 if ( cur ) {
201- var dialog = this . findDialog ( cur . id ) ;
202- if ( dialog ) {
203- dialog . dialogResumed ( this , { resumed : dlg . ResumeReason . completed , response : true , childId : childId } ) ;
188+ var m ;
189+ if ( message ) {
190+ if ( typeof message == 'string' || Array . isArray ( message ) ) {
191+ m = this . createMessage ( message , args ) ;
192+ }
193+ else if ( message . toMessage ) {
194+ m = message . toMessage ( ) ;
195+ }
196+ else {
197+ m = message ;
198+ }
199+ this . msgSent = true ;
200+ this . prepareMessage ( m ) ;
201+ this . batch . push ( m ) ;
204202 }
205- else {
206- this . error ( new Error ( "ERROR: Can't resume missing parent dialog '" + cur . id + "'." ) ) ;
203+ logger . info ( this , 'session.endDialog()' ) ;
204+ var childId = cur . id ;
205+ cur = this . popDialog ( ) ;
206+ this . startBatch ( ) ;
207+ if ( cur ) {
208+ var dialog = this . findDialog ( cur . id ) ;
209+ if ( dialog ) {
210+ dialog . dialogResumed ( this , { resumed : dlg . ResumeReason . completed , response : true , childId : childId } ) ;
211+ }
212+ else {
213+ this . error ( new Error ( "Can't resume missing parent dialog '" + cur . id + "'." ) ) ;
214+ }
207215 }
208216 }
209217 return this ;
210218 } ;
211219 Session . prototype . endDialogWithResult = function ( result ) {
212220 var cur = this . curDialog ( ) ;
213- if ( ! cur ) {
214- console . error ( 'ERROR: Too many calls to session.endDialog().' ) ;
215- return this ;
216- }
217- result = result || { } ;
218- if ( ! result . hasOwnProperty ( 'resumed' ) ) {
219- result . resumed = dlg . ResumeReason . completed ;
220- }
221- result . childId = cur . id ;
222- logger . info ( this , 'session.endDialogWithResult()' ) ;
223- cur = this . popDialog ( ) ;
224- this . startBatch ( ) ;
225221 if ( cur ) {
226- var dialog = this . findDialog ( cur . id ) ;
227- if ( dialog ) {
228- dialog . dialogResumed ( this , result ) ;
222+ result = result || { } ;
223+ if ( ! result . hasOwnProperty ( 'resumed' ) ) {
224+ result . resumed = dlg . ResumeReason . completed ;
229225 }
230- else {
231- this . error ( new Error ( "ERROR: Can't resume missing parent dialog '" + cur . id + "'." ) ) ;
226+ result . childId = cur . id ;
227+ logger . info ( this , 'session.endDialogWithResult()' ) ;
228+ cur = this . popDialog ( ) ;
229+ this . startBatch ( ) ;
230+ if ( cur ) {
231+ var dialog = this . findDialog ( cur . id ) ;
232+ if ( dialog ) {
233+ dialog . dialogResumed ( this , result ) ;
234+ }
235+ else {
236+ this . error ( new Error ( "Can't resume missing parent dialog '" + cur . id + "'." ) ) ;
237+ }
238+ }
239+ }
240+ return this ;
241+ } ;
242+ Session . prototype . cancelDialog = function ( dialogId , replaceWithId , replaceWithArgs ) {
243+ var childId = typeof dialogId === 'number' ? this . sessionState . callstack [ dialogId ] . id : dialogId ;
244+ var cur = this . deleteDialogs ( dialogId ) ;
245+ if ( replaceWithId ) {
246+ logger . info ( this , 'session.cancelDialog(%s)' , replaceWithId ) ;
247+ var id = this . resolveDialogId ( replaceWithId ) ;
248+ var dialog = this . findDialog ( id ) ;
249+ this . pushDialog ( { id : id , state : { } } ) ;
250+ this . startBatch ( ) ;
251+ dialog . begin ( this , replaceWithArgs ) ;
252+ }
253+ else {
254+ logger . info ( this , 'session.cancelDialog()' ) ;
255+ this . startBatch ( ) ;
256+ if ( cur ) {
257+ var dialog = this . findDialog ( cur . id ) ;
258+ if ( dialog ) {
259+ dialog . dialogResumed ( this , { resumed : dlg . ResumeReason . canceled , response : null , childId : childId } ) ;
260+ }
261+ else {
262+ this . error ( new Error ( "Can't resume missing parent dialog '" + cur . id + "'." ) ) ;
263+ }
232264 }
233265 }
234266 return this ;
@@ -313,20 +345,106 @@ var Session = (function (_super) {
313345 }
314346 } ;
315347 Session . prototype . routeMessage = function ( ) {
316- var cur = this . curDialog ( ) ;
317- if ( ! cur ) {
318- this . beginDialog ( this . options . dialogId , this . options . dialogArgs ) ;
348+ var _this = this ;
349+ var _that = this ;
350+ function routeToDialog ( recognizeResult ) {
351+ var cur = _that . curDialog ( ) ;
352+ if ( ! cur ) {
353+ _that . beginDialog ( _that . options . dialogId , _that . options . dialogArgs ) ;
354+ }
355+ else {
356+ var dialog = _that . findDialog ( cur . id ) ;
357+ _that . dialogData = cur . state ;
358+ dialog . replyReceived ( _that , recognizeResult ) ;
359+ }
319360 }
320- else if ( this . validateCallstack ( ) ) {
321- var dialog = this . findDialog ( cur . id ) ;
322- this . dialogData = cur . state ;
323- dialog . replyReceived ( this ) ;
361+ if ( this . validateCallstack ( ) ) {
362+ this . recognizeCurDialog ( function ( err , dialogResult ) {
363+ if ( err ) {
364+ _this . error ( err ) ;
365+ }
366+ else if ( dialogResult . score < 1.0 ) {
367+ _this . recognizeCallstackActions ( function ( err , actionResult ) {
368+ if ( err ) {
369+ _this . error ( err ) ;
370+ }
371+ else if ( actionResult . score > dialogResult . score ) {
372+ if ( actionResult . dialogId ) {
373+ var dialog = _this . findDialog ( actionResult . dialogId ) ;
374+ dialog . invokeAction ( _this , actionResult ) ;
375+ }
376+ else {
377+ _this . options . actions . invokeAction ( _this , actionResult ) ;
378+ }
379+ }
380+ else {
381+ routeToDialog ( dialogResult ) ;
382+ }
383+ } ) ;
384+ }
385+ else {
386+ routeToDialog ( dialogResult ) ;
387+ }
388+ } ) ;
324389 }
325390 else {
326- console . warn ( 'Callstack is invalid, resetting session.' ) ;
391+ logger . warn ( this , 'Callstack is invalid, resetting session.' ) ;
327392 this . reset ( this . options . dialogId , this . options . dialogArgs ) ;
328393 }
329394 } ;
395+ Session . prototype . recognizeCurDialog = function ( done ) {
396+ var cur = this . curDialog ( ) ;
397+ if ( cur && this . message . text . indexOf ( 'action?' ) !== 0 ) {
398+ var dialog = this . findDialog ( cur . id ) ;
399+ dialog . recognize ( { message : this . message , dialogData : cur . state , activeDialog : true } , done ) ;
400+ }
401+ else {
402+ done ( null , { score : 0.0 } ) ;
403+ }
404+ } ;
405+ Session . prototype . recognizeCallstackActions = function ( done ) {
406+ var _this = this ;
407+ var ss = this . sessionState ;
408+ var i = ss . callstack . length - 1 ;
409+ var result = { score : 0.0 } ;
410+ async . whilst ( function ( ) {
411+ return ( i >= 0 && result . score < 1.0 ) ;
412+ } , function ( cb ) {
413+ try {
414+ var index = i -- ;
415+ var cur = ss . callstack [ index ] ;
416+ var dialog = _this . findDialog ( cur . id ) ;
417+ dialog . recognizeAction ( _this . message , function ( err , r ) {
418+ if ( ! err && r && r . score > result . score ) {
419+ result = r ;
420+ result . dialogId = cur . id ;
421+ result . dialogIndex = index ;
422+ }
423+ cb ( err ) ;
424+ } ) ;
425+ }
426+ catch ( e ) {
427+ cb ( e ) ;
428+ }
429+ } , function ( err ) {
430+ if ( ! err ) {
431+ if ( result . score < 1.0 && _this . options . actions ) {
432+ _this . options . actions . recognizeAction ( _this . message , function ( err , r ) {
433+ if ( ! err && r && r . score > result . score ) {
434+ result = r ;
435+ }
436+ done ( err , result ) ;
437+ } ) ;
438+ }
439+ else {
440+ done ( null , result ) ;
441+ }
442+ }
443+ else {
444+ done ( err instanceof Error ? err : new Error ( err . toString ( ) ) , null ) ;
445+ }
446+ } ) ;
447+ } ;
330448 Session . prototype . vgettext = function ( messageid , args ) {
331449 var tmpl ;
332450 if ( this . options . localizer && this . message ) {
@@ -378,6 +496,28 @@ var Session = (function (_super) {
378496 this . dialogData = cur ? cur . state : null ;
379497 return cur ;
380498 } ;
499+ Session . prototype . deleteDialogs = function ( dialogId ) {
500+ var ss = this . sessionState ;
501+ var index = - 1 ;
502+ if ( typeof dialogId === 'string' ) {
503+ for ( var i = ss . callstack . length - 1 ; i >= 0 ; i -- ) {
504+ if ( ss . callstack [ i ] . id == dialogId ) {
505+ index = i ;
506+ break ;
507+ }
508+ }
509+ }
510+ else {
511+ index = dialogId ;
512+ }
513+ if ( index < 0 && index < ss . callstack . length ) {
514+ throw new Error ( 'Unable to cancel dialog. Dialog[' + dialogId + '] not found.' ) ;
515+ }
516+ ss . callstack . splice ( index ) ;
517+ var cur = this . curDialog ( ) ;
518+ this . dialogData = cur ? cur . state : null ;
519+ return cur ;
520+ } ;
381521 Session . prototype . curDialog = function ( ) {
382522 var cur ;
383523 var ss = this . sessionState ;
0 commit comments