Initial commit

This commit is contained in:
SantianDev
2026-03-03 15:05:55 +03:00
commit a9c89f027a
37 changed files with 3256 additions and 0 deletions

66
plugin/manager.go Normal file
View File

@@ -0,0 +1,66 @@
package plugin
import (
"context"
"fmt"
"os"
"path/filepath"
"strings"
"sync"
"sync/atomic"
)
var (
loaded atomic.Bool
plugins []*Plugin
)
func Add(impl Impl) {
if loaded.Load() {
panic("cannot add plugin after server has started")
}
plugins = append(plugins, &Plugin{impl: impl})
}
func Initialize(log Logger, folder string) (func(context.Context) *sync.WaitGroup, error) {
if !loaded.CompareAndSwap(false, true) {
panic("plugins already initialized")
}
log.Infof("Loading %d plugin(s)...", len(plugins))
names := map[string]struct{}{}
for _, p := range plugins {
key := strings.ToLower(p.impl.Name())
if _, ok := names[key]; ok {
return nil, fmt.Errorf("duplicate plugin name: %s", p.impl.Name())
}
names[key] = struct{}{}
}
wd, err := os.Getwd()
if err != nil {
return nil, err
}
for _, p := range plugins {
p.logger = log
p.directory = filepath.Join(wd, folder, p.impl.Name())
if err := p.impl.Setup(p); err != nil {
return nil, fmt.Errorf("plugin '%s' setup failed: %w", p.impl.Name(), err)
}
log.Infof("Plugin '%s' loaded.", p.impl.Name())
}
return func(ctx context.Context) *sync.WaitGroup {
wg := &sync.WaitGroup{}
for _, p := range plugins {
wg.Add(1)
go func(p *Plugin) {
defer wg.Done()
p.impl.Run(ctx, p)
}(p)
}
return wg
}, nil
}

40
plugin/plugin.go Normal file
View File

@@ -0,0 +1,40 @@
package plugin
import (
"context"
"fmt"
"os"
)
type Impl interface {
Name() string
Setup(p *Plugin) error
Run(ctx context.Context, p *Plugin)
}
type Plugin struct {
impl Impl
logger Logger
directory string
directoryCreated bool
}
type Logger interface {
Infof(format string, args ...any)
Warnf(format string, args ...any)
Errorf(format string, args ...any)
Debugf(format string, args ...any)
}
func (p *Plugin) Impl() Impl { return p.impl }
func (p *Plugin) Logger() Logger { return p.logger }
func (p *Plugin) DataFolder() string {
if !p.directoryCreated {
if err := os.MkdirAll(p.directory, os.ModePerm); err != nil {
panic(fmt.Sprintf("failed to create data folder for plugin %s: %v", p.impl.Name(), err))
}
p.directoryCreated = true
}
return p.directory
}