... | ... | @@ -65,6 +65,8 @@ Opened question is how to exchange data between hooks registered on the same cal |
|
|
|
|
|
We probably need to implement something similar to the `LibraryManager` from Kea to manage the hooks. We also need the `HooksManager` to register and call the hook callouts.
|
|
|
|
|
|
### Technical details
|
|
|
|
|
|
```mermaid
|
|
|
classDiagram
|
|
|
class IHook{
|
... | ... | @@ -80,18 +82,19 @@ classDiagram |
|
|
+ error Foo(int x)
|
|
|
}
|
|
|
|
|
|
class MyHook{
|
|
|
class FooHook{
|
|
|
+ FooCallout Callouts
|
|
|
+ string Version()
|
|
|
+ error Load()
|
|
|
+ error Unload()
|
|
|
}
|
|
|
|
|
|
IHook <|.. MyHook
|
|
|
MyHook o.. FooCallout
|
|
|
IHook <|.. FooHook
|
|
|
FooHook ..> FooCallout
|
|
|
|
|
|
HookModule *-- FooCallout
|
|
|
HookModule *-- IHook
|
|
|
HookModule : +CurrentVersion
|
|
|
|
|
|
class LibraryManager{
|
|
|
+ LM+error New(string path)$
|
... | ... | @@ -116,6 +119,69 @@ classDiagram |
|
|
+ UnloadAll()
|
|
|
}
|
|
|
|
|
|
HookLoader o-- LibraryManager
|
|
|
HookLoader ..> LibraryManager
|
|
|
HookLoader *-- HookManager
|
|
|
```
|
|
|
|
|
|
The hook module will contain three elements:
|
|
|
|
|
|
- Stork version
|
|
|
- Hook interface
|
|
|
- Callout types
|
|
|
|
|
|
The Stork version is forwarded from the `version.go` file and is used to check the compatibility between the core and hook. Hook interface is a Go interface that contains the definitions of primary functions (`load`, `unload`, `version`) and `callouts` object. The `callouts` object implements a variety set of callouts functions. The hook module defines the callouts as Go interfaces. The hook's author can use the interface checking technique to ensure that the callout signatures are correct.
|
|
|
|
|
|
On the top level, the hooks are managed by the hook loader. It is responsible for searching for the hook libraries, creating the library manager instances, and calling them. The loader works on the server's startup for loading all possible hooks and on the graceful shutdown to unload them. It should skip and log the libraries that report incompatible versions.
|
|
|
|
|
|
The library manager is a wrapper around the plugin module. It is responsible for retrieving and calling the primary functions and the callouts object. It can have a short lifetime because each Go plugin is opened only once and never closed. The library manager functions are called by the hook loader. The hook loader passes the callouts object to the hook manager.
|
|
|
|
|
|
The hook manager is a facade for all hooks. It implements all hook callouts. The server's function that needs to pass data to the hooks doesn't need to check if a specific hook is registered or not. They just call the hook manager methods. After loading a hook, the callout object is passed to the manager. The manager enumerates all callout types and checks if a given callout object implements them. If yes, it registers a given callout object as a hook handler. The hook manager's callout implementations redirect the calls to a specific handler or handlers or do nothing if no handler was registered.
|
|
|
|
|
|
The hook's author needs to prepare a structure that implements a set of chosen callouts. The interface checks should be used to ensure that the function signatures are valid. The hook must export the `Callouts` variable with an instance of this structure. The instance may be created in the `Load` function and destroyed in the `Unload` function. Additionally, the hook requires the `Version` function to be provided.
|
|
|
|
|
|
The hook loader searches for hook libraries in a specific directory. Users can provide a path by a flag or environment variable or use a default value.
|
|
|
|
|
|
### Object-oriented hook
|
|
|
|
|
|
It is a modification of the above design. The hook provides only two functions:
|
|
|
|
|
|
- Version()
|
|
|
- Load()
|
|
|
|
|
|
The `Version` is the same. It returns the version used to check the compatibility.
|
|
|
The `Load` function now returns the `Callouts` object and error. If something goes wrong with loading a hook, then the error is not `nil`. As previously, the `Callouts` object provides the implementations of the hook handlers. Additionally, it implements the `io.Closer` interface. The `Close` function has the same role as an `Unload` function in the previous design.
|
|
|
|
|
|
```mermaid
|
|
|
classDiagram
|
|
|
class IHook{
|
|
|
<<interface>>
|
|
|
+ string Version()
|
|
|
+ Callouts, error Load()
|
|
|
}
|
|
|
|
|
|
class Callouts{
|
|
|
<<interface>>
|
|
|
}
|
|
|
|
|
|
class ioCloser{
|
|
|
<<interface>>
|
|
|
}
|
|
|
|
|
|
ioCloser <|-- Callouts
|
|
|
IHook ..> Callouts
|
|
|
|
|
|
class FooCallout{
|
|
|
<<interface>>
|
|
|
+ error Foo(int x)
|
|
|
+ error Close()
|
|
|
}
|
|
|
|
|
|
class FooHook{
|
|
|
+ string Version()
|
|
|
+ FooCallout, error Load()
|
|
|
}
|
|
|
|
|
|
IHook <|.. FooHook
|
|
|
FooHook ..> FooCallout
|
|
|
Callouts <|.. FooCallout
|
|
|
``` |