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