185 lines
No EOL
8.1 KiB
JavaScript
185 lines
No EOL
8.1 KiB
JavaScript
"use strict";
|
|
/**
|
|
* @module botbuilder
|
|
*/
|
|
/**
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License.
|
|
*/
|
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
});
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.ConsoleTranscriptLogger = exports.TranscriptLoggerMiddleware = void 0;
|
|
const botframework_schema_1 = require("botframework-schema");
|
|
const turnContext_1 = require("./turnContext");
|
|
/**
|
|
* Logs incoming and outgoing activities to a TranscriptStore.
|
|
*/
|
|
class TranscriptLoggerMiddleware {
|
|
/**
|
|
* Middleware for logging incoming and outgoing activities to a transcript store.
|
|
*
|
|
* @param logger Transcript logger
|
|
*/
|
|
constructor(logger) {
|
|
if (!logger) {
|
|
throw new Error('TranscriptLoggerMiddleware requires a TranscriptLogger instance.');
|
|
}
|
|
this.logger = logger;
|
|
}
|
|
/**
|
|
* Initialization for middleware turn.
|
|
*
|
|
* @param context Context for the current turn of conversation with the user.
|
|
* @param next Function to call at the end of the middleware chain.
|
|
*/
|
|
onTurn(context, next) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
const transcript = [];
|
|
// log incoming activity at beginning of turn
|
|
if (context.activity) {
|
|
if (!context.activity.from.role) {
|
|
context.activity.from.role = botframework_schema_1.RoleTypes.User;
|
|
}
|
|
this.logActivity(transcript, this.cloneActivity(context.activity));
|
|
}
|
|
// hook up onSend pipeline
|
|
context.onSendActivities((ctx, activities, next) => __awaiter(this, void 0, void 0, function* () {
|
|
// Run full pipeline.
|
|
const responses = yield next();
|
|
activities.forEach((activity, index) => {
|
|
const clonedActivity = this.cloneActivity(activity);
|
|
clonedActivity.id = responses && responses[index] ? responses[index].id : clonedActivity.id;
|
|
// For certain channels, a ResourceResponse with an id is not always sent to the bot.
|
|
// This fix uses the timestamp on the activity to populate its id for logging the transcript.
|
|
// If there is no outgoing timestamp, the current time for the bot is used for the activity.id.
|
|
// See https://github.com/microsoft/botbuilder-js/issues/1122
|
|
if (!clonedActivity.id) {
|
|
const prefix = `g_${Math.random().toString(36).slice(2, 8)}`;
|
|
if (clonedActivity.timestamp) {
|
|
clonedActivity.id = `${prefix}${new Date(clonedActivity.timestamp).getTime().toString()}`;
|
|
}
|
|
else {
|
|
clonedActivity.id = `${prefix}${new Date().getTime().toString()}`;
|
|
}
|
|
}
|
|
this.logActivity(transcript, clonedActivity);
|
|
});
|
|
return responses;
|
|
}));
|
|
// hook up update activity pipeline
|
|
context.onUpdateActivity((ctx, activity, next) => __awaiter(this, void 0, void 0, function* () {
|
|
// run full pipeline
|
|
const response = yield next();
|
|
// add Message Update activity
|
|
const updateActivity = this.cloneActivity(activity);
|
|
updateActivity.type = botframework_schema_1.ActivityTypes.MessageUpdate;
|
|
this.logActivity(transcript, updateActivity);
|
|
return response;
|
|
}));
|
|
// hook up delete activity pipeline
|
|
context.onDeleteActivity((ctx, reference, next) => __awaiter(this, void 0, void 0, function* () {
|
|
// run full pipeline
|
|
yield next();
|
|
// add MessageDelete activity
|
|
// log as MessageDelete activity
|
|
const deleteActivity = turnContext_1.TurnContext.applyConversationReference({
|
|
type: botframework_schema_1.ActivityTypes.MessageDelete,
|
|
id: reference.activityId,
|
|
}, reference, false);
|
|
this.logActivity(transcript, this.cloneActivity(deleteActivity));
|
|
}));
|
|
// process bot logic
|
|
yield next();
|
|
// flush transcript at end of turn
|
|
while (transcript.length) {
|
|
try {
|
|
// If the implementation of this.logger.logActivity() is asynchronous, we don't
|
|
// await it as to not block processing of activities.
|
|
// Because TranscriptLogger.logActivity() returns void or Promise<void>, we capture
|
|
// the result and see if it is a Promise.
|
|
const maybePromise = this.logger.logActivity(transcript.shift());
|
|
// If this.logger.logActivity() returns a Promise, a catch is added in case there
|
|
// is no innate error handling in the method. This catch prevents
|
|
// UnhandledPromiseRejectionWarnings from being thrown and prints the error to the
|
|
// console.
|
|
if (maybePromise instanceof Promise) {
|
|
maybePromise.catch((err) => {
|
|
this.transcriptLoggerErrorHandler(err);
|
|
});
|
|
}
|
|
}
|
|
catch (err) {
|
|
this.transcriptLoggerErrorHandler(err);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
/**
|
|
* Logs the Activity.
|
|
*
|
|
* @param transcript Array where the activity will be pushed.
|
|
* @param activity Activity to log.
|
|
*/
|
|
logActivity(transcript, activity) {
|
|
if (!activity.timestamp) {
|
|
activity.timestamp = new Date();
|
|
}
|
|
// We should not log ContinueConversation events used by skills to initialize the middleware.
|
|
if (!(activity.type === botframework_schema_1.ActivityTypes.Event && activity.name === botframework_schema_1.ActivityEventNames.ContinueConversation)) {
|
|
transcript.push(activity);
|
|
}
|
|
}
|
|
/**
|
|
* Clones the Activity entity.
|
|
*
|
|
* @param activity Activity to clone.
|
|
* @returns The cloned activity.
|
|
*/
|
|
cloneActivity(activity) {
|
|
return Object.assign({}, activity);
|
|
}
|
|
/**
|
|
* Error logging helper function.
|
|
*
|
|
* @param err Error or object to console.error out.
|
|
*/
|
|
transcriptLoggerErrorHandler(err) {
|
|
// tslint:disable:no-console
|
|
if (err instanceof Error) {
|
|
console.error(`TranscriptLoggerMiddleware logActivity failed: "${err.message}"`);
|
|
console.error(err.stack);
|
|
}
|
|
else {
|
|
console.error(`TranscriptLoggerMiddleware logActivity failed: "${JSON.stringify(err)}"`);
|
|
}
|
|
// tslint:enable:no-console
|
|
}
|
|
}
|
|
exports.TranscriptLoggerMiddleware = TranscriptLoggerMiddleware;
|
|
/**
|
|
* ConsoleTranscriptLogger , writes activities to Console output.
|
|
*/
|
|
class ConsoleTranscriptLogger {
|
|
/**
|
|
* Log an activity to the transcript.
|
|
*
|
|
* @param activity Activity being logged.
|
|
*/
|
|
logActivity(activity) {
|
|
if (!activity) {
|
|
throw new Error('Activity is required.');
|
|
}
|
|
// tslint:disable-next-line:no-console
|
|
console.log('Activity Log:', activity);
|
|
}
|
|
}
|
|
exports.ConsoleTranscriptLogger = ConsoleTranscriptLogger;
|
|
//# sourceMappingURL=transcriptLogger.js.map
|