11import { AccessLevel , Inject , SingletonProto } from '@eggjs/core-decorator' ;
2- import { EventBus , Events , EventWaiter , EventName } from '@eggjs/eventbus-decorator' ;
2+ import { EventBus , Events , EventWaiter , EventName , CORK_ID } from '@eggjs/eventbus-decorator' ;
33import { EggContext } from '@eggjs/tegg-runtime' ;
44import type { EggLogger } from 'egg' ;
55import { EventContextFactory } from './EventContextFactory' ;
@@ -9,10 +9,21 @@ import awaitEvent from 'await-event';
99import awaitFirst from 'await-first' ;
1010
1111// from typed-emitter
12- type Arguments < T > = [ T ] extends [ ( ...args : infer U ) => any ]
12+ type Array < T > = [ T ] extends [ ( ...args : infer U ) => any ]
1313 ? U
1414 : [ T ] extends [ void ] ? [ ] : [ T ] ;
1515
16+ export interface Event {
17+ name : EventName ;
18+ args : Array < any > ;
19+ context ?: EggContext ;
20+ }
21+
22+ export interface CorkEvents {
23+ times : number ;
24+ events : Array < Event > ;
25+ }
26+
1627@SingletonProto ( {
1728 // TODO 需要考虑支持别名
1829 // SingletonEventBus 同时实现了两个接口
@@ -31,6 +42,10 @@ export class SingletonEventBus implements EventBus, EventWaiter {
3142 @Inject ( )
3243 private readonly logger : EggLogger ;
3344
45+ private corkIdSequence = 0 ;
46+
47+ private readonly corkedEvents = new Map < string /* corkId */ , CorkEvents > ( ) ;
48+
3449 /**
3550 * only use for ensure event will happen
3651 */
@@ -39,38 +54,88 @@ export class SingletonEventBus implements EventBus, EventWaiter {
3954 return this ;
4055 }
4156
42- async await < E extends keyof Events > ( event : E ) : Promise < Arguments < Events [ E ] > > {
57+ async await < E extends keyof Events > ( event : E ) : Promise < Array < Events [ E ] > > {
4358 return awaitEvent ( this . emitter , event ) ;
4459 }
4560
46- awaitFirst < E extends keyof Events > ( ...e : Array < E > ) : Promise < { event : EventName , args : Arguments < Events [ E ] > } > {
61+ awaitFirst < E extends keyof Events > ( ...e : Array < E > ) : Promise < { event : EventName , args : Array < Events [ E ] > } > {
4762 return awaitFirst ( this . emitter , e ) ;
4863 }
4964
50- emit < E extends keyof Events > ( event : E , ...args : Arguments < Events [ E ] > ) : boolean {
65+ emit < E extends keyof Events > ( event : E , ...args : Array < Events [ E ] > ) : boolean {
5166 const ctx = this . eventContextFactory . createContext ( ) ;
5267 const hasListener = this . eventHandlerFactory . hasListeners ( event ) ;
5368 this . doEmit ( ctx , event , args ) ;
5469 return hasListener ;
5570 }
5671
57- emitWithContext < E extends keyof Events > ( parentContext : EggContext , event : E , args : Arguments < Events [ E ] > ) : boolean {
58- const ctx = this . eventContextFactory . createContext ( parentContext ) ;
72+ generateCorkId ( ) : string {
73+ return String ( ++ this . corkIdSequence ) ;
74+ }
75+
76+ cork ( corkId : string ) {
77+ let corkEvents = this . corkedEvents . get ( corkId ) ;
78+ if ( ! corkEvents ) {
79+ corkEvents = {
80+ times : 0 ,
81+ events : [ ] ,
82+ } as unknown as CorkEvents ;
83+ this . corkedEvents . set ( corkId , corkEvents ) ;
84+ }
85+ corkEvents ! . times ++ ;
86+ }
87+
88+ uncork ( corkId : string ) {
89+ const corkEvents = this . corkedEvents . get ( corkId ) ;
90+ if ( ! corkEvents ) {
91+ throw new Error ( `eventbus corkId ${ corkId } not found` ) ;
92+ }
93+ if ( -- corkEvents . times !== 0 ) {
94+ return ;
95+ }
96+ this . corkedEvents . delete ( corkId ) ;
97+ for ( const event of corkEvents . events ) {
98+ if ( event . context ) {
99+ this . doEmitWithContext ( event . context , event . name , event . args ) ;
100+ }
101+ }
102+ }
103+
104+ queueEvent ( corkId : string , event : Event ) {
105+ const corkdEvents = this . corkedEvents . get ( corkId ) ;
106+ if ( ! corkdEvents ) {
107+ throw new Error ( `eventbus corkId ${ corkId } not found` ) ;
108+ }
109+ corkdEvents . events . push ( event ) ;
110+ }
111+
112+ emitWithContext < E extends keyof Events > ( parentContext : EggContext , event : E , args : Array < Events [ E ] > ) : boolean {
113+ const corkId = parentContext . get ( CORK_ID ) ;
114+ const hasListener = this . eventHandlerFactory . hasListeners ( event ) ;
115+ if ( corkId ) {
116+ this . queueEvent ( corkId , { name : event , args, context : parentContext } ) ;
117+ return hasListener ;
118+ }
119+ return this . doEmitWithContext ( parentContext , event , args ) ;
120+ }
121+
122+ private doEmitWithContext ( parentContext : EggContext , event : EventName , args : Array < any > ) : boolean {
59123 const hasListener = this . eventHandlerFactory . hasListeners ( event ) ;
124+ const ctx = this . eventContextFactory . createContext ( parentContext ) ;
60125 this . doEmit ( ctx , event , args ) ;
61126 return hasListener ;
62127 }
63128
64- doOnceEmit < E extends keyof Events > ( event : E , args : Arguments < Events [ E ] > ) {
129+ private doOnceEmit ( event : EventName , args : Array < any > ) {
65130 try {
66131 this . emitter . emit ( event , ...args ) ;
67132 } catch ( e ) {
68- e . message = `[EventBus] process once event ${ event } failed: ${ e . message } ` ;
133+ e . message = `[EventBus] process once event ${ String ( event ) } failed: ${ e . message } ` ;
69134 this . logger . error ( e ) ;
70135 }
71136 }
72137
73- async doEmit < E extends keyof Events > ( ctx : EggContext , event : E , args : Arguments < Events [ E ] > ) {
138+ private async doEmit ( ctx : EggContext , event : EventName , args : Array < any > ) {
74139 const lifecycle = { } ;
75140 if ( ctx . init ) {
76141 await ctx . init ( lifecycle ) ;
@@ -82,12 +147,12 @@ export class SingletonEventBus implements EventBus, EventWaiter {
82147 await Reflect . apply ( handler . handle , handler , args ) ;
83148 } catch ( e ) {
84149 // should wait all handlers done then destroy ctx
85- e . message = `[EventBus] process event ${ event } failed: ${ e . message } ` ;
150+ e . message = `[EventBus] process event ${ String ( event ) } failed: ${ e . message } ` ;
86151 this . logger . error ( e ) ;
87152 }
88153 } ) ) ;
89154 } catch ( e ) {
90- e . message = `[EventBus] process event ${ event } failed: ${ e . message } ` ;
155+ e . message = `[EventBus] process event ${ String ( event ) } failed: ${ e . message } ` ;
91156 this . logger . error ( e ) ;
92157 } finally {
93158 if ( ctx . destroy ) {
0 commit comments