UNPKG

botbuilder

Version:

Bot Builder is a framework for building rich bots on virtually any platform.

429 lines • 18 kB
"use strict"; 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.InspectionState = exports.InspectionMiddleware = void 0; /** * @module botbuilder */ /** * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ const uuid_1 = require("uuid"); const botframework_connector_1 = require("botframework-connector"); const botbuilder_core_1 = require("botbuilder-core"); const teamsActivityHelpers_1 = require("./teamsActivityHelpers"); /** @private */ class TraceActivity { static makeCommandActivity(command) { return { type: botbuilder_core_1.ActivityTypes.Trace, timestamp: new Date(), name: 'Command', label: 'Command', value: command, valueType: 'https://www.botframework.com/schemas/command', }; } static fromActivity(activity, name, label) { return { type: botbuilder_core_1.ActivityTypes.Trace, timestamp: new Date(), name: name, label: label, value: activity, valueType: 'https://www.botframework.com/schemas/activity', }; } static fromState(botState) { return { type: botbuilder_core_1.ActivityTypes.Trace, timestamp: new Date(), name: 'BotState', label: 'Bot State', value: botState, valueType: 'https://www.botframework.com/schemas/botState', }; } static fromConversationReference(conversationReference) { return { type: botbuilder_core_1.ActivityTypes.Trace, timestamp: new Date(), name: 'Deleted Message', label: 'MessageDelete', value: conversationReference, valueType: 'https://www.botframework.com/schemas/conversationReference', }; } static fromError(errorMessage) { return { type: botbuilder_core_1.ActivityTypes.Trace, timestamp: new Date(), name: 'Turn Error', label: 'TurnError', value: errorMessage, valueType: 'https://www.botframework.com/schemas/error', }; } } /** @private */ class InterceptionMiddleware { /** * Implement middleware signature * * @param turnContext {TurnContext} An incoming TurnContext object. * @param next {function} The next delegate function. */ onTurn(turnContext, next) { return __awaiter(this, void 0, void 0, function* () { const { shouldForwardToApplication, shouldIntercept } = yield this.invokeInbound(turnContext, TraceActivity.fromActivity(turnContext.activity, 'ReceivedActivity', 'Received Activity')); if (shouldIntercept) { turnContext.onSendActivities((ctx, activities, nextSend) => __awaiter(this, void 0, void 0, function* () { const traceActivities = []; activities.forEach((activity) => { traceActivities.push(TraceActivity.fromActivity(activity, 'SentActivity', 'Sent Activity')); }); yield this.invokeOutbound(ctx, traceActivities); return yield nextSend(); })); turnContext.onUpdateActivity((ctx, activity, nextUpdate) => __awaiter(this, void 0, void 0, function* () { const traceActivity = TraceActivity.fromActivity(activity, 'MessageUpdate', 'Updated Message'); yield this.invokeOutbound(ctx, [traceActivity]); return yield nextUpdate(); })); turnContext.onDeleteActivity((ctx, reference, nextDelete) => __awaiter(this, void 0, void 0, function* () { const traceActivity = TraceActivity.fromConversationReference(reference); yield this.invokeOutbound(ctx, [traceActivity]); return yield nextDelete(); })); } if (shouldForwardToApplication) { try { yield next(); } catch (err) { const traceActivity = TraceActivity.fromError(err.toString()); yield this.invokeOutbound(turnContext, [traceActivity]); throw err; } } if (shouldIntercept) { yield this.invokeTraceState(turnContext); } }); } invokeInbound(turnContext, traceActivity) { return __awaiter(this, void 0, void 0, function* () { try { return yield this.inbound(turnContext, traceActivity); } catch (err) { console.warn(`Exception in inbound interception ${err}`); return { shouldForwardToApplication: true, shouldIntercept: false }; } }); } invokeOutbound(turnContext, traceActivities) { return __awaiter(this, void 0, void 0, function* () { try { yield this.outbound(turnContext, traceActivities); } catch (err) { console.warn(`Exception in outbound interception ${err}`); } }); } invokeTraceState(turnContext) { return __awaiter(this, void 0, void 0, function* () { try { yield this.traceState(turnContext); } catch (err) { console.warn(`Exception in state interception ${err}`); } }); } } /** * InspectionMiddleware for emulator inspection of runtime Activities and BotState. * * @remarks * InspectionMiddleware for emulator inspection of runtime Activities and BotState. * @deprecated This class will be removed in a future version of the framework. */ class InspectionMiddleware extends InterceptionMiddleware { /** * Create the Inspection middleware for sending trace activities out to an emulator session * * @param inspectionState A state management object for inspection state. * @param userState A state management object for user state. * @param conversationState A state management object for conversation state. * @param credentials The authentication credentials. */ constructor(inspectionState, userState, conversationState, credentials) { super(); this.inspectionState = inspectionState; this.inspectionStateAccessor = inspectionState.createProperty('InspectionSessionByStatus'); this.userState = userState; this.conversationState = conversationState; credentials = Object.assign({ appId: '', appPassword: '' }, credentials); this.credentials = new botframework_connector_1.MicrosoftAppCredentials(credentials.appId, credentials.appPassword); } /** * Indentifies open and attach commands and calls the appropriate method. * * @param turnContext The [TurnContext](xref:botbuilder-core.TurnContext) for this turn. * @returns True if the command is open or attached, otherwise false. */ processCommand(turnContext) { return __awaiter(this, void 0, void 0, function* () { if (turnContext.activity.type == botbuilder_core_1.ActivityTypes.Message && turnContext.activity.text !== undefined) { const originalText = turnContext.activity.text; botbuilder_core_1.TurnContext.removeRecipientMention(turnContext.activity); const command = turnContext.activity.text.trim().split(' '); if (command.length > 1 && command[0] === InspectionMiddleware.command) { if (command.length === 2 && command[1] === 'open') { yield this.processOpenCommand(turnContext); return true; } if (command.length === 3 && command[1] === 'attach') { yield this.processAttachCommand(turnContext, command[2]); return true; } } turnContext.activity.text = originalText; } return false; }); } /** * Processes inbound activities. * * @param turnContext The [TurnContext](xref:botbuilder-core.TurnContext) for this turn. * @param traceActivity The trace activity. * @returns {Promise<any>} A promise representing the asynchronous operation. */ inbound(turnContext, traceActivity) { return __awaiter(this, void 0, void 0, function* () { if (yield this.processCommand(turnContext)) { return { shouldForwardToApplication: false, shouldIntercept: false }; } const session = yield this.findSession(turnContext); if (session !== undefined) { if (yield this.invokeSend(turnContext, session, traceActivity)) { return { shouldForwardToApplication: true, shouldIntercept: true }; } else { return { shouldForwardToApplication: true, shouldIntercept: false }; } } else { return { shouldForwardToApplication: true, shouldIntercept: false }; } }); } /** * Processes outbound activities. * * @param turnContext The [TurnContext](xref:botbuilder-core.TurnContext) for this turn. * @param traceActivities A collection of trace activities. */ outbound(turnContext, traceActivities) { return __awaiter(this, void 0, void 0, function* () { const session = yield this.findSession(turnContext); if (session !== undefined) { for (let i = 0; i < traceActivities.length; i++) { const traceActivity = traceActivities[i]; if (!(yield this.invokeSend(turnContext, session, traceActivity))) { break; } } } }); } /** * Processes the state management object. * * @param turnContext The [TurnContext](xref:botbuilder-core.TurnContext) for this turn. */ traceState(turnContext) { return __awaiter(this, void 0, void 0, function* () { const session = yield this.findSession(turnContext); if (session !== undefined) { if (this.userState !== undefined) { yield this.userState.load(turnContext, false); } if (this.conversationState != undefined) { yield this.conversationState.load(turnContext, false); } const botState = {}; if (this.userState !== undefined) { botState.userState = this.userState.get(turnContext); } if (this.conversationState !== undefined) { botState.conversationState = this.conversationState.get(turnContext); } yield this.invokeSend(turnContext, session, TraceActivity.fromState(botState)); } }); } /** * @private */ processOpenCommand(turnContext) { return __awaiter(this, void 0, void 0, function* () { const sessions = yield this.inspectionStateAccessor.get(turnContext, InspectionSessionsByStatus.DefaultValue); const sessionId = this.openCommand(sessions, botbuilder_core_1.TurnContext.getConversationReference(turnContext.activity)); yield turnContext.sendActivity(TraceActivity.makeCommandActivity(`${InspectionMiddleware.command} attach ${sessionId}`)); yield this.inspectionState.saveChanges(turnContext, false); }); } /** * @private */ processAttachCommand(turnContext, sessionId) { return __awaiter(this, void 0, void 0, function* () { const sessions = yield this.inspectionStateAccessor.get(turnContext, InspectionSessionsByStatus.DefaultValue); if (this.attachCommand(this.getAttachId(turnContext.activity), sessions, sessionId)) { yield turnContext.sendActivity('Attached to session, all traffic is being replicated for inspection.'); } else { yield turnContext.sendActivity(`Open session with id ${sessionId} does not exist.`); } yield this.inspectionState.saveChanges(turnContext, false); }); } /** * @private */ openCommand(sessions, conversationReference) { const sessionId = (0, uuid_1.v4)(); sessions.openedSessions[sessionId] = conversationReference; return sessionId; } /** * @private */ attachCommand(attachId, sessions, sessionId) { const inspectionSessionState = sessions.openedSessions[sessionId]; if (inspectionSessionState !== undefined) { sessions.attachedSessions[attachId] = inspectionSessionState; delete sessions.openedSessions[sessionId]; return true; } return false; } /** * @private */ findSession(turnContext) { return __awaiter(this, void 0, void 0, function* () { const sessions = yield this.inspectionStateAccessor.get(turnContext, InspectionSessionsByStatus.DefaultValue); const conversationReference = sessions.attachedSessions[this.getAttachId(turnContext.activity)]; if (conversationReference !== undefined) { return new InspectionSession(conversationReference, this.credentials); } return undefined; }); } /** * @private */ invokeSend(turnContext, session, activity) { return __awaiter(this, void 0, void 0, function* () { if (yield session.send(activity)) { return true; } else { yield this.cleanUpSession(turnContext); return false; } }); } /** * @private */ cleanUpSession(turnContext) { return __awaiter(this, void 0, void 0, function* () { const sessions = yield this.inspectionStateAccessor.get(turnContext, InspectionSessionsByStatus.DefaultValue); delete sessions.attachedSessions[this.getAttachId(turnContext.activity)]; yield this.inspectionState.saveChanges(turnContext, false); }); } /** * @private */ getAttachId(activity) { // If we are running in a Microsoft Teams Team the conversation Id will reflect a particular thread the bot is in. // So if we are in a Team then we will associate the "attach" with the Team Id rather than the more restrictive conversation Id. const teamId = (0, teamsActivityHelpers_1.teamsGetTeamId)(activity); return teamId ? teamId : activity.conversation.id; } } exports.InspectionMiddleware = InspectionMiddleware; InspectionMiddleware.command = '/INSPECT'; /** @private */ class InspectionSession { constructor(conversationReference, credentials) { this.conversationReference = conversationReference; this.connectorClient = new botframework_connector_1.ConnectorClient(credentials, { baseUri: conversationReference.serviceUrl }); } send(activity) { return __awaiter(this, void 0, void 0, function* () { botbuilder_core_1.TurnContext.applyConversationReference(activity, this.conversationReference); try { yield this.connectorClient.conversations.sendToConversation(activity.conversation.id, activity); } catch (_a) { return false; } return true; }); } } /** @private */ class InspectionSessionsByStatus { constructor() { this.openedSessions = {}; this.attachedSessions = {}; } } InspectionSessionsByStatus.DefaultValue = new InspectionSessionsByStatus(); /** * InspectionState for use by the InspectionMiddleware for emulator inspection of runtime Activities and BotState. * * @remarks * InspectionState for use by the InspectionMiddleware for emulator inspection of runtime Activities and BotState. * @deprecated This class will be removed in a future version of the framework. */ class InspectionState extends botbuilder_core_1.BotState { /** * Creates a new instance of the [InspectionState](xref:botbuilder.InspectionState) class. * * @param storage The [Storage](xref:botbuilder-core.Storage) layer this state management object will use to store and retrieve state. */ constructor(storage) { super(storage, (context) => { return Promise.resolve(this.getStorageKey(context)); }); } /** * Gets the key to use when reading and writing state to and from storage. * * @param _turnContext The [TurnContext](xref:botbuilder-core.TurnContext) for this turn. * @returns The storage key. */ getStorageKey(_turnContext) { return 'InspectionState'; } } exports.InspectionState = InspectionState; //# sourceMappingURL=inspectionMiddleware.js.map