package main import ( "context" "encoding/json" "fmt" "html/template" "log" "net/http" "runtime" "strconv" "strings" "github.com/darkit/goproxy/examples/plugin" ) // 全局插件管理器 var pm *plugin.PluginManager // AdminHandler 处理管理界面主页 func AdminHandler(w http.ResponseWriter, r *http.Request) { // HTML模板 tmpl := ` 插件管理系统

插件管理系统

系统信息

操作系统: {{.OS}}

动态加载支持: {{if .DynamicLoadingSupported}}是{{else}}否{{end}}

插件目录: {{.PluginsDir}}

已加载插件数量: {{len .Plugins}}

已安装插件

{{range .Plugins}}

{{.Name}}

版本: {{.Version}} 作者: {{.Author}}
{{if .Enabled}} 已启用 {{else}} 已禁用 {{end}}
{{.Description}}
{{if .Config}}

配置:

{{range $key, $value := .Config}}
{{$key}}:
{{$value}}
{{end}}
{{end}}
{{if .Enabled}} {{else}} {{end}}
{{end}} {{if not .Plugins}}

没有已安装的插件。

{{end}}

操作

` // 解析模板 t, err := template.New("admin").Parse(tmpl) if err != nil { http.Error(w, fmt.Sprintf("模板解析错误: %v", err), http.StatusInternalServerError) return } // 准备数据 data := struct { Plugins []plugin.PluginInfo OS string DynamicLoadingSupported bool PluginsDir string }{ Plugins: pm.GetPluginInfos(), OS: strings.Title(strings.ToLower(fmt.Sprintf("%s", strings.Split(runtime.GOOS, "/")[0]))), DynamicLoadingSupported: pm.IsDynamicLoadingSupported(), PluginsDir: pluginsDir, } // 渲染模板 if err := t.Execute(w, data); err != nil { http.Error(w, fmt.Sprintf("模板渲染错误: %v", err), http.StatusInternalServerError) } } // EnablePluginHandler 启用插件 func EnablePluginHandler(w http.ResponseWriter, r *http.Request) { pluginName := r.URL.Path[len("/enable/"):] if err := pm.EnablePlugin(pluginName); err != nil { http.Error(w, fmt.Sprintf("启用插件失败: %v", err), http.StatusInternalServerError) return } // 尝试初始化和启动插件 ctx := context.Background() plugin, exists := pm.GetPlugin(pluginName) if exists && plugin.IsEnabled() { config, _ := pm.GetPluginConfig(pluginName) if err := plugin.Init(ctx, config); err != nil { http.Error(w, fmt.Sprintf("初始化插件失败: %v", err), http.StatusInternalServerError) return } if err := plugin.Start(ctx); err != nil { http.Error(w, fmt.Sprintf("启动插件失败: %v", err), http.StatusInternalServerError) return } } http.Redirect(w, r, "/", http.StatusSeeOther) } // DisablePluginHandler 禁用插件 func DisablePluginHandler(w http.ResponseWriter, r *http.Request) { pluginName := r.URL.Path[len("/disable/"):] // 先停止插件 ctx := context.Background() plugin, exists := pm.GetPlugin(pluginName) if exists && plugin.IsEnabled() { if err := plugin.Stop(ctx); err != nil { http.Error(w, fmt.Sprintf("停止插件失败: %v", err), http.StatusInternalServerError) return } } // 禁用插件 if err := pm.DisablePlugin(pluginName); err != nil { http.Error(w, fmt.Sprintf("禁用插件失败: %v", err), http.StatusInternalServerError) return } http.Redirect(w, r, "/", http.StatusSeeOther) } // ConfigPluginHandler 配置插件 func ConfigPluginHandler(w http.ResponseWriter, r *http.Request) { pluginName := r.URL.Path[len("/config/"):] if r.Method == http.MethodPost { // 处理配置表单提交 if err := r.ParseForm(); err != nil { http.Error(w, fmt.Sprintf("解析表单失败: %v", err), http.StatusBadRequest) return } // 收集配置项 config := make(map[string]interface{}) for key, values := range r.PostForm { if key == "pluginName" { continue // 跳过插件名称字段 } if len(values) > 0 { // 尝试将值转换为适当的类型 value := values[0] // 布尔值处理 if value == "true" { config[key] = true } else if value == "false" { config[key] = false } else if strings.Contains(value, ".") { // 尝试解析为浮点数 if f, err := strconv.ParseFloat(value, 64); err == nil { config[key] = f } else { config[key] = value } } else if i, err := strconv.Atoi(value); err == nil { // 尝试解析为整数 config[key] = i } else { // 默认为字符串 config[key] = value } } } // 保存配置 if err := pm.SetPluginConfig(pluginName, config); err != nil { http.Error(w, fmt.Sprintf("保存配置失败: %v", err), http.StatusInternalServerError) return } // 重定向回主页 http.Redirect(w, r, "/", http.StatusSeeOther) return } // 获取插件信息和配置 info, config := getPluginInfo(pluginName) if info == nil { http.Error(w, "插件不存在", http.StatusNotFound) return } // 配置表单模板 tmpl := ` 配置 {{.Info.Name}}

