// /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() } }