UNPKG

md5-fight-plus

Version:

136 lines (132 loc) 4.08 kB
import { BailEvent } from "@/events/BailEvent"; import _ from "lodash"; type TapOptions = { name?: string; lives?: number; //生命次数,若<=0,则会自动移除tap,若lives不存在则视为无限执行次数的tap stage?: number; //优先级,越小优先级越高 范围0~99 }; type SyncBailHookOptions<T> = { beforeAction?: (params?: T) => any; afterAction?: (params?: T) => any; }; type LastCallback = (params: any) => any; export let ids = -1; export let hooksRecord = []; export class SyncBailHook<T> { bailedResult: any; cbs: { options: TapOptions; func: (params: T) => any; id: number }[]; options: SyncBailHookOptions<T>; error: any; afterActionHook: SyncBailHook<T>; beforeActionHook: SyncBailHook<T>; lastCallback: LastCallback; constructor(options: SyncBailHookOptions<T> = {}) { this.bailedResult = undefined; this.cbs = []; this.options = options; this.error = undefined; this.lastCallback = (params) => params; if (this.options.afterAction) { this.registerAfterActionHook( "register options afterAction", this.options.afterAction ); } if (this.options.beforeAction) { this.registerBeforeActionHook( "register options beforeAction", this.options.beforeAction ); } } tap(options: string | TapOptions, callback: (params: T) => T | BailEvent) { const optionsFormatted = formatTapOptions(options); this.cbs.push({ options: optionsFormatted, func: callback, id: ids++, }); this.cbs.sort((cb1, cb2) => cb1.options.stage - cb2.options.stage); return ids - 1; } call(params?: T) { this.bailedResult = params; try { for (let i = 0; i < this.cbs.length; i++) { const currentTap = this.cbs[i]; if (this.beforeActionHook) { this.bailedResult = this.beforeActionHook.call(this.bailedResult); //如果返回值是BailEvent,则会直接熔断。 if (this.bailedResult instanceof BailEvent) break; } this.bailedResult = currentTap.func(this.bailedResult); if ( _.isNumber(currentTap.options.lives) && --currentTap.options.lives <= 0 ) { //减少生命计数,若计数值<0则移除taps this.removeTap(currentTap.id); i--; } hooksRecord.push(currentTap.options.name); //如果返回值是BailEvent,则会直接熔断。 if (this.bailedResult instanceof BailEvent) break; //拦截器 if (this.afterActionHook) { this.bailedResult = this.afterActionHook.call(this.bailedResult); //如果返回值是BailEvent,则会直接熔断。 if (this.bailedResult instanceof BailEvent) break; } } } catch (err) { this.error = err; } finally { if (this.error) throw this.error; return this.lastCallback(this.bailedResult); } } registerLastCallback(cb: LastCallback) { this.lastCallback = cb; } registerAfterActionHook( info: string = "register afterActionFn", cb: (params?: T) => any ) { if (!this.afterActionHook) { this.afterActionHook = new SyncBailHook<T | undefined>(); } this.afterActionHook.tap(info, (params) => cb(params)); } registerBeforeActionHook( info: string = "register afterActionFn", cb: (params?: T) => any ) { if (!this.beforeActionHook) { this.beforeActionHook = new SyncBailHook<T | undefined>(); } this.beforeActionHook.tap(info, (params) => cb(params)); } removeTap(id) { for (let i = 0; i < this.cbs.length; i++) { const cb = this.cbs[i]; if (cb.id === id) { return this.cbs.splice(i, 1); } } return false; } } function formatTapOptions(options: string | TapOptions) { const rawOptions: TapOptions = { name: "", stage: 50, }; if (_.isString(options)) { rawOptions.name = options; return rawOptions; } for (const key in options) { rawOptions[key] = options[key]; } return rawOptions; }