diff --git a/cmd/agent/main.go b/cmd/agent/main.go index 9e1421d..6a56e3b 100644 --- a/cmd/agent/main.go +++ b/cmd/agent/main.go @@ -237,23 +237,9 @@ func installService(cmd *cobra.Command, args []string) { // uninstallService 卸载服务 func uninstallService(cmd *cobra.Command, args []string) { - // 加载配置 - cfg, err := config.Load(configPath) - if err != nil { - log.Fatalf("❌ 加载配置失败: %v", err) + if err := service.UninstallAgent(configPath); err != nil { + log.Fatalf("❌ 卸载失败: %v", err) } - - // 创建服务管理器 - mgr, err := service.NewServiceManager(cfg) - if err != nil { - log.Fatalf("❌ 创建服务管理器失败: %v", err) - } - - // 卸载服务 - if err := mgr.Uninstall(); err != nil { - log.Fatalf("❌ 卸载服务失败: %v", err) - } - log.Println("✅ 服务卸载成功") } diff --git a/internal/handler/agent_handler.go b/internal/handler/agent_handler.go index b3ec974..9378ea4 100644 --- a/internal/handler/agent_handler.go +++ b/internal/handler/agent_handler.go @@ -713,8 +713,29 @@ func (h *AgentHandler) Delete(c echo.Context) error { return err } - // 如果探针在线,先断开连接 + // 如果探针在线,先发送卸载指令,然后断开连接 if client, exists := h.wsManager.GetClient(agentID); exists { + // 构建卸载消息 + uninstallMsg, err := json.Marshal(protocol.OutboundMessage{ + Type: protocol.MessageTypeUninstall, + Data: struct{}{}, // 空数据,卸载指令不需要额外参数 + }) + if err == nil { + // 发送卸载指令(忽略发送错误,继续删除流程) + if err := h.wsManager.SendToClient(agentID, uninstallMsg); err != nil { + h.logger.Warn("发送卸载指令失败", + zap.String("agentID", agentID), + zap.Error(err)) + } else { + h.logger.Info("已向探针发送卸载指令", + zap.String("agentID", agentID), + zap.String("name", agent.Name)) + // 等待一小段时间让探针处理卸载消息 + time.Sleep(500 * time.Millisecond) + } + } + + // 断开连接 client.Conn.Close() } diff --git a/internal/protocol/message.go b/internal/protocol/message.go index dadf299..150e15a 100644 --- a/internal/protocol/message.go +++ b/internal/protocol/message.go @@ -52,6 +52,7 @@ const ( MessageTypeHeartbeat MessageType = "heartbeat" MessageTypeCommand MessageType = "command" MessageTypeCommandResp MessageType = "command_response" + MessageTypeUninstall MessageType = "uninstall" // 指标消息 MessageTypeMetrics MessageType = "metrics" MessageTypeMonitorConfig MessageType = "monitor_config" diff --git a/pkg/agent/id/id.go b/pkg/agent/id/id.go index b4d3032..469c2b6 100644 --- a/pkg/agent/id/id.go +++ b/pkg/agent/id/id.go @@ -18,12 +18,12 @@ type Manager struct { // NewManager 创建 ID 管理器 func NewManager() *Manager { return &Manager{ - idFilePath: getIDFilePath(), + idFilePath: GetIDFilePath(), } } -// getIDFilePath 获取 ID 文件路径 -func getIDFilePath() string { +// GetIDFilePath 获取 ID 文件路径 +func GetIDFilePath() string { // 获取用户主目录 var homeDir = utils.GetSafeHomeDir() // 统一使用 ~/.pika/agent.id diff --git a/pkg/agent/service/agent.go b/pkg/agent/service/agent.go index 6ca3500..0e369c5 100644 --- a/pkg/agent/service/agent.go +++ b/pkg/agent/service/agent.go @@ -296,6 +296,8 @@ func (a *Agent) readLoop(conn *websocket.Conn, done chan struct{}) error { go a.handleTamperProtect(msg.Data) case protocol.MessageTypeDDNSConfig: go a.handleDDNSConfig(msg.Data) + case protocol.MessageTypeUninstall: + go a.handleUninstall() default: // 忽略其他类型 } @@ -829,3 +831,27 @@ func (a *Agent) getIPAddress(manager *collector.Manager, method, value string, i return "", fmt.Errorf("不支持的 IP 获取方式: %s", method) } } + +// handleUninstall 处理服务端发送的卸载指令 +func (a *Agent) handleUninstall() { + log.Println("📥 收到服务端卸载指令,开始执行卸载...") + + // 获取配置文件路径 + cfgPath := a.cfg.Path + if cfgPath == "" { + cfgPath = config.GetDefaultConfigPath() + } + + // 执行卸载操作 + if err := UninstallAgent(cfgPath); err != nil { + log.Printf("❌ 卸载失败: %v", err) + return + } + + log.Println("✅ 探针卸载成功,即将退出...") + + // 卸载成功后,触发停止信号 + if a.cancel != nil { + a.cancel() + } +} diff --git a/pkg/agent/service/service.go b/pkg/agent/service/service.go index 8638ca8..cbe4255 100644 --- a/pkg/agent/service/service.go +++ b/pkg/agent/service/service.go @@ -9,6 +9,7 @@ import ( "syscall" "github.com/dushixiang/pika/pkg/agent/config" + "github.com/dushixiang/pika/pkg/agent/id" "github.com/dushixiang/pika/pkg/agent/sysutil" "github.com/dushixiang/pika/pkg/agent/updater" "github.com/kardianos/service" @@ -235,3 +236,46 @@ func (m *ServiceManager) Run() error { return nil } + +// UninstallAgent 执行探针卸载操作(可被复用) +func UninstallAgent(cfgPath string) error { + // 加载配置 + cfg, err := config.Load(cfgPath) + if err != nil { + return fmt.Errorf("加载配置失败: %w", err) + } + + // 创建服务管理器 + mgr, err := NewServiceManager(cfg) + if err != nil { + return fmt.Errorf("创建服务管理器失败: %w", err) + } + + // 检查服务状态,如果在运行则停止 + status, err := mgr.Status() + if err != nil { + log.Printf("⚠️ 获取服务状态失败: %v", err) + } else if status != "已停止 (Stopped)" { + if err := mgr.Stop(); err != nil { + return fmt.Errorf("停止服务失败: %w", err) + } + } + + // 卸载服务 + if err := mgr.Uninstall(); err != nil { + return fmt.Errorf("卸载服务失败: %w", err) + } + + // 删除配置文件 + if err := os.Remove(cfgPath); err != nil { + log.Printf("⚠️ 删除配置文件失败: %v", err) + } + + // 删除探针 ID 文件 + idPath := id.GetIDFilePath() + if err := os.Remove(idPath); err != nil { + log.Printf("⚠️ 删除探针 ID 文件失败: %v", err) + } + + return nil +}