Skip to content

Commit b77f683

Browse files
committed
Added watch support.
1 parent 125f22b commit b77f683

File tree

5 files changed

+192
-10
lines changed

5 files changed

+192
-10
lines changed

Node/core/lib/Session.js

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ var Message_1 = require("./Message");
99
var consts = require("./consts");
1010
var sprintf = require("sprintf-js");
1111
var events = require("events");
12+
var async = require("async");
1213
var Session = (function (_super) {
1314
__extends(Session, _super);
1415
function Session(options) {
@@ -39,6 +40,7 @@ var Session = (function (_super) {
3940
userData: this.userData,
4041
conversationData: this.conversationData,
4142
privateConversationData: this.privateConversationData,
43+
dialogData: this.dialogData,
4244
localizer: this.localizer,
4345
logger: this.logger,
4446
dialogStack: function () { return _this.dialogStack(); },
@@ -489,6 +491,53 @@ var Session = (function (_super) {
489491
this.error(new Error('Invalid Dialog Stack.'));
490492
}
491493
};
494+
Session.prototype.watch = function (variable, enable) {
495+
if (enable === void 0) { enable = true; }
496+
var name = variable.toLowerCase();
497+
if (!this.userData.hasOwnProperty(consts.Data.DebugWatches)) {
498+
this.userData[consts.Data.DebugWatches] = {};
499+
}
500+
if (watchableHandlers.hasOwnProperty(name)) {
501+
var entry = watchableHandlers[name];
502+
this.userData[consts.Data.DebugWatches][entry.name] = enable;
503+
}
504+
else {
505+
throw new Error("Invalid watch statement. '" + variable + " isn't watchable");
506+
}
507+
return this;
508+
};
509+
Session.prototype.watchList = function () {
510+
var watches = [];
511+
if (this.userData.hasOwnProperty(consts.Data.DebugWatches)) {
512+
for (var name_1 in this.userData[consts.Data.DebugWatches]) {
513+
if (this.userData[consts.Data.DebugWatches][name_1]) {
514+
watches.push(name_1);
515+
}
516+
}
517+
}
518+
return watches;
519+
};
520+
Session.watchable = function (variable, handler) {
521+
if (handler) {
522+
watchableHandlers[variable.toLowerCase()] = { name: variable, handler: handler };
523+
}
524+
else {
525+
var entry = watchableHandlers[variable.toLowerCase()];
526+
if (entry) {
527+
handler = entry.handler;
528+
}
529+
}
530+
return handler;
531+
};
532+
Session.watchableList = function () {
533+
var variables = [];
534+
for (var name_2 in watchableHandlers) {
535+
if (watchableHandlers.hasOwnProperty(name_2)) {
536+
variables.push(watchableHandlers[name_2].name);
537+
}
538+
}
539+
return variables;
540+
};
492541
Session.prototype.onSave = function (cb) {
493542
var _this = this;
494543
this.options.onSave(function (err) {
@@ -519,12 +568,36 @@ var Session = (function (_super) {
519568
};
520569
Session.prototype.onFinishBatch = function (cb) {
521570
var _this = this;
522-
this.logger.flush(function (err) {
523-
_this.sendingBatch = false;
571+
var ctx = this.toRecognizeContext();
572+
async.each(this.watchList(), function (variable, cb) {
573+
var entry = watchableHandlers[variable];
574+
if (entry && entry.handler) {
575+
try {
576+
entry.handler(ctx, function (err, value) {
577+
if (!err) {
578+
_this.logger.dump(variable, value);
579+
}
580+
cb(err);
581+
});
582+
}
583+
catch (e) {
584+
cb(e);
585+
}
586+
}
587+
else {
588+
cb(new Error("'" + variable + "' isn't watchable."));
589+
}
590+
}, function (err) {
524591
if (err) {
525-
console.error(err);
592+
_this.logger.error(_this.dialogStack(), err);
526593
}
527-
cb();
594+
_this.logger.flush(function (err) {
595+
_this.sendingBatch = false;
596+
if (err) {
597+
console.error(err);
598+
}
599+
cb();
600+
});
528601
});
529602
};
530603
Session.prototype.startBatch = function () {
@@ -642,3 +715,12 @@ var Session = (function (_super) {
642715
return Session;
643716
}(events.EventEmitter));
644717
exports.Session = Session;
718+
var watchableHandlers = {
719+
'userdata': { name: 'userData', handler: function (ctx, cb) { return cb(null, ctx.userData); } },
720+
'conversationdata': { name: 'conversationData', handler: function (ctx, cb) { return cb(null, ctx.conversationData); } },
721+
'privateconversationdata': { name: 'privateConversationData', handler: function (ctx, cb) { return cb(null, ctx.privateConversationData); } },
722+
'dialogdata': { name: 'dialogData', handler: function (ctx, cb) { return cb(null, ctx.dialogData); } },
723+
'dialogstack': { name: 'dialogStack', handler: function (ctx, cb) { return cb(null, ctx.dialogStack()); } },
724+
'preferredlocale': { name: 'preferredLocale', handler: function (ctx, cb) { return cb(null, ctx.preferredLocale()); } },
725+
'libraryname': { name: 'libraryName', handler: function (ctx, cb) { return cb(null, ctx.libraryName); } }
726+
};

Node/core/lib/consts.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ exports.Data = {
2424
Field: 'BotBuilder.Data.Field',
2525
FirstRunVersion: 'BotBuilder.Data.FirstRunVersion',
2626
PreferredLocale: 'BotBuilder.Data.PreferredLocale',
27-
DebugAddress: 'BotBuilder.Data.DebugAddress'
27+
DebugAddress: 'BotBuilder.Data.DebugAddress',
28+
DebugWatches: 'BotBuilder.Data.DebugWatches'
2829
};
2930
exports.DialogId = {
3031
Prompts: 'BotBuilder:Prompts',

Node/core/src/Session.ts

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ export interface ISessionMiddleware {
6262
(session: Session, next: Function): void;
6363
}
6464

65+
export interface IWatchableHandler {
66+
(context: IRecognizeContext, callback: (err: Error, value: any) => void): void;
67+
}
68+
6569
export class Session extends events.EventEmitter {
6670
private msgSent = false;
6771
private _isReset = false;
@@ -89,6 +93,7 @@ export class Session extends events.EventEmitter {
8993
userData: this.userData,
9094
conversationData: this.conversationData,
9195
privateConversationData: this.privateConversationData,
96+
dialogData: this.dialogData,
9297
localizer: this.localizer,
9398
logger: this.logger,
9499
dialogStack: () => { return this.dialogStack(); },
@@ -603,6 +608,62 @@ export class Session extends events.EventEmitter {
603608
}
604609
}
605610

611+
//-----------------------------------------------------
612+
// Watch Statements
613+
//-----------------------------------------------------
614+
615+
/** Enables/disables the watch statment for a given variable. */
616+
public watch(variable: string, enable = true): this {
617+
let name = variable.toLowerCase();
618+
if (!this.userData.hasOwnProperty(consts.Data.DebugWatches)) {
619+
this.userData[consts.Data.DebugWatches] = {};
620+
}
621+
if (watchableHandlers.hasOwnProperty(name)) {
622+
var entry = watchableHandlers[name];
623+
this.userData[consts.Data.DebugWatches][entry.name] = enable;
624+
} else {
625+
throw new Error("Invalid watch statement. '" + variable + " isn't watchable");
626+
}
627+
return this;
628+
}
629+
630+
/** Returns the list of enabled watch statements for the session. */
631+
public watchList(): string[] {
632+
var watches: string[] = [];
633+
if (this.userData.hasOwnProperty(consts.Data.DebugWatches)) {
634+
for (let name in this.userData[consts.Data.DebugWatches]) {
635+
if (this.userData[consts.Data.DebugWatches][name]) {
636+
watches.push(name);
637+
}
638+
}
639+
}
640+
return watches;
641+
}
642+
643+
/** Adds or retrieves a watchable variable from the session. */
644+
static watchable(variable: string, handler?: IWatchableHandler): IWatchableHandler {
645+
if (handler) {
646+
watchableHandlers[variable.toLowerCase()] = { name: variable, handler: handler };
647+
} else {
648+
let entry = watchableHandlers[variable.toLowerCase()];
649+
if (entry) {
650+
handler = entry.handler;
651+
}
652+
}
653+
return handler;
654+
}
655+
656+
/** Returns the list of watchable variables. */
657+
static watchableList(): string[] {
658+
let variables: string[] = [];
659+
for (let name in watchableHandlers) {
660+
if (watchableHandlers.hasOwnProperty(name)) {
661+
variables.push(watchableHandlers[name].name);
662+
}
663+
}
664+
return variables;
665+
}
666+
606667
//-----------------------------------------------------
607668
// PRIVATE HELPERS
608669
//-----------------------------------------------------
@@ -637,12 +698,36 @@ export class Session extends events.EventEmitter {
637698
}
638699

639700
private onFinishBatch(cb: Function): void {
640-
this.logger.flush((err) => {
641-
this.sendingBatch = false;
701+
// Dump watchList
702+
var ctx = this.toRecognizeContext();
703+
async.each(this.watchList(), (variable, cb) => {
704+
let entry = watchableHandlers[variable];
705+
if (entry && entry.handler) {
706+
try {
707+
entry.handler(ctx, (err, value) => {
708+
if (!err) {
709+
this.logger.dump(variable, value);
710+
}
711+
cb(err);
712+
});
713+
} catch (e) {
714+
cb(e);
715+
}
716+
} else {
717+
cb(new Error("'" + variable + "' isn't watchable."));
718+
}
719+
}, (err) => {
720+
// Flush logs
642721
if (err) {
643-
console.error(err);
722+
this.logger.error(this.dialogStack(), err);
644723
}
645-
cb();
724+
this.logger.flush((err) => {
725+
this.sendingBatch = false;
726+
if (err) {
727+
console.error(err);
728+
}
729+
cb();
730+
});
646731
});
647732
}
648733

@@ -774,3 +859,15 @@ export class Session extends events.EventEmitter {
774859
return this.message.sourceEvent;
775860
}
776861
}
862+
863+
// Initialize default list of watchable variables.
864+
let watchableHandlers: { [name: string]: { name: string; handler: IWatchableHandler; }; } = {
865+
'userdata': { name: 'userData', handler: (ctx, cb) => cb(null, ctx.userData) },
866+
'conversationdata': { name: 'conversationData', handler: (ctx, cb) => cb(null, ctx.conversationData) },
867+
'privateconversationdata': { name: 'privateConversationData', handler: (ctx, cb) => cb(null, ctx.privateConversationData) },
868+
'dialogdata': { name: 'dialogData', handler: (ctx, cb) => cb(null, ctx.dialogData) },
869+
'dialogstack': { name: 'dialogStack', handler: (ctx, cb) => cb(null, ctx.dialogStack()) },
870+
'preferredlocale': { name: 'preferredLocale', handler: (ctx, cb) => cb(null, ctx.preferredLocale()) },
871+
'libraryname': { name: 'libraryName', handler: (ctx, cb) => cb(null, ctx.libraryName) }
872+
};
873+

Node/core/src/consts.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ export const Data = {
5959
Field: 'BotBuilder.Data.Field',
6060
FirstRunVersion: 'BotBuilder.Data.FirstRunVersion',
6161
PreferredLocale: 'BotBuilder.Data.PreferredLocale',
62-
DebugAddress: 'BotBuilder.Data.DebugAddress'
62+
DebugAddress: 'BotBuilder.Data.DebugAddress',
63+
DebugWatches: 'BotBuilder.Data.DebugWatches'
6364
};
6465

6566
export const DialogId = {

Node/core/src/dialogs/IntentRecognizerSet.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export interface IRecognizeContext {
4646
userData: any;
4747
conversationData: any;
4848
privateConversationData: any;
49+
dialogData: any;
4950
localizer: ILocalizer;
5051
logger: SessionLogger;
5152
preferredLocale(): string;

0 commit comments

Comments
 (0)