futriis/internal/lua/plugin.go

151 lines
3.4 KiB
Go
Raw Normal View History

2026-02-23 22:48:31 +03:00
// /futriis/internal/lua/plugin.go
// Пакет lua реализует поддержку Lua плагинов
package lua
import (
"fmt"
"io/ioutil"
"path/filepath"
"sync"
"futriis/pkg/config"
"futriis/pkg/utils"
"github.com/yuin/gopher-lua"
)
// PluginManager управляет Lua плагинами
type PluginManager struct {
state *lua.LState
plugins map[string]*lua.LFunction
mu sync.RWMutex
enabled bool
}
// NewPluginManager создаёт новый менеджер плагинов
func NewPluginManager(cfg *config.LuaConfig) *PluginManager {
pm := &PluginManager{
plugins: make(map[string]*lua.LFunction),
enabled: cfg.Enabled,
}
if cfg.Enabled {
pm.state = lua.NewState()
pm.registerFunctions()
}
return pm
}
// registerFunctions регистрирует функции Go, доступные из Lua
func (pm *PluginManager) registerFunctions() {
if !pm.enabled || pm.state == nil {
return
}
// Регистрируем функции для работы с данными
pm.state.SetGlobal("print", pm.state.NewFunction(func(L *lua.LState) int {
top := L.GetTop()
args := make([]interface{}, top)
for i := 1; i <= top; i++ {
args[i-1] = L.Get(i).String()
}
utils.PrintInfo(fmt.Sprint(args...))
return 0
}))
pm.state.SetGlobal("get", pm.state.NewFunction(func(L *lua.LState) int {
key := L.ToString(1)
// TODO: получить значение из хранилища
L.Push(lua.LString(key))
return 1
}))
pm.state.SetGlobal("set", pm.state.NewFunction(func(L *lua.LState) int {
key := L.ToString(1)
value := L.ToString(2)
// TODO: установить значение в хранилище
utils.PrintInfo("Lua set: %s = %s", key, value)
return 0
}))
}
// LoadPlugins загружает все Lua плагины из директории
func (pm *PluginManager) LoadPlugins(pluginsDir string) error {
if !pm.enabled || pm.state == nil {
return nil
}
files, err := ioutil.ReadDir(pluginsDir)
if err != nil {
return err
}
for _, file := range files {
if filepath.Ext(file.Name()) == ".lua" {
if err := pm.LoadPlugin(filepath.Join(pluginsDir, file.Name())); err != nil {
utils.PrintError("Ошибка загрузки плагина %s: %v", file.Name(), err)
}
}
}
return nil
}
// LoadPlugin загружает один Lua плагин
func (pm *PluginManager) LoadPlugin(path string) error {
if !pm.enabled || pm.state == nil {
return nil
}
data, err := ioutil.ReadFile(path)
if err != nil {
return err
}
fn, err := pm.state.LoadString(string(data))
if err != nil {
return err
}
pm.mu.Lock()
pm.plugins[filepath.Base(path)] = fn
pm.mu.Unlock()
utils.PrintSuccess("Загружен плагин: %s", filepath.Base(path))
return nil
}
// ExecutePlugin выполняет функцию плагина
func (pm *PluginManager) ExecutePlugin(name string, args ...lua.LValue) error {
if !pm.enabled || pm.state == nil {
return nil
}
pm.mu.RLock()
fn, exists := pm.plugins[name]
pm.mu.RUnlock()
if !exists {
return fmt.Errorf("плагин %s не найден", name)
}
pm.state.Push(fn)
for _, arg := range args {
pm.state.Push(arg)
}
if err := pm.state.PCall(len(args), lua.MultRet, nil); err != nil {
return err
}
return nil
}
// Close закрывает Lua состояние
func (pm *PluginManager) Close() {
if pm.state != nil {
pm.state.Close()
}
}