mirror of
https://github.com/m1k1o/neko.git
synced 2024-07-24 14:40:50 +12:00
134 lines
2.6 KiB
Go
134 lines
2.6 KiB
Go
package plugins
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/rs/zerolog"
|
|
|
|
"github.com/demodesk/neko/pkg/types"
|
|
)
|
|
|
|
type dependency struct {
|
|
plugin types.Plugin
|
|
dependsOn []*dependency
|
|
invoked bool
|
|
logger zerolog.Logger
|
|
}
|
|
|
|
func (a *dependency) findPlugin(name string) (*dependency, bool) {
|
|
if a == nil {
|
|
return nil, false
|
|
}
|
|
|
|
if a.plugin.Name() == name {
|
|
return a, true
|
|
}
|
|
|
|
for _, dep := range a.dependsOn {
|
|
plug, ok := dep.findPlugin(name)
|
|
if ok {
|
|
return plug, true
|
|
}
|
|
}
|
|
|
|
return nil, false
|
|
}
|
|
|
|
func (a *dependency) startPlugin(pm types.PluginManagers) error {
|
|
if a.invoked {
|
|
return nil
|
|
}
|
|
|
|
a.invoked = true
|
|
|
|
for _, do := range a.dependsOn {
|
|
if err := do.startPlugin(pm); err != nil {
|
|
return fmt.Errorf("plugin's '%s' dependency: %w", a.plugin.Name(), err)
|
|
}
|
|
}
|
|
|
|
err := a.plugin.Start(pm)
|
|
if err != nil {
|
|
return fmt.Errorf("plugin '%s' failed to start: %w", a.plugin.Name(), err)
|
|
}
|
|
|
|
a.logger.Info().Str("plugin", a.plugin.Name()).Msg("plugin started")
|
|
return nil
|
|
}
|
|
|
|
type dependiencies struct {
|
|
deps map[string]*dependency
|
|
logger zerolog.Logger
|
|
}
|
|
|
|
func (d *dependiencies) addPlugin(plugin types.Plugin) error {
|
|
pluginName := plugin.Name()
|
|
|
|
plug, ok := d.deps[pluginName]
|
|
if !ok {
|
|
plug = &dependency{}
|
|
} else if plug.plugin != nil {
|
|
return fmt.Errorf("plugin '%s' already added", pluginName)
|
|
}
|
|
|
|
plug.plugin = plugin
|
|
plug.logger = d.logger
|
|
d.deps[pluginName] = plug
|
|
|
|
dplug, ok := plugin.(types.DependablePlugin)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
|
|
for _, depName := range dplug.DependsOn() {
|
|
dependsOn, ok := d.deps[depName]
|
|
if !ok {
|
|
dependsOn = &dependency{}
|
|
} else if dependsOn.plugin != nil {
|
|
// if there is a cyclical dependency, break it and return error
|
|
if tdep, ok := dependsOn.findPlugin(pluginName); ok {
|
|
dependsOn.dependsOn = nil
|
|
delete(d.deps, pluginName)
|
|
return fmt.Errorf("cyclical dependency detected: '%s' <-> '%s'", pluginName, tdep.plugin.Name())
|
|
}
|
|
}
|
|
|
|
plug.dependsOn = append(plug.dependsOn, dependsOn)
|
|
d.deps[depName] = dependsOn
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (d *dependiencies) findPlugin(name string) (*dependency, bool) {
|
|
for _, dep := range d.deps {
|
|
plug, ok := dep.findPlugin(name)
|
|
if ok {
|
|
return plug, true
|
|
}
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func (d *dependiencies) start(pm types.PluginManagers) error {
|
|
for _, dep := range d.deps {
|
|
if err := dep.startPlugin(pm); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (d *dependiencies) forEach(f func(*dependency) error) error {
|
|
for _, dep := range d.deps {
|
|
if err := f(dep); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (d *dependiencies) len() int {
|
|
return len(d.deps)
|
|
}
|