From bddff0cf2f93d28f6b0db861c4e2d5417ad9828f Mon Sep 17 00:00:00 2001 From: Toby Chui Date: Thu, 27 Feb 2025 22:27:13 +0800 Subject: [PATCH] Added working plugin manager prototype - Added experimental plugin UI proxy - Added plugin icon loader - Added plugin table renderer --- example/plugins/helloworld/icon.png | Bin 0 -> 14120 bytes example/plugins/helloworld/icon.psd | Bin 0 -> 134796 bytes src/api.go | 8 +++ src/mod/plugins/handler.go | 83 ++++++++++++++++++++++++++++ src/mod/plugins/lifecycle.go | 56 ++++++++++++++++--- src/mod/plugins/no_img.png | Bin 0 -> 8404 bytes src/mod/plugins/no_img.psd | Bin 0 -> 96484 bytes src/mod/plugins/plugins.go | 59 ++++++++++++++++---- src/mod/plugins/uirouter.go | 41 ++++++++++++++ src/router.go | 13 +++++ src/start.go | 4 ++ src/web/components/plugins.html | 67 ++++++++++++++++------ src/web/index.html | 2 +- 13 files changed, 294 insertions(+), 39 deletions(-) create mode 100644 example/plugins/helloworld/icon.png create mode 100644 example/plugins/helloworld/icon.psd create mode 100644 src/mod/plugins/handler.go create mode 100644 src/mod/plugins/no_img.png create mode 100644 src/mod/plugins/no_img.psd create mode 100644 src/mod/plugins/uirouter.go diff --git a/example/plugins/helloworld/icon.png b/example/plugins/helloworld/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..69c3e2984c2b0a95bbd0f9102f590a43edd4de05 GIT binary patch literal 14120 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 literal 0 HcmV?d00001 diff --git a/src/mod/plugins/plugins.go b/src/mod/plugins/plugins.go index 957eaa4..181d3e5 100644 --- a/src/mod/plugins/plugins.go +++ b/src/mod/plugins/plugins.go @@ -2,12 +2,16 @@ package plugins import ( "errors" + "fmt" "os" "os/exec" "path/filepath" "sync" + _ "embed" + "imuslab.com/zoraxy/mod/database" + "imuslab.com/zoraxy/mod/dynamicproxy/dpcore" "imuslab.com/zoraxy/mod/info/logger" "imuslab.com/zoraxy/mod/utils" ) @@ -15,8 +19,10 @@ import ( type Plugin struct { RootDir string //The root directory of the plugin Spec *IntroSpect //The plugin specification - Process *exec.Cmd //The process of the plugin Enabled bool //Whether the plugin is enabled + + uiProxy *dpcore.ReverseProxy //The reverse proxy for the plugin UI + process *exec.Cmd //The process of the plugin } type ManagerOptions struct { @@ -31,16 +37,22 @@ type Manager struct { Options *ManagerOptions } +//go:embed no_img.png +var noImg []byte + // NewPluginManager creates a new plugin manager func NewPluginManager(options *ManagerOptions) *Manager { + //Create plugin directory if not exists if options.PluginDir == "" { options.PluginDir = "./plugins" } - if !utils.FileExists(options.PluginDir) { os.MkdirAll(options.PluginDir, 0755) } + //Create database table + options.Database.NewTable("plugins") + return &Manager{ LoadedPlugins: sync.Map{}, Options: options, @@ -63,17 +75,18 @@ func (m *Manager) LoadPluginsFromDisk() error { m.Log("Failed to load plugin: "+filepath.Base(pluginPath), err) continue } - thisPlugin.RootDir = pluginPath + thisPlugin.RootDir = filepath.ToSlash(pluginPath) m.LoadedPlugins.Store(thisPlugin.Spec.ID, thisPlugin) m.Log("Loaded plugin: "+thisPlugin.Spec.Name, nil) - //TODO: Move this to a separate function - // Enable the plugin if it is enabled in the database - err = m.StartPlugin(thisPlugin.Spec.ID) - if err != nil { - m.Log("Failed to enable plugin: "+thisPlugin.Spec.Name, err) + // If the plugin was enabled, start it now + fmt.Println(m.GetPluginPreviousEnableState(thisPlugin.Spec.ID)) + if m.GetPluginPreviousEnableState(thisPlugin.Spec.ID) { + err = m.StartPlugin(thisPlugin.Spec.ID) + if err != nil { + m.Log("Failed to enable plugin: "+thisPlugin.Spec.Name, err) + } } - } } @@ -95,26 +108,48 @@ func (m *Manager) EnablePlugin(pluginID string) error { if err != nil { return err } - //TODO: Add database record + m.Options.Database.Write("plugins", pluginID, true) return nil } // DisablePlugin disables a plugin func (m *Manager) DisablePlugin(pluginID string) error { err := m.StopPlugin(pluginID) - //TODO: Add database record + m.Options.Database.Write("plugins", pluginID, false) if err != nil { return err } return nil } +// GetPluginPreviousEnableState returns the previous enable state of a plugin +func (m *Manager) GetPluginPreviousEnableState(pluginID string) bool { + enableState := true + err := m.Options.Database.Read("plugins", pluginID, &enableState) + if err != nil { + //Default to true + return true + } + return enableState +} + +// ListLoadedPlugins returns a list of loaded plugins +func (m *Manager) ListLoadedPlugins() ([]*Plugin, error) { + var plugins []*Plugin + m.LoadedPlugins.Range(func(key, value interface{}) bool { + plugin := value.(*Plugin) + plugins = append(plugins, plugin) + return true + }) + return plugins, 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) + m.StopPlugin(plugin.Spec.ID) } return true }) diff --git a/src/mod/plugins/uirouter.go b/src/mod/plugins/uirouter.go new file mode 100644 index 0000000..62414de --- /dev/null +++ b/src/mod/plugins/uirouter.go @@ -0,0 +1,41 @@ +package plugins + +import ( + "net/http" + + "imuslab.com/zoraxy/mod/dynamicproxy/dpcore" + "imuslab.com/zoraxy/mod/utils" +) + +// HandlePluginUI handles the request to the plugin UI +// This function will route the request to the correct plugin UI handler +func (m *Manager) HandlePluginUI(pluginID string, w http.ResponseWriter, r *http.Request) { + plugin, err := m.GetPluginByID(pluginID) + if err != nil { + utils.SendErrorResponse(w, err.Error()) + return + } + + //Check if the plugin has UI + if plugin.Spec.UIPath == "" { + utils.SendErrorResponse(w, "Plugin does not have UI") + return + } + + //Check if the plugin has UI handler + if plugin.uiProxy == nil { + utils.SendErrorResponse(w, "Plugin does not have UI handler") + return + } + + //Call the plugin UI handler + plugin.uiProxy.ServeHTTP(w, r, &dpcore.ResponseRewriteRuleSet{ + UseTLS: false, + OriginalHost: r.Host, + ProxyDomain: r.Host, + NoCache: true, + PathPrefix: "/plugin.ui/" + pluginID, + Version: m.Options.SystemConst.ZoraxyVersion, + }) + +} diff --git a/src/router.go b/src/router.go index 7fab6cf..e7a4645 100644 --- a/src/router.go +++ b/src/router.go @@ -58,6 +58,19 @@ func FSHandler(handler http.Handler) http.Handler { return } + //For Plugin Routing + if strings.HasPrefix(r.URL.Path, "/plugin.ui/") { + //Extract the plugin ID from the request path + parts := strings.Split(r.URL.Path, "/") + if len(parts) > 2 { + pluginID := parts[2] + pluginManager.HandlePluginUI(pluginID, w, r) + } else { + http.Error(w, "Invalid Usage", http.StatusInternalServerError) + } + return + } + //For WebSSH Routing //Example URL Path: /web.ssh/{{instance_uuid}}/* if strings.HasPrefix(r.URL.Path, "/web.ssh/") { diff --git a/src/start.go b/src/start.go index 7a7171d..f9d757d 100644 --- a/src/start.go +++ b/src/start.go @@ -384,6 +384,10 @@ func ShutdownSeq() { if acmeAutoRenewer != nil { acmeAutoRenewer.Close() } + //Close the plugin manager + SystemWideLogger.Println("Shutting down plugin manager") + pluginManager.Close() + //Remove the tmp folder SystemWideLogger.Println("Cleaning up tmp files") os.RemoveAll("./tmp") diff --git a/src/web/components/plugins.html b/src/web/components/plugins.html index 15a6775..7d0e780 100644 --- a/src/web/components/plugins.html +++ b/src/web/components/plugins.html @@ -1,7 +1,7 @@
-

Plugins Manager

-

Add custom features to Zoraxy

+

Plugins

+

Custom features on Zoraxy

@@ -9,30 +9,61 @@ - - - - - - - - - - - + +
Plugin Name Descriptions CatergoryVersionAuthor Action
{{plugin.name}}{{plugin.description}}{{plugin.category}}{{plugin.version}}{{plugin.author}} -
- -
- -
diff --git a/src/web/index.html b/src/web/index.html index 8527b00..c2aaca3 100644 --- a/src/web/index.html +++ b/src/web/index.html @@ -79,7 +79,7 @@ - Plugins Manager + Plugins Static Web Server