123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- package plugins
- import (
- "errors"
- "os"
- "os/exec"
- "path/filepath"
- "sync"
- "time"
- "imuslab.com/zoraxy/mod/database"
- "imuslab.com/zoraxy/mod/info/logger"
- )
- type Plugin struct {
- Spec *IntroSpect //The plugin specification
- Process *exec.Cmd //The process of the plugin
- Enabled bool //Whether the plugin is enabled
- }
- type ManagerOptions struct {
- ZoraxyVersion string
- PluginDir string
- SystemConst *RuntimeConstantValue
- Database database.Database
- Logger *logger.Logger
- }
- type Manager struct {
- LoadedPlugins sync.Map //Storing *Plugin
- Options *ManagerOptions
- }
- func NewPluginManager(options *ManagerOptions) *Manager {
- return &Manager{
- LoadedPlugins: sync.Map{},
- Options: options,
- }
- }
- // LoadPlugins loads all plugins from the plugin directory
- func (m *Manager) LoadPlugins() error {
- // Load all plugins from the plugin directory
- foldersInPluginDir, err := os.ReadDir(m.Options.PluginDir)
- if err != nil {
- return err
- }
- for _, folder := range foldersInPluginDir {
- if folder.IsDir() {
- pluginPath := filepath.Join(m.Options.PluginDir, folder.Name())
- thisPlugin, err := m.LoadPluginSpec(pluginPath)
- if err != nil {
- m.Log("Failed to load plugin: "+filepath.Base(pluginPath), err)
- continue
- }
- m.LoadedPlugins.Store(thisPlugin.Spec.ID, thisPlugin)
- }
- }
- return nil
- }
- // GetPluginByID returns a plugin by its ID
- func (m *Manager) GetPluginByID(pluginID string) (*Plugin, error) {
- plugin, ok := m.LoadedPlugins.Load(pluginID)
- if !ok {
- return nil, errors.New("plugin not found")
- }
- return plugin.(*Plugin), nil
- }
- // EnablePlugin enables a plugin
- func (m *Manager) EnablePlugin(pluginID string) error {
- plugin, ok := m.LoadedPlugins.Load(pluginID)
- if !ok {
- return errors.New("plugin not found")
- }
- plugin.(*Plugin).Enabled = true
- return nil
- }
- // DisablePlugin disables a plugin
- func (m *Manager) DisablePlugin(pluginID string) error {
- plugin, ok := m.LoadedPlugins.Load(pluginID)
- if !ok {
- return errors.New("plugin not found")
- }
- thisPlugin := plugin.(*Plugin)
- thisPlugin.Process.Process.Signal(os.Interrupt)
- go func() {
- //Wait for 10 seconds for the plugin to stop gracefully
- time.Sleep(10 * time.Second)
- if thisPlugin.Process.ProcessState == nil || !thisPlugin.Process.ProcessState.Exited() {
- m.Log("Plugin "+thisPlugin.Spec.Name+" failed to stop gracefully, killing it", nil)
- thisPlugin.Process.Process.Kill()
- } else {
- m.Log("Plugin "+thisPlugin.Spec.Name+" background process stopped", nil)
- }
- }()
- thisPlugin.Enabled = false
- return nil
- }
- // Terminate all plugins and exit
- func (m *Manager) Close() {
- m.LoadedPlugins.Range(func(key, value interface{}) bool {
- plugin := value.(*Plugin)
- if plugin.Enabled {
- m.DisablePlugin(plugin.Spec.ID)
- }
- return true
- })
- //Wait until all loaded plugin process are terminated
- m.BlockUntilAllProcessExited()
- }
|