1
- import { ConditionVariable , HashMap , Pair } from "tstl" ;
1
+ import { ConditionVariable , HashMap , HashSet } from "tstl" ;
2
2
3
3
import { Driver } from "../typings/Driver" ;
4
4
import { serializeError } from "../utils/internal/serializeError" ;
5
5
import { Invoke } from "./Invoke" ;
6
+ import { InvokeEvent } from "./InvokeEvent" ;
6
7
7
8
/**
8
9
* The basic communicator.
@@ -44,7 +45,15 @@ export abstract class Communicator<
44
45
/**
45
46
* @hidden
46
47
*/
47
- private promises_ : HashMap < number , Pair < FunctionLike , FunctionLike > > ;
48
+ private promises_ : HashMap < number , IFunctionReservation > ;
49
+
50
+ /**
51
+ * @hidden
52
+ */
53
+ private event_listeners_ : HashMap <
54
+ InvokeEvent . Type ,
55
+ HashSet < ( event : InvokeEvent ) => void >
56
+ > ;
48
57
49
58
/**
50
59
* @hidden
@@ -72,6 +81,50 @@ export abstract class Communicator<
72
81
// OTHER MEMBERS
73
82
this . promises_ = new HashMap ( ) ;
74
83
this . join_cv_ = new ConditionVariable ( ) ;
84
+ this . event_listeners_ = new HashMap ( ) ;
85
+ }
86
+
87
+ /**
88
+ * Add invoke event listener.
89
+ *
90
+ * Add an event listener for the invoke event. The event listener would be called
91
+ * when some invoke event has been occured; sending, receiving, completing, or returning.
92
+ *
93
+ * If you change the requesting parameters or returning value in the event listener,
94
+ * it would affect to the RPC (Remote Procedure Call) communication. Therefore, you have
95
+ * to be careful when modifying the remote function calling.
96
+ *
97
+ * Of course, you can utilize the event listener just for monitoring the RPC events.
98
+ *
99
+ * @param type Type of the event
100
+ * @param listener The listener function to enroll
101
+ */
102
+ public on < Type extends InvokeEvent . Type > (
103
+ type : Type ,
104
+ listener : ( event : InvokeEvent . EventMapper [ Type ] ) => void ,
105
+ ) : void {
106
+ this . event_listeners_
107
+ . take ( type , ( ) => new HashSet ( ) )
108
+ . insert ( listener as ( event : InvokeEvent ) => void ) ;
109
+ }
110
+
111
+ /**
112
+ * Erase invoke event listener.
113
+ *
114
+ * Erase an event listener from the invoke event. The event listener would not be
115
+ * called anymore when the specific invoke event has been occured.
116
+ *
117
+ * @param type Type of the event
118
+ * @param listener The listener function to erase
119
+ */
120
+ public off < Type extends InvokeEvent . Type > (
121
+ type : Type ,
122
+ listener : ( event : InvokeEvent . EventMapper [ Type ] ) => void ,
123
+ ) : void {
124
+ const it = this . event_listeners_ . find ( type ) ;
125
+ if ( it . equals ( this . event_listeners_ . end ( ) ) === false )
126
+ it . second . erase ( listener as ( event : InvokeEvent ) => void ) ;
127
+ if ( it . second . empty ( ) ) this . event_listeners_ . erase ( it ) ;
75
128
}
76
129
77
130
/**
@@ -93,7 +146,7 @@ export abstract class Communicator<
93
146
: new Error ( "Connection has been closed." ) ;
94
147
95
148
for ( const entry of this . promises_ ) {
96
- const reject : FunctionLike = entry . second . second ;
149
+ const reject : FunctionLike = entry . second . reject ;
97
150
reject ( rejectError ) ;
98
151
}
99
152
@@ -116,7 +169,6 @@ export abstract class Communicator<
116
169
*/
117
170
private _Proxy_func ( name : string ) : FunctionLike {
118
171
const func = ( ...params : any [ ] ) => this . _Call_function ( name , ...params ) ;
119
-
120
172
return new Proxy ( func , {
121
173
get : ( { } , newName : string ) => {
122
174
if ( newName === "bind" )
@@ -125,7 +177,6 @@ export abstract class Communicator<
125
177
return ( thisArg : any , ...args : any [ ] ) => func . call ( thisArg , ...args ) ;
126
178
else if ( newName === "apply" )
127
179
return ( thisArg : any , args : any [ ] ) => func . apply ( thisArg , args ) ;
128
-
129
180
return this . _Proxy_func ( `${ name } .${ newName } ` ) ;
130
181
} ,
131
182
} ) ;
@@ -155,8 +206,27 @@ export abstract class Communicator<
155
206
} ) ) ,
156
207
} ;
157
208
209
+ // CALL EVENT LISTENERS
210
+ const eventSetIterator = this . event_listeners_ . find ( "send" ) ;
211
+ if ( eventSetIterator . equals ( this . event_listeners_ . end ( ) ) === false ) {
212
+ const event : InvokeEvent . ISend = {
213
+ type : "send" ,
214
+ time : new Date ( ) ,
215
+ function : invoke ,
216
+ } ;
217
+ for ( const listener of eventSetIterator . second )
218
+ try {
219
+ listener ( event ) ;
220
+ } catch { }
221
+ }
222
+
158
223
// DO SEND WITH PROMISE
159
- this . promises_ . emplace ( invoke . uid , new Pair ( resolve , reject ) ) ;
224
+ this . promises_ . emplace ( invoke . uid , {
225
+ function : invoke ,
226
+ time : new Date ( ) ,
227
+ resolve,
228
+ reject,
229
+ } ) ;
160
230
await this . sendData ( invoke ) ;
161
231
} ) ;
162
232
}
@@ -271,14 +341,15 @@ export abstract class Communicator<
271
341
protected replyData ( invoke : Invoke ) : void {
272
342
if ( ( invoke as Invoke . IFunction ) . listener )
273
343
this . _Handle_function ( invoke as Invoke . IFunction ) . catch ( ( ) => { } ) ;
274
- else this . _Handle_return ( invoke as Invoke . IReturn ) ;
344
+ else this . _Handle_complete ( invoke as Invoke . IReturn ) ;
275
345
}
276
346
277
347
/**
278
348
* @hidden
279
349
*/
280
350
private async _Handle_function ( invoke : Invoke . IFunction ) : Promise < void > {
281
351
const uid : number = invoke . uid ;
352
+ const time : Date = new Date ( ) ;
282
353
283
354
try {
284
355
//----
@@ -323,33 +394,80 @@ export abstract class Communicator<
323
394
}
324
395
func = func . bind ( thisArg ) ;
325
396
397
+ // CALL EVENT LISTENERS
398
+ const eventSetIterator : HashMap . Iterator <
399
+ InvokeEvent . Type ,
400
+ HashSet < ( event : InvokeEvent ) => void >
401
+ > = this . event_listeners_ . find ( "receive" ) ;
402
+ if ( eventSetIterator . equals ( this . event_listeners_ . end ( ) ) === false ) {
403
+ const event : InvokeEvent . IReceive = {
404
+ type : "receive" ,
405
+ time,
406
+ function : invoke ,
407
+ } ;
408
+ for ( const closure of eventSetIterator . second )
409
+ try {
410
+ closure ( event ) ;
411
+ } catch { }
412
+ }
413
+
326
414
//----
327
415
// RETURN VALUE
328
416
//----
329
417
// CALL FUNCTION
330
418
const parameters : any [ ] = invoke . parameters . map ( ( p ) => p . value ) ;
331
- const ret : any = await func ( ...parameters ) ;
332
-
333
- await this . _Send_return ( uid , true , ret ) ;
419
+ const result : any = await func ( ...parameters ) ;
420
+ await this . _Send_return ( {
421
+ invoke,
422
+ time,
423
+ return : {
424
+ uid,
425
+ success : true ,
426
+ value : result ,
427
+ } ,
428
+ } ) ;
334
429
} catch ( exp ) {
335
- await this . _Send_return ( uid , false , exp ) ;
430
+ await this . _Send_return ( {
431
+ invoke,
432
+ time,
433
+ return : {
434
+ uid,
435
+ success : false ,
436
+ value : exp ,
437
+ } ,
438
+ } ) ;
336
439
}
337
440
}
338
441
339
442
/**
340
443
* @hidden
341
444
*/
342
- private _Handle_return ( invoke : Invoke . IReturn ) : void {
343
- // GET THE PROMISE OBJECT
445
+ private _Handle_complete ( invoke : Invoke . IReturn ) : void {
446
+ // FIND TARGET FUNCTION CALL
344
447
const it = this . promises_ . find ( invoke . uid ) ;
345
448
if ( it . equals ( this . promises_ . end ( ) ) ) return ;
346
449
450
+ // CALL EVENT LISTENERS
451
+ const eventSetIterator = this . event_listeners_ . find ( "complete" ) ;
452
+ if ( eventSetIterator . equals ( this . event_listeners_ . end ( ) ) === false ) {
453
+ const event : InvokeEvent . IComplete = {
454
+ type : "complete" ,
455
+ function : it . second . function ,
456
+ return : invoke ,
457
+ requested_at : it . second . time ,
458
+ completed_at : new Date ( ) ,
459
+ } ;
460
+ for ( const closure of eventSetIterator . second )
461
+ try {
462
+ closure ( event ) ;
463
+ } catch { }
464
+ }
465
+
347
466
// RETURNS
348
467
const func : FunctionLike = invoke . success
349
- ? it . second . first
350
- : it . second . second ;
468
+ ? it . second . resolve
469
+ : it . second . reject ;
351
470
this . promises_ . erase ( it ) ;
352
-
353
471
func ( invoke . value ) ;
354
472
}
355
473
@@ -366,23 +484,39 @@ export abstract class Communicator<
366
484
/**
367
485
* @hidden
368
486
*/
369
- private async _Send_return (
370
- uid : number ,
371
- success : boolean ,
372
- value : any ,
373
- ) : Promise < void > {
487
+ private async _Send_return ( props : {
488
+ invoke : Invoke . IFunction ;
489
+ return : Invoke . IReturn ;
490
+ time : Date ;
491
+ } ) : Promise < void > {
492
+ const eventSet = this . event_listeners_ . find ( "return" ) ;
493
+ if ( eventSet . equals ( this . event_listeners_ . end ( ) ) === false ) {
494
+ const event : InvokeEvent . IReturn = {
495
+ type : "return" ,
496
+ function : props . invoke ,
497
+ return : props . return ,
498
+ requested_at : props . time ,
499
+ completed_at : new Date ( ) ,
500
+ } ;
501
+ for ( const closure of eventSet . second )
502
+ try {
503
+ closure ( event ) ;
504
+ } catch { }
505
+ }
506
+
374
507
// SPECIAL LOGIC FOR ERROR -> FOR CLEAR JSON ENCODING
375
- if ( success === false && value instanceof Error )
376
- value = serializeError ( value ) ;
508
+ if ( props . return . success === false && props . return . value instanceof Error )
509
+ props . return . value = serializeError ( props . return . value ) ;
377
510
378
511
// RETURNS
379
- const ret : Invoke . IReturn = {
380
- uid,
381
- success,
382
- value,
383
- } ;
384
- await this . sendData ( ret ) ;
512
+ await this . sendData ( props . return ) ;
385
513
}
386
514
}
387
515
388
516
type FunctionLike = ( ...args : any [ ] ) => any ;
517
+ interface IFunctionReservation {
518
+ function : Invoke . IFunction ;
519
+ time : Date ;
520
+ resolve : FunctionLike ;
521
+ reject : FunctionLike ;
522
+ }
0 commit comments