UNPKG

16 kBJavaScriptView Raw
1"use strict";
2var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 return new (P || (P = Promise))(function (resolve, reject) {
4 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6 function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
7 step((generator = generator.apply(thisArg, _arguments || [])).next());
8 });
9};
10Object.defineProperty(exports, "__esModule", { value: true });
11/**
12 * @module botbuilder
13 */
14/**
15 * Copyright (c) Microsoft Corporation. All rights reserved.
16 * Licensed under the MIT License.
17 */
18const botframework_connector_1 = require("botframework-connector");
19const botbuilder_core_1 = require("botbuilder-core");
20const teamsActivityHelpers_1 = require("./teamsActivityHelpers");
21/** @private */
22class TraceActivity {
23 static makeCommandActivity(command) {
24 return {
25 type: botbuilder_core_1.ActivityTypes.Trace,
26 timestamp: new Date(),
27 name: 'Command',
28 label: 'Command',
29 value: command,
30 valueType: 'https://www.botframework.com/schemas/command'
31 };
32 }
33 static fromActivity(activity, name, label) {
34 return {
35 type: botbuilder_core_1.ActivityTypes.Trace,
36 timestamp: new Date(),
37 name: name,
38 label: label,
39 value: activity,
40 valueType: 'https://www.botframework.com/schemas/activity'
41 };
42 }
43 static fromState(botState) {
44 return {
45 type: botbuilder_core_1.ActivityTypes.Trace,
46 timestamp: new Date(),
47 name: 'BotState',
48 label: 'Bot State',
49 value: botState,
50 valueType: 'https://www.botframework.com/schemas/botState'
51 };
52 }
53 static fromConversationReference(conversationReference) {
54 return {
55 type: botbuilder_core_1.ActivityTypes.Trace,
56 timestamp: new Date(),
57 name: 'Deleted Message',
58 label: 'MessageDelete',
59 value: conversationReference,
60 valueType: 'https://www.botframework.com/schemas/conversationReference'
61 };
62 }
63 static fromError(errorMessage) {
64 return {
65 type: botbuilder_core_1.ActivityTypes.Trace,
66 timestamp: new Date(),
67 name: 'Turn Error',
68 label: 'TurnError',
69 value: errorMessage,
70 valueType: 'https://www.botframework.com/schemas/error'
71 };
72 }
73}
74/** @private */
75class InterceptionMiddleware {
76 /** Implement middleware signature
77 * @param context {TurnContext} An incoming TurnContext object.
78 * @param next {function} The next delegate function.
79 */
80 onTurn(turnContext, next) {
81 return __awaiter(this, void 0, void 0, function* () {
82 var { shouldForwardToApplication, shouldIntercept } = yield this.invokeInbound(turnContext, TraceActivity.fromActivity(turnContext.activity, 'ReceivedActivity', 'Received Activity'));
83 if (shouldIntercept) {
84 turnContext.onSendActivities((ctx, activities, nextSend) => __awaiter(this, void 0, void 0, function* () {
85 var traceActivities = [];
86 activities.forEach(activity => {
87 traceActivities.push(TraceActivity.fromActivity(activity, 'SentActivity', 'Sent Activity'));
88 });
89 yield this.invokeOutbound(ctx, traceActivities);
90 return yield nextSend();
91 }));
92 turnContext.onUpdateActivity((ctx, activity, nextUpdate) => __awaiter(this, void 0, void 0, function* () {
93 var traceActivity = TraceActivity.fromActivity(activity, 'MessageUpdate', 'Updated Message');
94 yield this.invokeOutbound(ctx, [traceActivity]);
95 return yield nextUpdate();
96 }));
97 turnContext.onDeleteActivity((ctx, reference, nextDelete) => __awaiter(this, void 0, void 0, function* () {
98 var traceActivity = TraceActivity.fromConversationReference(reference);
99 yield this.invokeOutbound(ctx, [traceActivity]);
100 return yield nextDelete();
101 }));
102 }
103 if (shouldForwardToApplication) {
104 try {
105 yield next();
106 }
107 catch (err) {
108 var traceActivity = TraceActivity.fromError(err.toString());
109 yield this.invokeOutbound(turnContext, [traceActivity]);
110 throw err;
111 }
112 }
113 if (shouldIntercept) {
114 yield this.invokeTraceState(turnContext);
115 }
116 });
117 }
118 invokeInbound(turnContext, traceActivity) {
119 return __awaiter(this, void 0, void 0, function* () {
120 try {
121 return yield this.inbound(turnContext, traceActivity);
122 }
123 catch (err) {
124 console.warn(`Exception in inbound interception ${err}`);
125 return { shouldForwardToApplication: true, shouldIntercept: false };
126 }
127 });
128 }
129 invokeOutbound(turnContext, traceActivities) {
130 return __awaiter(this, void 0, void 0, function* () {
131 try {
132 yield this.outbound(turnContext, traceActivities);
133 }
134 catch (err) {
135 console.warn(`Exception in outbound interception ${err}`);
136 }
137 });
138 }
139 invokeTraceState(turnContext) {
140 return __awaiter(this, void 0, void 0, function* () {
141 try {
142 yield this.traceState(turnContext);
143 }
144 catch (err) {
145 console.warn(`Exception in state interception ${err}`);
146 }
147 });
148 }
149}
150/**
151 * InspectionMiddleware for emulator inspection of runtime Activities and BotState.
152 *
153 * @remarks
154 * InspectionMiddleware for emulator inspection of runtime Activities and BotState.
155 *
156 */
157class InspectionMiddleware extends InterceptionMiddleware {
158 /**
159 * Create the Inspection middleware for sending trace activities out to an emulator session
160 */
161 constructor(inspectionState, userState, conversationState, credentials) {
162 super();
163 this.inspectionState = inspectionState;
164 this.inspectionStateAccessor = inspectionState.createProperty('InspectionSessionByStatus');
165 this.userState = userState;
166 this.conversationState = conversationState;
167 credentials = Object.assign({ appId: '', appPassword: '' }, credentials);
168 this.credentials = new botframework_connector_1.MicrosoftAppCredentials(credentials.appId, credentials.appPassword);
169 }
170 processCommand(turnContext) {
171 return __awaiter(this, void 0, void 0, function* () {
172 if (turnContext.activity.type == botbuilder_core_1.ActivityTypes.Message && turnContext.activity.text !== undefined) {
173 var originalText = turnContext.activity.text;
174 botbuilder_core_1.TurnContext.removeRecipientMention(turnContext.activity);
175 var command = turnContext.activity.text.trim().split(' ');
176 if (command.length > 1 && command[0] === InspectionMiddleware.command) {
177 if (command.length === 2 && command[1] === 'open') {
178 yield this.processOpenCommand(turnContext);
179 return true;
180 }
181 if (command.length === 3 && command[1] === 'attach') {
182 yield this.processAttachCommand(turnContext, command[2]);
183 return true;
184 }
185 }
186 turnContext.activity.text = originalText;
187 }
188 return false;
189 });
190 }
191 inbound(turnContext, traceActivity) {
192 return __awaiter(this, void 0, void 0, function* () {
193 if (yield this.processCommand(turnContext)) {
194 return { shouldForwardToApplication: false, shouldIntercept: false };
195 }
196 var session = yield this.findSession(turnContext);
197 if (session !== undefined) {
198 if (yield this.invokeSend(turnContext, session, traceActivity)) {
199 return { shouldForwardToApplication: true, shouldIntercept: true };
200 }
201 else {
202 return { shouldForwardToApplication: true, shouldIntercept: false };
203 }
204 }
205 else {
206 return { shouldForwardToApplication: true, shouldIntercept: false };
207 }
208 });
209 }
210 outbound(turnContext, traceActivities) {
211 return __awaiter(this, void 0, void 0, function* () {
212 var session = yield this.findSession(turnContext);
213 if (session !== undefined) {
214 for (var i = 0; i < traceActivities.length; i++) {
215 var traceActivity = traceActivities[i];
216 if (!(yield this.invokeSend(turnContext, session, traceActivity))) {
217 break;
218 }
219 }
220 }
221 });
222 }
223 traceState(turnContext) {
224 return __awaiter(this, void 0, void 0, function* () {
225 var session = yield this.findSession(turnContext);
226 if (session !== undefined) {
227 if (this.userState !== undefined) {
228 yield this.userState.load(turnContext, false);
229 }
230 if (this.conversationState != undefined) {
231 yield this.conversationState.load(turnContext, false);
232 }
233 var botState = {};
234 if (this.userState !== undefined) {
235 botState.userState = this.userState.get(turnContext);
236 }
237 if (this.conversationState !== undefined) {
238 botState.conversationState = this.conversationState.get(turnContext);
239 }
240 yield this.invokeSend(turnContext, session, TraceActivity.fromState(botState));
241 }
242 });
243 }
244 processOpenCommand(turnContext) {
245 return __awaiter(this, void 0, void 0, function* () {
246 var sessions = yield this.inspectionStateAccessor.get(turnContext, InspectionSessionsByStatus.DefaultValue);
247 var sessionId = this.openCommand(sessions, botbuilder_core_1.TurnContext.getConversationReference(turnContext.activity));
248 yield turnContext.sendActivity(TraceActivity.makeCommandActivity(`${InspectionMiddleware.command} attach ${sessionId}`));
249 yield this.inspectionState.saveChanges(turnContext, false);
250 });
251 }
252 processAttachCommand(turnContext, sessionId) {
253 return __awaiter(this, void 0, void 0, function* () {
254 var sessions = yield this.inspectionStateAccessor.get(turnContext, InspectionSessionsByStatus.DefaultValue);
255 if (this.attachCommand(this.getAttachId(turnContext.activity), sessions, sessionId)) {
256 yield turnContext.sendActivity('Attached to session, all traffic is being replicated for inspection.');
257 }
258 else {
259 yield turnContext.sendActivity(`Open session with id ${sessionId} does not exist.`);
260 }
261 yield this.inspectionState.saveChanges(turnContext, false);
262 });
263 }
264 openCommand(sessions, conversationReference) {
265 function generate_guid() {
266 function s4() {
267 return Math.floor((1 + Math.random()) * 0x10000)
268 .toString(16)
269 .substring(1);
270 }
271 return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
272 s4() + '-' + s4() + s4() + s4();
273 }
274 var sessionId = generate_guid();
275 sessions.openedSessions[sessionId] = conversationReference;
276 return sessionId;
277 }
278 attachCommand(attachId, sessions, sessionId) {
279 var inspectionSessionState = sessions.openedSessions[sessionId];
280 if (inspectionSessionState !== undefined) {
281 sessions.attachedSessions[attachId] = inspectionSessionState;
282 delete sessions.openedSessions[sessionId];
283 return true;
284 }
285 return false;
286 }
287 findSession(turnContext) {
288 return __awaiter(this, void 0, void 0, function* () {
289 var sessions = yield this.inspectionStateAccessor.get(turnContext, InspectionSessionsByStatus.DefaultValue);
290 var conversationReference = sessions.attachedSessions[this.getAttachId(turnContext.activity)];
291 if (conversationReference !== undefined) {
292 return new InspectionSession(conversationReference, this.credentials);
293 }
294 return undefined;
295 });
296 }
297 invokeSend(turnContext, session, activity) {
298 return __awaiter(this, void 0, void 0, function* () {
299 if (yield session.send(activity)) {
300 return true;
301 }
302 else {
303 yield this.cleanUpSession(turnContext);
304 return false;
305 }
306 });
307 }
308 cleanUpSession(turnContext) {
309 return __awaiter(this, void 0, void 0, function* () {
310 var sessions = yield this.inspectionStateAccessor.get(turnContext, InspectionSessionsByStatus.DefaultValue);
311 delete sessions.attachedSessions[this.getAttachId(turnContext.activity)];
312 yield this.inspectionState.saveChanges(turnContext, false);
313 });
314 }
315 getAttachId(activity) {
316 // If we are running in a Microsoft Teams Team the conversation Id will reflect a particular thread the bot is in.
317 // So if we are in a Team then we will associate the "attach" with the Team Id rather than the more restrictive conversation Id.
318 const teamId = teamsActivityHelpers_1.teamsGetTeamId(activity);
319 return teamId ? teamId : activity.conversation.id;
320 }
321}
322InspectionMiddleware.command = "/INSPECT";
323exports.InspectionMiddleware = InspectionMiddleware;
324/** @private */
325class InspectionSession {
326 constructor(conversationReference, credentials) {
327 this.conversationReference = conversationReference;
328 this.connectorClient = new botframework_connector_1.ConnectorClient(credentials, { baseUri: conversationReference.serviceUrl });
329 }
330 send(activity) {
331 return __awaiter(this, void 0, void 0, function* () {
332 botbuilder_core_1.TurnContext.applyConversationReference(activity, this.conversationReference);
333 try {
334 yield this.connectorClient.conversations.sendToConversation(activity.conversation.id, activity);
335 }
336 catch (err) {
337 return false;
338 }
339 return true;
340 });
341 }
342}
343/** @private */
344class InspectionSessionsByStatus {
345 constructor() {
346 this.openedSessions = {};
347 this.attachedSessions = {};
348 }
349}
350InspectionSessionsByStatus.DefaultValue = new InspectionSessionsByStatus();
351/**
352 * InspectionState for use by the InspectionMiddleware for emulator inspection of runtime Activities and BotState.
353 *
354 * @remarks
355 * InspectionState for use by the InspectionMiddleware for emulator inspection of runtime Activities and BotState.
356 *
357 */
358class InspectionState extends botbuilder_core_1.BotState {
359 constructor(storage) {
360 super(storage, (context) => {
361 return Promise.resolve(this.getStorageKey(context));
362 });
363 }
364 getStorageKey(turnContext) {
365 return 'InspectionState';
366 }
367}
368exports.InspectionState = InspectionState;
369//# sourceMappingURL=inspectionMiddleware.js.map
\No newline at end of file