... | @@ -53,15 +53,13 @@ The plugin object provides a single `Lookup` function. It accepts a string ident |
... | @@ -53,15 +53,13 @@ The plugin object provides a single `Lookup` function. It accepts a string ident |
|
|
|
|
|
It is possible to implement the Kea hook structure in Go. We can search for `load`, `unload`, and `version` functions (`multi_threading_compatible` is not necessary) or any callout. Callouts can have the same signature as in Kea.
|
|
It is possible to implement the Kea hook structure in Go. We can search for `load`, `unload`, and `version` functions (`multi_threading_compatible` is not necessary) or any callout. Callouts can have the same signature as in Kea.
|
|
|
|
|
|
I think that we can use the same primary functions. Stork should search for plugins in a specific directory (it should be the same for all plugins) and load them on startup calling the `load` function if provided. During gracefully stopping the server, we can call the `unload` function too. The `version` function will be used to check the compatibility between a core and a plugin.
|
|
I think that we can slightly modify the primary functions set. Stork should search for plugins in a specific directory (it should be the same for all plugins) and load them on startup by calling the mandatory `Load` function. This function's responsibility will be to create an object with callout points. This object may optionally implement the `Close` method (as in `io.Closer` interface) that will be called during gracefully stopping the server. The plugin needs to provide the `version` function too. It will return the program name (one for server and another for agent) and version string that will be used to check the compatibility between a core and a plugin.
|
|
|
|
|
|
We also need the hook module that will be shared between the core and hooks.
|
|
However, we should redesign the callout signature. It should be strongly typed but not strongly related to the core codebase. The function shouldn't accept the `CalloutHandle` object and lookup in runtime for specific arguments. It should just take all needed arguments. The expected signature can be defined as an interface in the hook module and used with an interface check in the hook implementation.
|
|
|
|
|
|
However, we should redesign the callout signature. It should be strongly typed but not strongly related to the core codebase. The function shouldn't accept the `CalloutHandle` object and lookup in runtime for specific arguments. It should just take all needed arguments. The expected signature can be defined as a type in the hook module and used with an interface check in the hook implementation.
|
|
|
|
|
|
|
|
In the Kea layout, the hook is a set of callout functions. It means that we need to search each callout by name. We must share between the core and hook the type (function signature) and the identifier (function name). In Go, the hook can provide an object that will be tested for implementing expected hook interfaces. We don't need to use any identifiers.
|
|
In the Kea layout, the hook is a set of callout functions. It means that we need to search each callout by name. We must share between the core and hook the type (function signature) and the identifier (function name). In Go, the hook can provide an object that will be tested for implementing expected hook interfaces. We don't need to use any identifiers.
|
|
|
|
|
|
Opened question is how to exchange data between hooks registered on the same callout. I think that the specific solution depends on the hook.
|
|
Opened question is how to exchange data between hooks registered on the same callout. I think that the specific solution depends on the specific hook.
|
|
|
|
|
|
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.
|
|
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.
|
|
|
|
|
... | @@ -71,56 +69,115 @@ We probably need to implement something similar to the `LibraryManager` from Kea |
... | @@ -71,56 +69,115 @@ We probably need to implement something similar to the `LibraryManager` from Kea |
|
classDiagram
|
|
classDiagram
|
|
class IHook{
|
|
class IHook{
|
|
<<interface>>
|
|
<<interface>>
|
|
+ string Version()
|
|
+ string, string Version()
|
|
+ error Load()
|
|
+ any, error Load()
|
|
+ error Unload()
|
|
|
|
+ interface Callouts
|
|
|
|
}
|
|
}
|
|
|
|
|
|
class FooCallout{
|
|
class FooCallout {
|
|
<<interface>>
|
|
<<interface>>
|
|
+ error Foo(int x)
|
|
+ error Foo(int x)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
class BarCallout {
|
|
|
|
<<interface>>
|
|
|
|
+ error Bar(bool x)
|
|
|
|
}
|
|
|
|
|
|
|
|
class BazCallout {
|
|
|
|
<<interface>>
|
|
|
|
+ int Baz(string x)
|
|
|
|
}
|
|
|
|
|
|
class FooHook{
|
|
class FooHook{
|
|
+ FooCallout Callouts
|
|
<<plugin>>
|
|
+ string Version()
|
|
+ string, string Version()
|
|
+ error Load()
|
|
+ FooImpl, error Load()
|
|
+ error Unload()
|
|
|
|
}
|
|
}
|
|
|
|
|
|
IHook <|.. FooHook
|
|
class FooImpl {
|
|
FooHook ..> FooCallout
|
|
<<plugin>>
|
|
|
|
+ error Foo(int x)
|
|
|
|
}
|
|
|
|
|
|
HookModule *-- FooCallout
|
|
class BarBazHook{
|
|
HookModule *-- IHook
|
|
<<plugin>>
|
|
HookModule : +CurrentVersion
|
|
+ string, string Version()
|
|
|
|
+ BarBazImpl, error Load()
|
|
|
|
}
|
|
|
|
|
|
class LibraryManager{
|
|
class BarBazImpl {
|
|
+ LM+error New(string path)$
|
|
<<plugin>>
|
|
+ error Load()
|
|
+ error Bar(bool x)
|
|
+ error Unload()
|
|
+ int Baz(string x)
|
|
+ bool IsCompatible()
|
|
+ error Close()
|
|
+ interface Callouts()
|
|
|
|
}
|
|
}
|
|
|
|
|
|
LibraryManager *-- IHook
|
|
class HookModule {
|
|
|
|
string CurrentVersion
|
|
|
|
}
|
|
|
|
|
|
class HookManager{
|
|
class LibraryManager{
|
|
+ RegisterCallouts(interface)
|
|
+ LM, error New(string path)$
|
|
|
|
+ any, error Load()
|
|
|
|
+ string, string Version()
|
|
|
|
}
|
|
|
|
|
|
|
|
class AgentHookManager{
|
|
+ error Foo(int x)
|
|
+ error Foo(int x)
|
|
|
|
+ Close()
|
|
}
|
|
}
|
|
|
|
|
|
FooCallout <|.. HookManager
|
|
class ServerHookManager{
|
|
HookManager ..> LibraryManager
|
|
+ error Bar(bool x)
|
|
|
|
+ int Baz(string x)
|
|
|
|
+ Close()
|
|
|
|
}
|
|
|
|
|
|
class HookLoader{
|
|
class HookLoader{
|
|
+ LoadAll()
|
|
+ LoadAll()
|
|
+ UnloadAll()
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
class HookExecutor{
|
|
|
|
+ RegisterCallouts(any callouts)
|
|
|
|
+ UnregisterAllCallouts()
|
|
|
|
+ Call(type calloutType, func caller)
|
|
|
|
}
|
|
|
|
|
|
|
|
class ServerCore{
|
|
|
|
<<external>>
|
|
|
|
}
|
|
|
|
|
|
|
|
class AgentCore{
|
|
|
|
<<external>>
|
|
|
|
}
|
|
|
|
|
|
|
|
HookModule -- FooCallout
|
|
|
|
HookModule -- BarCallout
|
|
|
|
HookModule -- BazCallout
|
|
|
|
HookModule -- IHook
|
|
|
|
|
|
|
|
AgentHookManager *-- HookExecutor
|
|
|
|
ServerHookManager *-- HookExecutor
|
|
|
|
|
|
|
|
ServerCore ..> ServerHookManager
|
|
|
|
AgentCore ..> AgentHookManager
|
|
|
|
|
|
|
|
FooCallout <|.. AgentHookManager
|
|
|
|
BarCallout <|.. ServerHookManager
|
|
|
|
BazCallout <|.. ServerHookManager
|
|
|
|
|
|
|
|
HookExecutor .. HookLoader
|
|
|
|
|
|
HookLoader ..> LibraryManager
|
|
HookLoader ..> LibraryManager
|
|
HookLoader *-- HookManager
|
|
LibraryManager ..> IHook
|
|
|
|
|
|
|
|
IHook <|.. FooHook
|
|
|
|
IHook <|.. BarBazHook
|
|
|
|
FooHook --> FooImpl
|
|
|
|
BarBazHook --> BarBazImpl
|
|
|
|
FooImpl ..|> FooCallout
|
|
|
|
BarBazImpl ..|> BarCallout
|
|
|
|
BarBazImpl ..|> BazCallout
|
|
```
|
|
```
|
|
|
|
|
|
The hook module will contain three elements:
|
|
The hook module will contain three elements:
|
... | @@ -140,48 +197,3 @@ The hook manager is a facade for all hooks. It implements all hook callouts. The |
... | @@ -140,48 +197,3 @@ The hook manager is a facade for all hooks. It implements all hook callouts. The |
|
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'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. |
|
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
|
|
|
|
``` |
|
|