feat(api): 添加从商店安装插件功能
All checks were successful
Build Multi-Platform Binaries / build-frontend (push) Successful in 30s
Build Multi-Platform Binaries / build-binaries (amd64, darwin, server, false) (push) Successful in 50s
Build Multi-Platform Binaries / build-binaries (amd64, linux, client, true) (push) Successful in 49s
Build Multi-Platform Binaries / build-binaries (amd64, linux, server, true) (push) Successful in 58s
Build Multi-Platform Binaries / build-binaries (amd64, windows, client, true) (push) Successful in 45s
Build Multi-Platform Binaries / build-binaries (amd64, windows, server, true) (push) Successful in 57s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, client, true) (push) Successful in 51s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, server, true) (push) Successful in 1m7s
Build Multi-Platform Binaries / build-binaries (arm64, darwin, server, false) (push) Successful in 51s
Build Multi-Platform Binaries / build-binaries (arm64, linux, client, true) (push) Successful in 45s
Build Multi-Platform Binaries / build-binaries (arm64, linux, server, true) (push) Successful in 58s
Build Multi-Platform Binaries / build-binaries (arm64, windows, server, false) (push) Successful in 51s

- 添加 /store/install API 端点用于从商店安装插件
- 实现 StorePluginInstallRequest 请求结构体
- 添加 handleStoreInstall 处理函数实现插件下载和安装逻辑
- 在客户端视图中添加商店插件安装模态框和相关功能
- 在插件视图中添加商店插件安装按钮和安装到客户端功能
- 添加 installStorePlugin API 函数用于前端调用
- 实现客户端在线状态检查和插件安装流程
This commit is contained in:
Flik
2025-12-29 19:40:34 +08:00
parent ab81e08100
commit d4984c8d78
4 changed files with 241 additions and 6 deletions

View File

@@ -131,6 +131,7 @@ func RegisterRoutes(r *Router, app AppInterface) {
api.HandleFunc("/plugins", h.handlePlugins)
api.HandleFunc("/plugin/", h.handlePlugin)
api.HandleFunc("/store/plugins", h.handleStorePlugins)
api.HandleFunc("/store/install", h.handleStoreInstall)
api.HandleFunc("/client-plugin/", h.handleClientPlugin)
api.HandleFunc("/js-plugin/", h.handleJSPlugin)
api.HandleFunc("/js-plugins", h.handleJSPlugins)
@@ -582,6 +583,13 @@ type StorePluginInfo struct {
DownloadURL string `json:"download_url,omitempty"`
}
// StorePluginInstallRequest 从商店安装插件的请求
type StorePluginInstallRequest struct {
PluginName string `json:"plugin_name"`
DownloadURL string `json:"download_url"`
ClientID string `json:"client_id"`
}
// handleStorePlugins 处理扩展商店插件列表
func (h *APIHandler) handleStorePlugins(rw http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
@@ -625,6 +633,71 @@ func (h *APIHandler) handleStorePlugins(rw http.ResponseWriter, r *http.Request)
})
}
// handleStoreInstall 从商店安装插件到客户端
func (h *APIHandler) handleStoreInstall(rw http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(rw, "Method not allowed", http.StatusMethodNotAllowed)
return
}
var req StorePluginInstallRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(rw, err.Error(), http.StatusBadRequest)
return
}
if req.PluginName == "" || req.DownloadURL == "" || req.ClientID == "" {
http.Error(rw, "plugin_name, download_url and client_id required", http.StatusBadRequest)
return
}
// 检查客户端是否在线
online, _, _ := h.server.GetClientStatus(req.ClientID)
if !online {
http.Error(rw, "client not online", http.StatusBadRequest)
return
}
// 下载插件
client := &http.Client{Timeout: 30 * time.Second}
resp, err := client.Get(req.DownloadURL)
if err != nil {
http.Error(rw, "Failed to download plugin: "+err.Error(), http.StatusBadGateway)
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
http.Error(rw, "Plugin download failed with status: "+resp.Status, http.StatusBadGateway)
return
}
source, err := io.ReadAll(resp.Body)
if err != nil {
http.Error(rw, "Failed to read plugin: "+err.Error(), http.StatusInternalServerError)
return
}
// 安装到客户端
installReq := JSPluginInstallRequest{
PluginName: req.PluginName,
Source: string(source),
RuleName: req.PluginName,
AutoStart: true,
}
if err := h.server.InstallJSPluginToClient(req.ClientID, installReq); err != nil {
http.Error(rw, "Failed to install plugin: "+err.Error(), http.StatusInternalServerError)
return
}
h.jsonResponse(rw, map[string]interface{}{
"status": "ok",
"plugin": req.PluginName,
"client": req.ClientID,
})
}
// handleClientPlugin 处理客户端插件配置
// 路由: /api/client-plugin/{clientID}/{pluginName}/config
func (h *APIHandler) handleClientPlugin(rw http.ResponseWriter, r *http.Request) {