配置 {{.Info.Name}}

{{range $key, $value := .Config}}
{{if eq (printf "%T" $value) "bool"}} {{else if eq (printf "%T" $value) "float64"}} {{else if eq (printf "%T" $value) "int"}} {{else}} {{end}}
{{end}}
返回插件列表 ` // 解析模板 t, err := template.New("config").Parse(tmpl) if err != nil { http.Error(w, fmt.Sprintf("模板解析错误: %v", err), http.StatusInternalServerError) return } // 准备数据 data := struct { Info *plugin.PluginInfo Config map[string]interface{} }{ Info: info, Config: config, } // 渲染模板 if err := t.Execute(w, data); err != nil { http.Error(w, fmt.Sprintf("模板渲染错误: %v", err), http.StatusInternalServerError) } } // ReloadPluginsHandler 重新加载插件 func ReloadPluginsHandler(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Redirect(w, r, "/", http.StatusSeeOther) return } // 停止所有插件 ctx := context.Background() if err := pm.StopPlugins(ctx); err != nil { http.Error(w, fmt.Sprintf("停止插件失败: %v", err), http.StatusInternalServerError) return } // 重新加载插件 if err := pm.LoadPlugins(); err != nil { http.Error(w, fmt.Sprintf("加载插件失败: %v", err), http.StatusInternalServerError) return } // 初始化和启动插件 if err := pm.InitPlugins(ctx); err != nil { http.Error(w, fmt.Sprintf("初始化插件失败: %v", err), http.StatusInternalServerError) return } if err := pm.StartPlugins(ctx); err != nil { http.Error(w, fmt.Sprintf("启动插件失败: %v", err), http.StatusInternalServerError) return } http.Redirect(w, r, "/", http.StatusSeeOther) } // API接口处理器 - 返回插件列表 func APIPluginsHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") plugins := pm.GetPluginInfos() if err := json.NewEncoder(w).Encode(plugins); err != nil { http.Error(w, fmt.Sprintf("编码JSON失败: %v", err), http.StatusInternalServerError) } } // getPluginInfo 获取插件信息和配置 func getPluginInfo(name string) (*plugin.PluginInfo, map[string]interface{}) { plugins := pm.GetPluginInfos() for _, info := range plugins { if info.Name == name { config, _ := pm.GetPluginConfig(name) return &info, config } } return nil, nil } // 插件目录 var pluginsDir = "./plugins" func main3() { // 创建插件管理器 pm = plugin.NewPluginManager(pluginsDir) // 加载插件 if err := pm.LoadPlugins(); err != nil { log.Fatalf("加载插件失败: %v", err) } // 初始化并启动插件 ctx := context.Background() if err := pm.InitPlugins(ctx); err != nil { log.Printf("初始化插件失败: %v", err) } if err := pm.StartPlugins(ctx); err != nil { log.Printf("启动插件失败: %v", err) } // 注册处理器 http.HandleFunc("/", AdminHandler) http.HandleFunc("/enable/", EnablePluginHandler) http.HandleFunc("/disable/", DisablePluginHandler) http.HandleFunc("/config/", ConfigPluginHandler) http.HandleFunc("/reload", ReloadPluginsHandler) http.HandleFunc("/api/plugins", APIPluginsHandler) // 启动Web服务器 log.Println("管理界面启动在 :8080...") log.Fatal(http.ListenAndServe(":8080", nil)) }