151 lines
3.4 KiB
Go
151 lines
3.4 KiB
Go
|
|
// /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()
|
|||
|
|
}
|
|||
|
|
}
|