2023-04-23 23:05:30 +08:00
|
|
|
import { assert } from '../helpers/error';
|
|
|
|
import { combineURL } from '../helpers/combineURL';
|
2023-04-25 11:54:10 +08:00
|
|
|
import { isFunction, isString } from '../helpers/isTypes';
|
2023-04-23 23:05:30 +08:00
|
|
|
|
|
|
|
export interface MiddlewareNext {
|
|
|
|
(): Promise<void>;
|
|
|
|
}
|
|
|
|
|
2023-04-25 14:28:28 +08:00
|
|
|
export interface MiddlewareCallback<Context extends AnyObject> {
|
|
|
|
(ctx: Context, next: MiddlewareNext): Promise<void>;
|
2023-04-23 23:05:30 +08:00
|
|
|
}
|
|
|
|
|
2023-04-25 14:28:28 +08:00
|
|
|
export interface MiddlewareUse<Context extends AnyObject> {
|
|
|
|
/**
|
|
|
|
* 添加中间件
|
|
|
|
*
|
|
|
|
* @param path 中间件路径
|
|
|
|
* @param callback 中间件回调
|
|
|
|
*/
|
|
|
|
(
|
|
|
|
path: string,
|
|
|
|
callback: MiddlewareCallback<Context>,
|
|
|
|
): MiddlewareManager<Context>;
|
|
|
|
/**
|
|
|
|
* 添加中间件
|
|
|
|
*
|
|
|
|
* @param callback 中间件回调
|
|
|
|
*/
|
|
|
|
(callback: MiddlewareCallback<Context>): MiddlewareManager<Context>;
|
2023-04-23 23:05:30 +08:00
|
|
|
}
|
|
|
|
|
2023-04-25 14:28:28 +08:00
|
|
|
export default class MiddlewareManager<Context extends AnyObject = AnyObject> {
|
|
|
|
#map = new Map<string, MiddlewareCallback<Context>[]>();
|
2023-04-25 11:54:10 +08:00
|
|
|
|
2023-04-25 14:28:28 +08:00
|
|
|
/**
|
|
|
|
* 添加中间件
|
|
|
|
*/
|
|
|
|
use: MiddlewareUse<Context> = (
|
|
|
|
path: string | MiddlewareCallback<Context>,
|
|
|
|
callback?: MiddlewareCallback<Context>,
|
|
|
|
) => {
|
2023-04-23 23:05:30 +08:00
|
|
|
if (isFunction(path)) {
|
|
|
|
callback = path;
|
|
|
|
path = '/';
|
|
|
|
}
|
2023-04-25 11:54:10 +08:00
|
|
|
assert(isString(path), 'path 不是一个 string');
|
|
|
|
assert(!!path, 'path 不是一个长度大于零的 string');
|
|
|
|
assert(isFunction(callback), 'callback 不是一个 function');
|
2023-04-23 23:05:30 +08:00
|
|
|
|
|
|
|
const middlewares = this.#map.get(path) ?? [];
|
|
|
|
middlewares.push(callback!);
|
|
|
|
this.#map.set(path, middlewares);
|
|
|
|
|
|
|
|
return this;
|
2023-04-25 14:28:28 +08:00
|
|
|
};
|
2023-04-23 23:05:30 +08:00
|
|
|
|
2023-04-25 14:28:28 +08:00
|
|
|
flush(ctx: Context, finish: MiddlewareNext) {
|
|
|
|
const allMiddlewares: MiddlewareCallback<Context>[] = [];
|
2023-04-23 23:05:30 +08:00
|
|
|
|
2023-04-25 14:28:28 +08:00
|
|
|
for (const [path, middlewares] of this.#map.entries()) {
|
|
|
|
const url = combineURL(ctx.req.baseURL, path);
|
|
|
|
const checkRE = new RegExp(`^${url}([/?].*)?`);
|
2023-04-23 23:05:30 +08:00
|
|
|
|
2023-04-25 14:28:28 +08:00
|
|
|
if (path === '/') {
|
|
|
|
allMiddlewares.push(...middlewares);
|
|
|
|
} else if (checkRE.test(ctx.req.url!)) {
|
|
|
|
allMiddlewares.push(...middlewares);
|
2023-04-23 23:05:30 +08:00
|
|
|
}
|
2023-04-25 14:28:28 +08:00
|
|
|
}
|
2023-04-23 23:05:30 +08:00
|
|
|
|
2023-04-25 14:28:28 +08:00
|
|
|
const tasks = [...allMiddlewares, finish];
|
|
|
|
return (function next(): Promise<void> {
|
|
|
|
return tasks.shift()!(ctx, next);
|
|
|
|
})();
|
2023-04-23 23:05:30 +08:00
|
|
|
}
|
|
|
|
}
|