1
1
// Copyright (c) .NET Foundation. All rights reserved.
2
2
// Licensed under the MIT License.
3
3
4
- import { Context } from '@azure/functions' ;
4
+ import { HookCallback } from '@azure/functions-worker ' ;
5
5
import { AzureFunctionsRpcMessages as rpc } from '../azure-functions-language-worker-protobuf/src/rpc' ;
6
+ import { Disposable } from './Disposable' ;
6
7
import { IFunctionLoader } from './FunctionLoader' ;
7
8
import { IEventStream } from './GrpcClient' ;
8
-
9
- type InvocationRequestBefore = ( context : Context , userFn : Function ) => Function ;
10
- type InvocationRequestAfter = ( context : Context ) => void ;
9
+ import Module = require( 'module' ) ;
11
10
12
11
export class WorkerChannel {
13
12
public eventStream : IEventStream ;
14
13
public functionLoader : IFunctionLoader ;
15
- private _invocationRequestBefore : InvocationRequestBefore [ ] ;
16
- private _invocationRequestAfter : InvocationRequestAfter [ ] ;
14
+ private _preInvocationHooks : HookCallback [ ] = [ ] ;
15
+ private _postInvocationHooks : HookCallback [ ] = [ ] ;
17
16
18
17
constructor ( eventStream : IEventStream , functionLoader : IFunctionLoader ) {
19
18
this . eventStream = eventStream ;
20
19
this . functionLoader = functionLoader ;
21
- this . _invocationRequestBefore = [ ] ;
22
- this . _invocationRequestAfter = [ ] ;
20
+ this . initWorkerModule ( this ) ;
23
21
}
24
22
25
23
/**
@@ -33,32 +31,49 @@ export class WorkerChannel {
33
31
} ) ;
34
32
}
35
33
36
- /**
37
- * Register a patching function to be run before User Function is executed.
38
- * Hook should return a patched version of User Function.
39
- */
40
- public registerBeforeInvocationRequest ( beforeCb : InvocationRequestBefore ) : void {
41
- this . _invocationRequestBefore . push ( beforeCb ) ;
34
+ public registerHook ( hookName : string , callback : HookCallback ) : Disposable {
35
+ const hooks = this . getHooks ( hookName ) ;
36
+ hooks . push ( callback ) ;
37
+ return new Disposable ( ( ) => {
38
+ const index = hooks . indexOf ( callback ) ;
39
+ if ( index > - 1 ) {
40
+ hooks . splice ( index , 1 ) ;
41
+ }
42
+ } ) ;
42
43
}
43
44
44
- /**
45
- * Register a function to be run after User Function resolves.
46
- */
47
- public registerAfterInvocationRequest ( afterCb : InvocationRequestAfter ) : void {
48
- this . _invocationRequestAfter . push ( afterCb ) ;
45
+ public async executeHooks ( hookName : string , context : { } ) : Promise < void > {
46
+ const callbacks = this . getHooks ( hookName ) ;
47
+ for ( const callback of callbacks ) {
48
+ await callback ( context ) ;
49
+ }
49
50
}
50
51
51
- public runInvocationRequestBefore ( context : Context , userFunction : Function ) : Function {
52
- let wrappedFunction = userFunction ;
53
- for ( const before of this . _invocationRequestBefore ) {
54
- wrappedFunction = before ( context , wrappedFunction ) ;
52
+ private getHooks ( hookName : string ) : HookCallback [ ] {
53
+ switch ( hookName ) {
54
+ case 'preInvocation' :
55
+ return this . _preInvocationHooks ;
56
+ case 'postInvocation' :
57
+ return this . _postInvocationHooks ;
58
+ default :
59
+ throw new RangeError ( `Unrecognized hook "${ hookName } "` ) ;
55
60
}
56
- return wrappedFunction ;
57
61
}
58
62
59
- public runInvocationRequestAfter ( context : Context ) {
60
- for ( const after of this . _invocationRequestAfter ) {
61
- after ( context ) ;
62
- }
63
+ private initWorkerModule ( channel : WorkerChannel ) {
64
+ const workerApi = {
65
+ registerHook : ( hookName : string , callback : HookCallback ) => channel . registerHook ( hookName , callback ) ,
66
+ Disposable,
67
+ } ;
68
+
69
+ Module . prototype . require = new Proxy ( Module . prototype . require , {
70
+ apply ( target , thisArg , argArray ) {
71
+ if ( argArray [ 0 ] === '@azure/functions-worker' ) {
72
+ return workerApi ;
73
+ } else {
74
+ return Reflect . apply ( target , thisArg , argArray ) ;
75
+ }
76
+ } ,
77
+ } ) ;
63
78
}
64
79
}
0 commit comments