update
All checks were successful
Build Multi-Platform Binaries / build-frontend (push) Successful in 34s
Build Multi-Platform Binaries / build-binaries (amd64, darwin, server, false) (push) Successful in 5m6s
Build Multi-Platform Binaries / build-binaries (amd64, linux, client, true) (push) Successful in 1m39s
Build Multi-Platform Binaries / build-binaries (amd64, linux, server, true) (push) Successful in 5m8s
Build Multi-Platform Binaries / build-binaries (amd64, windows, client, true) (push) Successful in 2m45s
Build Multi-Platform Binaries / build-binaries (amd64, windows, server, true) (push) Successful in 5m50s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, client, true) (push) Successful in 2m20s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, server, true) (push) Successful in 4m25s
Build Multi-Platform Binaries / build-binaries (arm64, darwin, server, false) (push) Successful in 5m1s
Build Multi-Platform Binaries / build-binaries (arm64, linux, client, true) (push) Successful in 1m4s
Build Multi-Platform Binaries / build-binaries (arm64, linux, server, true) (push) Successful in 5m16s
Build Multi-Platform Binaries / build-binaries (arm64, windows, server, false) (push) Successful in 5m13s
All checks were successful
Build Multi-Platform Binaries / build-frontend (push) Successful in 34s
Build Multi-Platform Binaries / build-binaries (amd64, darwin, server, false) (push) Successful in 5m6s
Build Multi-Platform Binaries / build-binaries (amd64, linux, client, true) (push) Successful in 1m39s
Build Multi-Platform Binaries / build-binaries (amd64, linux, server, true) (push) Successful in 5m8s
Build Multi-Platform Binaries / build-binaries (amd64, windows, client, true) (push) Successful in 2m45s
Build Multi-Platform Binaries / build-binaries (amd64, windows, server, true) (push) Successful in 5m50s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, client, true) (push) Successful in 2m20s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, server, true) (push) Successful in 4m25s
Build Multi-Platform Binaries / build-binaries (arm64, darwin, server, false) (push) Successful in 5m1s
Build Multi-Platform Binaries / build-binaries (arm64, linux, client, true) (push) Successful in 1m4s
Build Multi-Platform Binaries / build-binaries (arm64, linux, server, true) (push) Successful in 5m16s
Build Multi-Platform Binaries / build-binaries (arm64, windows, server, false) (push) Successful in 5m13s
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -248,6 +249,8 @@ func (c *Client) handleStream(stream net.Conn) {
|
|||||||
go c.handleLogRequest(stream, msg)
|
go c.handleLogRequest(stream, msg)
|
||||||
case protocol.MsgTypeLogStop:
|
case protocol.MsgTypeLogStop:
|
||||||
c.handleLogStop(stream, msg)
|
c.handleLogStop(stream, msg)
|
||||||
|
case protocol.MsgTypePluginStatusQuery:
|
||||||
|
c.handlePluginStatusQuery(stream, msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -913,6 +916,30 @@ func restartClientProcess(path, serverAddr, token, id string) {
|
|||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handlePluginStatusQuery 处理插件状态查询
|
||||||
|
func (c *Client) handlePluginStatusQuery(stream net.Conn, msg *protocol.Message) {
|
||||||
|
defer stream.Close()
|
||||||
|
|
||||||
|
c.pluginMu.RLock()
|
||||||
|
plugins := make([]protocol.PluginStatusEntry, 0, len(c.runningPlugins))
|
||||||
|
for key := range c.runningPlugins {
|
||||||
|
// key 格式为 "pluginName:ruleName",只提取 pluginName
|
||||||
|
parts := strings.SplitN(key, ":", 2)
|
||||||
|
pluginName := parts[0]
|
||||||
|
plugins = append(plugins, protocol.PluginStatusEntry{
|
||||||
|
PluginName: pluginName,
|
||||||
|
Running: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
c.pluginMu.RUnlock()
|
||||||
|
|
||||||
|
resp := protocol.PluginStatusQueryResponse{
|
||||||
|
Plugins: plugins,
|
||||||
|
}
|
||||||
|
respMsg, _ := protocol.NewMessage(protocol.MsgTypePluginStatusQueryResp, resp)
|
||||||
|
protocol.WriteMessage(stream, respMsg)
|
||||||
|
}
|
||||||
|
|
||||||
// handleLogRequest 处理日志请求
|
// handleLogRequest 处理日志请求
|
||||||
func (c *Client) handleLogRequest(stream net.Conn, msg *protocol.Message) {
|
func (c *Client) handleLogRequest(stream net.Conn, msg *protocol.Message) {
|
||||||
if c.logger == nil {
|
if c.logger == nil {
|
||||||
|
|||||||
@@ -115,11 +115,39 @@ func (h *ClientHandler) Get(c *gin.Context) {
|
|||||||
|
|
||||||
online, lastPing, remoteAddr := h.app.GetServer().GetClientStatus(clientID)
|
online, lastPing, remoteAddr := h.app.GetServer().GetClientStatus(clientID)
|
||||||
|
|
||||||
|
// 复制插件列表
|
||||||
|
plugins := make([]db.ClientPlugin, len(client.Plugins))
|
||||||
|
copy(plugins, client.Plugins)
|
||||||
|
|
||||||
|
// 如果客户端在线,获取实时插件运行状态
|
||||||
|
if online {
|
||||||
|
if statusList, err := h.app.GetServer().GetClientPluginStatus(clientID); err == nil {
|
||||||
|
// 创建运行中插件的映射
|
||||||
|
runningPlugins := make(map[string]bool)
|
||||||
|
for _, s := range statusList {
|
||||||
|
runningPlugins[s.PluginName] = s.Running
|
||||||
|
}
|
||||||
|
// 更新插件状态
|
||||||
|
for i := range plugins {
|
||||||
|
if running, ok := runningPlugins[plugins[i].Name]; ok {
|
||||||
|
plugins[i].Running = running
|
||||||
|
} else {
|
||||||
|
plugins[i].Running = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 客户端离线时,所有插件都标记为未运行
|
||||||
|
for i := range plugins {
|
||||||
|
plugins[i].Running = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resp := dto.ClientResponse{
|
resp := dto.ClientResponse{
|
||||||
ID: client.ID,
|
ID: client.ID,
|
||||||
Nickname: client.Nickname,
|
Nickname: client.Nickname,
|
||||||
Rules: client.Rules,
|
Rules: client.Rules,
|
||||||
Plugins: client.Plugins,
|
Plugins: plugins,
|
||||||
Online: online,
|
Online: online,
|
||||||
LastPing: lastPing,
|
LastPing: lastPing,
|
||||||
RemoteAddr: remoteAddr,
|
RemoteAddr: remoteAddr,
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ type ServerInterface interface {
|
|||||||
// 日志流
|
// 日志流
|
||||||
StartClientLogStream(clientID, sessionID string, lines int, follow bool, level string) (<-chan protocol.LogEntry, error)
|
StartClientLogStream(clientID, sessionID string, lines int, follow bool, level string) (<-chan protocol.LogEntry, error)
|
||||||
StopClientLogStream(sessionID string)
|
StopClientLogStream(sessionID string)
|
||||||
|
// 插件状态查询
|
||||||
|
GetClientPluginStatus(clientID string) ([]protocol.PluginStatusEntry, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigField 配置字段
|
// ConfigField 配置字段
|
||||||
|
|||||||
@@ -574,6 +574,49 @@ func (s *Server) GetClientStatus(clientID string) (online bool, lastPing string,
|
|||||||
return false, "", ""
|
return false, "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetClientPluginStatus 获取客户端插件运行状态
|
||||||
|
func (s *Server) GetClientPluginStatus(clientID string) ([]protocol.PluginStatusEntry, error) {
|
||||||
|
s.mu.RLock()
|
||||||
|
cs, ok := s.clients[clientID]
|
||||||
|
s.mu.RUnlock()
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("client %s not online", clientID)
|
||||||
|
}
|
||||||
|
|
||||||
|
stream, err := cs.Session.Open()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer stream.Close()
|
||||||
|
|
||||||
|
// 发送查询请求
|
||||||
|
msg, err := protocol.NewMessage(protocol.MsgTypePluginStatusQuery, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := protocol.WriteMessage(stream, msg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取响应
|
||||||
|
resp, err := protocol.ReadMessage(stream)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Type != protocol.MsgTypePluginStatusQueryResp {
|
||||||
|
return nil, fmt.Errorf("unexpected response type: %d", resp.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
var statusResp protocol.PluginStatusQueryResponse
|
||||||
|
if err := resp.ParsePayload(&statusResp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return statusResp.Plugins, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetAllClientStatus 获取所有客户端状态
|
// GetAllClientStatus 获取所有客户端状态
|
||||||
func (s *Server) GetAllClientStatus() map[string]struct {
|
func (s *Server) GetAllClientStatus() map[string]struct {
|
||||||
Online bool
|
Online bool
|
||||||
|
|||||||
@@ -40,10 +40,12 @@ const (
|
|||||||
MsgTypePluginConfig uint8 = 25 // 插件配置同步
|
MsgTypePluginConfig uint8 = 25 // 插件配置同步
|
||||||
|
|
||||||
// 客户端插件消息
|
// 客户端插件消息
|
||||||
MsgTypeClientPluginStart uint8 = 40 // 启动客户端插件
|
MsgTypeClientPluginStart uint8 = 40 // 启动客户端插件
|
||||||
MsgTypeClientPluginStop uint8 = 41 // 停止客户端插件
|
MsgTypeClientPluginStop uint8 = 41 // 停止客户端插件
|
||||||
MsgTypeClientPluginStatus uint8 = 42 // 客户端插件状态
|
MsgTypeClientPluginStatus uint8 = 42 // 客户端插件状态
|
||||||
MsgTypeClientPluginConn uint8 = 43 // 客户端插件连接请求
|
MsgTypeClientPluginConn uint8 = 43 // 客户端插件连接请求
|
||||||
|
MsgTypePluginStatusQuery uint8 = 44 // 查询所有插件状态
|
||||||
|
MsgTypePluginStatusQueryResp uint8 = 45 // 插件状态查询响应
|
||||||
|
|
||||||
// JS 插件动态安装
|
// JS 插件动态安装
|
||||||
MsgTypeJSPluginInstall uint8 = 50 // 安装 JS 插件
|
MsgTypeJSPluginInstall uint8 = 50 // 安装 JS 插件
|
||||||
@@ -225,6 +227,17 @@ type ClientPluginConnRequest struct {
|
|||||||
RuleName string `json:"rule_name"` // 规则名称
|
RuleName string `json:"rule_name"` // 规则名称
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PluginStatusEntry 单个插件状态
|
||||||
|
type PluginStatusEntry struct {
|
||||||
|
PluginName string `json:"plugin_name"` // 插件名称
|
||||||
|
Running bool `json:"running"` // 是否运行中
|
||||||
|
}
|
||||||
|
|
||||||
|
// PluginStatusQueryResponse 插件状态查询响应
|
||||||
|
type PluginStatusQueryResponse struct {
|
||||||
|
Plugins []PluginStatusEntry `json:"plugins"` // 所有插件状态
|
||||||
|
}
|
||||||
|
|
||||||
// JSPluginInstallRequest JS 插件安装请求
|
// JSPluginInstallRequest JS 插件安装请求
|
||||||
type JSPluginInstallRequest struct {
|
type JSPluginInstallRequest struct {
|
||||||
PluginName string `json:"plugin_name"` // 插件名称
|
PluginName string `json:"plugin_name"` // 插件名称
|
||||||
|
|||||||
Reference in New Issue
Block a user