botbuilder-core
Version:
Core components for Microsoft Bot Builder. Components in this library can run either in a browser or on the server.
139 lines (129 loc) • 4.67 kB
text/typescript
/**
* @module botbuilder
*/
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { TurnContext } from './turnContext';
/**
* Interface implemented by object based middleware.
*/
export interface Middleware {
/**
* Called each time the bot receives a new request.
*
* @remarks
* Calling `await next();` will cause execution to continue to either the next piece of
* middleware in the chain or the bots main logic if you are the last piece of middleware.
*
* Your middleware should perform its business logic before and/or after the call to `next()`.
* You can short-circuit further execution of the turn by omitting the call to `next()`.
*
* The following example shows a simple piece of logging middleware:
*
* ```JavaScript
* class MyLogger {
* async onTurn(context, next) {
* console.log(`Leading Edge`);
* await next();
* console.log(`Trailing Edge`);
* }
* }
* ```
* @param context Context for current turn of conversation with the user.
* @param next Function to call to continue execution to the next step in the middleware chain.
*/
onTurn(context: TurnContext, next: () => Promise<void>): Promise<void>;
}
/**
* Signature implemented by function based middleware.
*
* ```TypeScript
* type MiddlewareHandler = (context: TurnContext, next: () => Promise<void>) => Promise<void>;
* ```
*/
export type MiddlewareHandler = (context: TurnContext, next: () => Promise<void>) => Promise<void>;
/**
* A set of `Middleware` plugins.
*
* @remarks
* The set itself is middleware so you can easily package up a set of middleware that can be composed
* into an adapter with a single `adapter.use(mySet)` call or even into another middleware set using
* `set.use(mySet)`.
*
* ```JavaScript
* const { MiddlewareSet } = require('botbuilder');
*
* const set = new MiddlewareSet();
* set.use(async (context, next) => {
* console.log(`Leading Edge`);
* await next();
* console.log(`Trailing Edge`);
* });
* ```
*/
export class MiddlewareSet implements Middleware {
private middleware: MiddlewareHandler[] = [];
/**
* Creates a new MiddlewareSet instance.
*
* @param {...any} middlewares One or more middleware handlers(s) to register.
*/
constructor(...middlewares: (MiddlewareHandler | Middleware)[]) {
this.use(...middlewares);
}
/**
* Processes an incoming activity.
*
* @param context [TurnContext](xref:botbuilder-core.TurnContext) object for this turn.
* @param next Delegate to call to continue the bot middleware pipeline.
* @returns {Promise<void>} A Promise representing the async operation.
*/
onTurn(context: TurnContext, next: () => Promise<void>): Promise<void> {
return this.run(context, next);
}
/**
* Registers middleware handlers(s) with the set.
*
* @remarks This example adds a new piece of middleware to a set:
* ```JavaScript
* set.use(async (context, next) => {
* console.log(`Leading Edge`);
* await next();
* console.log(`Trailing Edge`);
* });
* ```
* @param {...any} middlewares One or more middleware handlers(s) to register.
* @returns The updated middleware set.
*/
use(...middlewares: (MiddlewareHandler | Middleware)[]): this {
middlewares.forEach((plugin) => {
if (typeof plugin === 'function') {
this.middleware.push(plugin);
} else if (typeof plugin === 'object' && plugin.onTurn) {
this.middleware.push((context, next) => plugin.onTurn(context, next));
} else {
throw new Error('MiddlewareSet.use(): invalid plugin type being added.');
}
});
return this;
}
/**
* Executes a set of middleware in series.
*
* @param context Context for the current turn of conversation with the user.
* @param next Function to invoke at the end of the middleware chain.
* @returns A promise that resolves after the handler chain is complete.
*/
run(context: TurnContext, next: () => Promise<void>): Promise<void> {
const runHandlers = ([handler, ...remaining]: MiddlewareHandler[]) => {
try {
return Promise.resolve(handler ? handler(context, () => runHandlers(remaining)) : next());
} catch (err) {
return Promise.reject(err);
}
};
return runHandlers(this.middleware);
}
}