118 lines
2.0 KiB
Go
118 lines
2.0 KiB
Go
|
package plugin
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"path/filepath"
|
||
|
"plugin"
|
||
|
"sync"
|
||
|
|
||
|
"github.com/pkg/errors"
|
||
|
)
|
||
|
|
||
|
type Registry struct {
|
||
|
plugins map[string]Plugin
|
||
|
mutex sync.RWMutex
|
||
|
}
|
||
|
|
||
|
func (r *Registry) Add(plg Plugin) {
|
||
|
r.mutex.Lock()
|
||
|
defer r.mutex.Unlock()
|
||
|
|
||
|
r.plugins[plg.PluginName()] = plg
|
||
|
}
|
||
|
|
||
|
func (r *Registry) Get(name string) (Plugin, error) {
|
||
|
r.mutex.RLock()
|
||
|
defer r.mutex.RUnlock()
|
||
|
|
||
|
plg, exists := r.plugins[name]
|
||
|
if !exists {
|
||
|
return nil, errors.WithStack(ErrPluginNotFound)
|
||
|
}
|
||
|
|
||
|
return plg, nil
|
||
|
}
|
||
|
|
||
|
func (r *Registry) Load(ctx context.Context, path string) (Plugin, error) {
|
||
|
p, err := plugin.Open(path)
|
||
|
if err != nil {
|
||
|
return nil, errors.WithStack(err)
|
||
|
}
|
||
|
|
||
|
registerFuncSymbol, err := p.Lookup("RegisterPlugin")
|
||
|
if err != nil {
|
||
|
return nil, errors.WithStack(err)
|
||
|
}
|
||
|
|
||
|
register, ok := registerFuncSymbol.(func(context.Context) (Plugin, error))
|
||
|
if !ok {
|
||
|
return nil, errors.WithStack(ErrInvalidRegisterFunc)
|
||
|
}
|
||
|
|
||
|
plg, err := register(ctx)
|
||
|
if err != nil {
|
||
|
return nil, errors.WithStack(err)
|
||
|
}
|
||
|
|
||
|
if plg == nil {
|
||
|
return nil, errors.WithStack(ErrInvalidPlugin)
|
||
|
}
|
||
|
|
||
|
r.Add(plg)
|
||
|
|
||
|
return plg, nil
|
||
|
}
|
||
|
|
||
|
func (r *Registry) LoadAll(ctx context.Context, pattern string) ([]Plugin, error) {
|
||
|
extensions := make([]Plugin, 0)
|
||
|
|
||
|
matches, err := filepath.Glob(pattern)
|
||
|
if err != nil {
|
||
|
return nil, errors.WithStack(err)
|
||
|
}
|
||
|
|
||
|
for _, m := range matches {
|
||
|
ext, err := r.Load(ctx, m)
|
||
|
if err != nil {
|
||
|
return nil, errors.WithStack(err)
|
||
|
}
|
||
|
|
||
|
extensions = append(extensions, ext)
|
||
|
}
|
||
|
|
||
|
return extensions, nil
|
||
|
}
|
||
|
|
||
|
func (r *Registry) Plugins() []Plugin {
|
||
|
r.mutex.RLock()
|
||
|
defer r.mutex.RUnlock()
|
||
|
|
||
|
plugins := make([]Plugin, 0, len(r.plugins))
|
||
|
for _, p := range r.plugins {
|
||
|
plugins = append(plugins, p)
|
||
|
}
|
||
|
|
||
|
return plugins
|
||
|
}
|
||
|
|
||
|
type IteratorFunc func(plg Plugin) error
|
||
|
|
||
|
func (r *Registry) Each(iterator IteratorFunc) error {
|
||
|
r.mutex.RLock()
|
||
|
defer r.mutex.RUnlock()
|
||
|
|
||
|
for _, p := range r.plugins {
|
||
|
if err := iterator(p); err != nil {
|
||
|
return errors.WithStack(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func NewRegistry() *Registry {
|
||
|
return &Registry{
|
||
|
plugins: make(map[string]Plugin),
|
||
|
}
|
||
|
}
|