package net import ( "net" "strconv" "cellbot/internal/engine" "cellbot/internal/protocol" "github.com/bytedance/sonic" "github.com/valyala/fasthttp" "go.uber.org/zap" ) // Server HTTP服务器 type Server struct { host string port int logger *zap.Logger botManager *protocol.BotManager eventBus *engine.EventBus wsManager *WebSocketManager server *fasthttp.Server } // NewServer 创建HTTP服务器 func NewServer(host string, port int, logger *zap.Logger, botManager *protocol.BotManager, eventBus *engine.EventBus) *Server { wsManager := NewWebSocketManager(logger, eventBus) return &Server{ host: host, port: port, logger: logger.Named("server"), botManager: botManager, eventBus: eventBus, wsManager: wsManager, } } // Start 启动服务器 func (s *Server) Start() error { s.server = &fasthttp.Server{ Handler: s.requestHandler, MaxConnsPerIP: 1000, MaxRequestsPerConn: 1000, ReadTimeout: 0, WriteTimeout: 0, IdleTimeout: 0, DisableKeepalive: false, } addr := net.JoinHostPort(s.host, strconv.Itoa(s.port)) s.logger.Info("Starting HTTP server", zap.String("address", addr)) go func() { if err := s.server.ListenAndServe(addr); err != nil { s.logger.Error("Server error", zap.Error(err)) } }() return nil } // Stop 停止服务器 func (s *Server) Stop() error { if s.server != nil { s.logger.Info("Stopping HTTP server") return s.server.Shutdown() } return nil } // requestHandler 请求处理器 func (s *Server) requestHandler(ctx *fasthttp.RequestCtx) { path := string(ctx.Path()) method := string(ctx.Method()) s.logger.Debug("Received request", zap.String("path", path), zap.String("method", method)) // 路由处理 switch path { case "/": s.handleRoot(ctx) case "/health": s.handleHealth(ctx) case "/bots": s.handleBots(ctx) case "/bots/create": s.handleCreateBot(ctx) case "/events/publish": s.handlePublishEvent(ctx) case "/events/subscribe": s.handleSubscribeEvent(ctx) default: ctx.Error("Not Found", fasthttp.StatusNotFound) } } // handleRoot 根路径处理 func (s *Server) handleRoot(ctx *fasthttp.RequestCtx) { ctx.SetContentType("application/json") ctx.SetBodyString(`{"message":"CellBot Server","version":"1.0.0"}`) } // handleHealth 健康检查 func (s *Server) handleHealth(ctx *fasthttp.RequestCtx) { ctx.SetContentType("application/json") ctx.SetBodyString(`{"status":"ok"}`) } // BotInfo 机器人信息结构 type BotInfo struct { ID string `json:"id"` Name string `json:"name"` Version string `json:"version"` Status string `json:"status"` SelfID string `json:"self_id"` Connected bool `json:"connected"` } // handleBots 获取机器人列表 func (s *Server) handleBots(ctx *fasthttp.RequestCtx) { bots := s.botManager.GetAll() ctx.SetContentType("application/json") // 构建机器人信息列表 botInfos := make([]BotInfo, 0, len(bots)) for _, bot := range bots { botInfos = append(botInfos, BotInfo{ ID: bot.GetID(), Name: bot.Name(), Version: bot.Version(), Status: string(bot.GetStatus()), SelfID: bot.GetSelfID(), Connected: bot.IsConnected(), }) } // 序列化为JSON response := map[string]interface{}{ "bots": botInfos, "count": len(botInfos), } data, err := sonic.Marshal(response) if err != nil { s.logger.Error("Failed to marshal bots response", zap.Error(err)) ctx.Error("Internal Server Error", fasthttp.StatusInternalServerError) return } ctx.SetBody(data) } // CreateBotRequest 创建机器人请求 type CreateBotRequest struct { ID string `json:"id"` Protocol string `json:"protocol"` Config map[string]interface{} `json:"config"` } // handleCreateBot 创建机器人 func (s *Server) handleCreateBot(ctx *fasthttp.RequestCtx) { if string(ctx.Method()) != "POST" { ctx.Error("Method Not Allowed", fasthttp.StatusMethodNotAllowed) return } ctx.SetContentType("application/json") // 解析请求体 var req CreateBotRequest if err := sonic.Unmarshal(ctx.PostBody(), &req); err != nil { s.logger.Error("Failed to parse create bot request", zap.Error(err)) response := map[string]interface{}{ "success": false, "error": "Invalid request body", } data, _ := sonic.Marshal(response) ctx.SetStatusCode(fasthttp.StatusBadRequest) ctx.SetBody(data) return } // 验证必需字段 if req.ID == "" { response := map[string]interface{}{ "success": false, "error": "Bot ID is required", } data, _ := sonic.Marshal(response) ctx.SetStatusCode(fasthttp.StatusBadRequest) ctx.SetBody(data) return } if req.Protocol == "" { response := map[string]interface{}{ "success": false, "error": "Protocol is required", } data, _ := sonic.Marshal(response) ctx.SetStatusCode(fasthttp.StatusBadRequest) ctx.SetBody(data) return } // 检查机器人是否已存在 if _, exists := s.botManager.Get(req.ID); exists { response := map[string]interface{}{ "success": false, "error": "Bot with this ID already exists", } data, _ := sonic.Marshal(response) ctx.SetStatusCode(fasthttp.StatusConflict) ctx.SetBody(data) return } // TODO: 根据协议类型创建相应的机器人实例 // 这里需要协议工厂来创建不同类型的机器人 // 目前返回成功但提示需要实现协议适配器 s.logger.Info("Bot creation requested", zap.String("bot_id", req.ID), zap.String("protocol", req.Protocol)) response := map[string]interface{}{ "success": true, "message": "Bot creation queued (protocol adapter implementation required)", "bot_id": req.ID, } data, _ := sonic.Marshal(response) ctx.SetStatusCode(fasthttp.StatusAccepted) ctx.SetBody(data) } // handlePublishEvent 发布事件 func (s *Server) handlePublishEvent(ctx *fasthttp.RequestCtx) { if string(ctx.Method()) != "POST" { ctx.Error("Method Not Allowed", fasthttp.StatusMethodNotAllowed) return } ctx.SetContentType("application/json") // 解析请求体为事件对象 var event protocol.BaseEvent if err := sonic.Unmarshal(ctx.PostBody(), &event); err != nil { s.logger.Error("Failed to parse event", zap.Error(err)) response := map[string]interface{}{ "success": false, "error": "Invalid event format", } data, _ := sonic.Marshal(response) ctx.SetStatusCode(fasthttp.StatusBadRequest) ctx.SetBody(data) return } // 验证事件类型 if event.Type == "" { response := map[string]interface{}{ "success": false, "error": "Event type is required", } data, _ := sonic.Marshal(response) ctx.SetStatusCode(fasthttp.StatusBadRequest) ctx.SetBody(data) return } // 如果没有时间戳,使用当前时间 if event.Timestamp == 0 { event.Timestamp = ctx.Time().Unix() } // 确保Data字段不为nil if event.Data == nil { event.Data = make(map[string]interface{}) } s.logger.Info("Publishing event", zap.String("type", string(event.Type)), zap.String("detail_type", event.DetailType), zap.String("self_id", event.SelfID)) // 发布到事件总线 s.eventBus.Publish(&event) response := map[string]interface{}{ "success": true, "message": "Event published successfully", "timestamp": event.Timestamp, } data, _ := sonic.Marshal(response) ctx.SetBody(data) } // handleSubscribeEvent 订阅事件(WebSocket升级) func (s *Server) handleSubscribeEvent(ctx *fasthttp.RequestCtx) { // 检查是否为WebSocket升级请求 if !ctx.IsGet() { ctx.Error("Method Not Allowed", fasthttp.StatusMethodNotAllowed) return } // 检查是否为WebSocket升级请求 if string(ctx.Request.Header.Peek("Upgrade")) != "websocket" { ctx.SetContentType("application/json") response := map[string]interface{}{ "success": false, "error": "WebSocket upgrade required", "message": "This endpoint requires WebSocket connection", } data, _ := sonic.Marshal(response) ctx.SetStatusCode(fasthttp.StatusBadRequest) ctx.SetBody(data) return } // 获取订阅者ID(可选) subscriberID := string(ctx.QueryArgs().Peek("subscriber_id")) if subscriberID == "" { subscriberID = "event-subscriber" } // 获取要订阅的事件类型(可选,为空则订阅所有类型) eventTypeStr := string(ctx.QueryArgs().Peek("event_type")) s.logger.Info("WebSocket event subscription request", zap.String("subscriber_id", subscriberID), zap.String("event_type", eventTypeStr), zap.String("remote_addr", ctx.RemoteAddr().String())) // 升级为WebSocket连接 wsConn, err := s.wsManager.UpgradeWebSocket(ctx) if err != nil { s.logger.Error("Failed to upgrade WebSocket", zap.Error(err)) ctx.SetContentType("application/json") response := map[string]interface{}{ "success": false, "error": "Failed to upgrade WebSocket connection", } data, _ := sonic.Marshal(response) ctx.SetStatusCode(fasthttp.StatusInternalServerError) ctx.SetBody(data) return } // 订阅所有主要事件类型 eventTypes := []protocol.EventType{ protocol.EventTypeMessage, protocol.EventTypeNotice, protocol.EventTypeRequest, protocol.EventTypeMeta, protocol.EventTypeMessageSent, protocol.EventTypeNoticeSent, protocol.EventTypeRequestSent, } // 如果指定了事件类型,只订阅该类型 if eventTypeStr != "" { eventTypes = []protocol.EventType{protocol.EventType(eventTypeStr)} } // 为每种事件类型创建订阅 for _, eventType := range eventTypes { eventChan := s.eventBus.Subscribe(eventType, nil) // nil filter means accept all events // 启动goroutine监听事件并发送到WebSocket go func(ch chan protocol.Event, et protocol.EventType) { for { select { case event, ok := <-ch: if !ok { return } // 序列化事件为JSON data, err := sonic.Marshal(event) if err != nil { s.logger.Error("Failed to marshal event", zap.Error(err)) continue } // 发送到WebSocket连接 if err := wsConn.SendMessage(data); err != nil { s.logger.Error("Failed to send event to WebSocket", zap.String("conn_id", wsConn.ID), zap.Error(err)) // 连接可能已断开,取消订阅 s.eventBus.Unsubscribe(et, ch) return } case <-wsConn.ctx.Done(): // 连接关闭,取消订阅 s.eventBus.Unsubscribe(et, ch) return } } }(eventChan, eventType) } s.logger.Info("WebSocket event subscription established", zap.String("conn_id", wsConn.ID), zap.String("subscriber_id", subscriberID)) }