mirror of
https://github.com/safing/portbase
synced 2025-04-16 15:39:08 +00:00
142 lines
3.6 KiB
Go
142 lines
3.6 KiB
Go
package subsystems
|
|
|
|
import (
|
|
"context"
|
|
"flag"
|
|
"fmt"
|
|
|
|
"github.com/safing/portbase/config"
|
|
_ "github.com/safing/portbase/database/dbmodule" // database module is required
|
|
"github.com/safing/portbase/modules"
|
|
"github.com/safing/portbase/runtime"
|
|
)
|
|
|
|
const configChangeEvent = "config change"
|
|
|
|
var (
|
|
// DefaultManager is the default subsystem registry.
|
|
DefaultManager *Manager
|
|
|
|
module *modules.Module
|
|
printGraphFlag bool
|
|
)
|
|
|
|
// Register registers a new subsystem. It's like Manager.Register
|
|
// but uses DefaultManager and panics on error.
|
|
func Register(id, name, description string, module *modules.Module, configKeySpace string, option *config.Option) {
|
|
err := DefaultManager.Register(id, name, description, module, configKeySpace, option)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func init() {
|
|
// The subsystem layer takes over module management. Note that
|
|
// no one must have called EnableModuleManagement. Otherwise
|
|
// the subsystem layer will silently fail managing module
|
|
// dependencies!
|
|
// TODO(ppacher): we SHOULD panic here!
|
|
// TASK(#1431)
|
|
|
|
modules.EnableModuleManagement(func(m *modules.Module) {
|
|
if DefaultManager == nil {
|
|
return
|
|
}
|
|
DefaultManager.handleModuleUpdate(m)
|
|
})
|
|
|
|
module = modules.Register("subsystems", prep, start, nil, "config", "database", "runtime", "base")
|
|
module.Enable()
|
|
|
|
// TODO(ppacher): can we create the default registry during prep phase?
|
|
var err error
|
|
DefaultManager, err = NewManager(runtime.DefaultRegistry)
|
|
if err != nil {
|
|
panic("Failed to create default registry: " + err.Error())
|
|
}
|
|
|
|
flag.BoolVar(&printGraphFlag, "print-subsystem-graph", false, "print the subsystem module dependency graph")
|
|
}
|
|
|
|
func prep() error {
|
|
if printGraphFlag {
|
|
DefaultManager.PrintGraph()
|
|
return modules.ErrCleanExit
|
|
}
|
|
|
|
// We need to listen for configuration changes so we can
|
|
// start/stop dependend modules in case a subsystem is
|
|
// (de-)activated.
|
|
if err := module.RegisterEventHook(
|
|
"config",
|
|
configChangeEvent,
|
|
"control subsystems",
|
|
func(ctx context.Context, _ interface{}) error {
|
|
err := DefaultManager.CheckConfig(ctx)
|
|
if err != nil {
|
|
module.Error(
|
|
"modulemgmt-failed",
|
|
fmt.Sprintf("The subsystem framework failed to start or stop one or more modules.\nError: %s\nCheck logs for more information.", err),
|
|
)
|
|
return nil
|
|
}
|
|
module.Resolve("modulemgmt-failed")
|
|
return nil
|
|
},
|
|
); err != nil {
|
|
return fmt.Errorf("register event hook: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func start() error {
|
|
// Registration of subsystems is only allowed during
|
|
// preparation. Make sure any further call to Register()
|
|
// panics.
|
|
if err := DefaultManager.Start(); err != nil {
|
|
return err
|
|
}
|
|
|
|
module.StartWorker("initial subsystem configuration", DefaultManager.CheckConfig)
|
|
|
|
return nil
|
|
}
|
|
|
|
// PrintGraph prints the subsystem and module graph.
|
|
func (mng *Manager) PrintGraph() {
|
|
mng.l.RLock()
|
|
defer mng.l.RUnlock()
|
|
|
|
fmt.Println("subsystems dependency graph:")
|
|
|
|
// unmark subsystems module
|
|
module.Disable()
|
|
|
|
// mark roots
|
|
for _, sub := range mng.subsys {
|
|
sub.module.Enable() // mark as tree root
|
|
}
|
|
|
|
for _, sub := range mng.subsys {
|
|
printModuleGraph("", sub.module, true)
|
|
}
|
|
|
|
fmt.Println("\nsubsystem module groups:")
|
|
_ = start() // no errors for what we need here
|
|
for _, sub := range mng.subsys {
|
|
fmt.Printf("├── %s\n", sub.Name)
|
|
for _, mod := range sub.Modules[1:] {
|
|
fmt.Printf("│ ├── %s\n", mod.Name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func printModuleGraph(prefix string, module *modules.Module, root bool) {
|
|
fmt.Printf("%s├── %s\n", prefix, module.Name)
|
|
if root || !module.Enabled() {
|
|
for _, dep := range module.Dependencies() {
|
|
printModuleGraph(fmt.Sprintf("│ %s", prefix), dep, false)
|
|
}
|
|
}
|
|
}
|