mirror of
https://github.com/m1k1o/neko.git
synced 2025-05-21 21:17:04 +02:00
load plugins in order of dependencies.
This commit is contained in:
parent
cd2d9b413d
commit
49ff490640
7 changed files with 804 additions and 33 deletions
130
internal/plugins/dependency.go
Normal file
130
internal/plugins/dependency.go
Normal file
|
@ -0,0 +1,130 @@
|
|||
package plugins
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
"gitlab.com/demodesk/neko/server/pkg/types"
|
||||
)
|
||||
|
||||
type dependency struct {
|
||||
plugin types.Plugin
|
||||
dependsOn []*dependency
|
||||
invoked bool
|
||||
logger zerolog.Logger
|
||||
}
|
||||
|
||||
type dependiencies struct {
|
||||
deps map[string]*dependency
|
||||
logger zerolog.Logger
|
||||
}
|
||||
|
||||
func (d *dependiencies) addPlugin(plugin types.Plugin) error {
|
||||
plug, ok := d.deps[plugin.Name()]
|
||||
if !ok {
|
||||
plug = &dependency{}
|
||||
} else if plug.plugin != nil {
|
||||
return fmt.Errorf("plugin '%s' already added", plugin.Name())
|
||||
}
|
||||
|
||||
plug.plugin = plugin
|
||||
plug.logger = d.logger
|
||||
d.deps[plugin.Name()] = plug
|
||||
|
||||
dplug, ok := plugin.(types.DependablePlugin)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, dep := range dplug.DependsOn() {
|
||||
var dependsOn *dependency
|
||||
dependsOn, ok = d.deps[dep]
|
||||
if !ok {
|
||||
dependsOn = &dependency{}
|
||||
} else if dependsOn.plugin != nil {
|
||||
// if there is a cyclical dependency, break it and return error
|
||||
if tdep := dependsOn.findPlugin(plugin.Name()); tdep != nil {
|
||||
dependsOn.dependsOn = nil
|
||||
delete(d.deps, plugin.Name())
|
||||
return fmt.Errorf("cyclical dependency detected: '%s' <-> '%s'", plugin.Name(), tdep.plugin.Name())
|
||||
}
|
||||
}
|
||||
|
||||
plug.dependsOn = append(plug.dependsOn, dependsOn)
|
||||
d.deps[dep] = dependsOn
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *dependiencies) start(pm types.PluginManagers) error {
|
||||
for _, p := range d.deps {
|
||||
if err := p.start(pm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *dependiencies) findPlugin(name string) (*dependency, bool) {
|
||||
for _, p := range d.deps {
|
||||
if found := p.findPlugin(name); found != nil {
|
||||
return found, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (a *dependency) findPlugin(name string) *dependency {
|
||||
if a == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if a.plugin.Name() == name {
|
||||
return a
|
||||
}
|
||||
|
||||
for _, p := range a.dependsOn {
|
||||
if found := p.findPlugin(name); found != nil {
|
||||
return found
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *dependiencies) forEach(f func(*dependency) error) error {
|
||||
for _, dp := range d.deps {
|
||||
if err := f(dp); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *dependiencies) len() int {
|
||||
return len(d.deps)
|
||||
}
|
||||
|
||||
func (a *dependency) start(pm types.PluginManagers) error {
|
||||
if a.invoked {
|
||||
return nil
|
||||
}
|
||||
|
||||
a.invoked = true
|
||||
|
||||
for _, do := range a.dependsOn {
|
||||
if err := do.start(pm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err := a.plugin.Start(pm)
|
||||
a.logger.Err(err).Str("plugin", a.plugin.Name()).Msg("plugin start")
|
||||
if err != nil {
|
||||
return fmt.Errorf("plugin %s failed to start: %s", a.plugin.Name(), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue