package router import ( "database/sql" "net/http" "github.com/gin-gonic/gin" "github.com/yourname/cyrene-ai/gateway/internal/config" "github.com/yourname/cyrene-ai/gateway/internal/engine" "github.com/yourname/cyrene-ai/gateway/internal/handler" "github.com/yourname/cyrene-ai/gateway/internal/middleware" "github.com/yourname/cyrene-ai/gateway/internal/store" "github.com/yourname/cyrene-ai/gateway/internal/ws" ) // Setup 注册所有路由 func Setup(r *gin.Engine, hub *ws.Hub, cfg *config.Config, sessionStore *store.SessionStore, reminderStore *store.ReminderStore, briefingStore *store.BriefingStore, automationStore *store.AutomationStore, fileStore *store.FileStore, ruleEngine *engine.RuleEngine, knowledgeStore *store.KnowledgeStore, imageHandler *handler.ImageHandler, db interface{}, modelConfigStore *config.ModelsConfigStore) { // 限流器 rateLimiter := middleware.NewRateLimiter(10, 20) // 每秒10个请求,突发20 // 初始化处理器 var authDB *sql.DB if db != nil { authDB = db.(*sql.DB) } authHandler := handler.NewAuthHandler(cfg, authDB) sessionHandler := handler.NewSessionHandler(hub, sessionStore) memoryHandler := handler.NewMemoryHandler(cfg.MemoryServiceURL) chatHandler := handler.NewChatHandler(cfg, hub, sessionStore) webhookHandler := handler.NewWebhookHandler(cfg, hub) notificationHandler := handler.NewNotificationHandler(cfg, hub) reminderHandler := handler.NewReminderHandler(reminderStore, hub) briefingHandler := handler.NewBriefingHandler(cfg, hub, briefingStore, reminderStore) voiceHandler := handler.NewVoiceHandler(cfg.VoiceServiceURL) fileHandler := handler.NewFileHandler(fileStore) automationHandler := handler.NewAutomationHandler(automationStore, ruleEngine) knowledgeHandler := handler.NewKnowledgeHandler(knowledgeStore, fileStore) modelConfigHandler := handler.NewModelConfigHandler(modelConfigStore) if imageHandler == nil { imageHandler = handler.NewImageHandler(cfg, fileStore) } // ========== 公开路由 ========== api := r.Group("/api/v1") // 健康检查 api.GET("/health", func(c *gin.Context) { c.JSON(200, gin.H{ "status": "ok", "service": "cyrene-gateway", "ws_connections": hub.ClientCount(), }) }) // 认证路由专用限流器:每分钟每个IP每个端点最多5次请求(防暴力破解) authRateLimiter := middleware.NewRateLimiter(0.083, 5) // ~5 per minute per IP+endpoint // 认证 (无需JWT) auth := api.Group("/auth") { auth.POST("/register", authRateLimiter.HandlerWithKey(middleware.AuthIPKey("register")), authHandler.Register) auth.POST("/login", authRateLimiter.HandlerWithKey(middleware.AuthIPKey("login")), authHandler.Login) } // ========== 需要认证的路由 ========== protected := api.Group("") protected.Use(middleware.JWTAuth(cfg)) protected.Use(rateLimiter.Handler()) { // Token刷新 protected.POST("/auth/refresh", authHandler.RefreshToken) // 当前用户信息 protected.GET("/profile", authHandler.GetProfile) // 会话管理 sessions := protected.Group("/sessions") { sessions.POST("", sessionHandler.Create) // POST /api/v1/sessions sessions.GET("", sessionHandler.List) // GET /api/v1/sessions?user_id=xxx sessions.DELETE("", sessionHandler.DeleteAll) // DELETE /api/v1/sessions?user_id=xxx sessions.GET("/:id", sessionHandler.Get) // GET /api/v1/sessions/:id sessions.DELETE("/:id", sessionHandler.Delete) // DELETE /api/v1/sessions/:id sessions.GET("/:id/messages", sessionHandler.GetMessages) // GET /api/v1/sessions/:id/messages?limit=50 sessions.DELETE("/:id/messages", sessionHandler.ClearMessages) // DELETE /api/v1/sessions/:id/messages sessions.GET("/:id/export", sessionHandler.ExportSession) // GET /api/v1/sessions/:id/export?format=json|markdown|txt } // 消息搜索 protected.GET("/messages/search", sessionHandler.SearchMessages) // GET /api/v1/messages/search?q=xxx&user_id=xxx&limit=50&offset=0 // 记忆管理 memory := protected.Group("/memory") { memory.GET("/search", memoryHandler.Query) memory.GET("", memoryHandler.List) memory.POST("", memoryHandler.Add) memory.DELETE("", memoryHandler.Delete) } // 通知推送 (需要认证) notifications := protected.Group("/notifications") { notifications.POST("/push", notificationHandler.Push) } // 提醒管理 (需要认证) reminders := protected.Group("/reminders") { reminders.GET("", reminderHandler.List) // GET /api/v1/reminders?user_id=xxx&status=pending&limit=50 reminders.POST("", reminderHandler.Create) // POST /api/v1/reminders reminders.PUT("/:id", reminderHandler.Update) // PUT /api/v1/reminders/:id reminders.DELETE("/:id", reminderHandler.Delete) // DELETE /api/v1/reminders/:id } // 每日简报 (需要认证) briefings := protected.Group("/briefings") { briefings.GET("", briefingHandler.GetBriefing) // GET /api/v1/briefings?user_id=xxx&date=2024-01-01 briefings.GET("/latest", briefingHandler.GetLatestBriefings) // GET /api/v1/briefings/latest?user_id=xxx&limit=7 briefings.POST("/generate", briefingHandler.Generate) // POST /api/v1/briefings/generate } // 语音识别 + TTS (需要认证) voice := protected.Group("/voice") { voice.POST("/transcribe", voiceHandler.Transcribe) voice.POST("/tts", voiceHandler.TTSSynthesize) voice.GET("/tts/voices", voiceHandler.TTSVoices) voice.GET("/tts/status", voiceHandler.TTSStatus) voice.GET("/status", voiceHandler.VoiceStatus) } // 文件管理 (需要认证) files := protected.Group("/files") { files.POST("/upload", fileHandler.Upload) files.GET("", fileHandler.List) files.GET("/:id", fileHandler.Get) files.GET("/:id/download", fileHandler.Download) files.GET("/:id/thumbnail", fileHandler.Thumbnail) files.DELETE("/:id", fileHandler.Delete) } // 自动化 (需要认证) automation := protected.Group("/automation") { // 规则 rules := automation.Group("/rules") { rules.GET("", automationHandler.ListRules) // GET /api/v1/automation/rules rules.POST("", automationHandler.CreateRule) // POST /api/v1/automation/rules rules.GET("/:id", automationHandler.GetRule) // GET /api/v1/automation/rules/:id rules.PUT("/:id", automationHandler.UpdateRule) // PUT /api/v1/automation/rules/:id rules.DELETE("/:id", automationHandler.DeleteRule) // DELETE /api/v1/automation/rules/:id rules.POST("/:id/trigger", automationHandler.TriggerRule) // POST /api/v1/automation/rules/:id/trigger } // 场景 scenes := automation.Group("/scenes") { scenes.GET("", automationHandler.ListScenes) // GET /api/v1/automation/scenes scenes.POST("", automationHandler.CreateScene) // POST /api/v1/automation/scenes scenes.GET("/:id", automationHandler.GetScene) // GET /api/v1/automation/scenes/:id scenes.PUT("/:id", automationHandler.UpdateScene) // PUT /api/v1/automation/scenes/:id scenes.DELETE("/:id", automationHandler.DeleteScene) // DELETE /api/v1/automation/scenes/:id scenes.POST("/:id/execute", automationHandler.ExecuteScene) // POST /api/v1/automation/scenes/:id/execute } } // 知识库管理 (需要认证) knowledge := protected.Group("/knowledge") { // 知识库 CRUD knowledge.POST("/bases", knowledgeHandler.CreateKB) // POST /api/v1/knowledge/bases knowledge.GET("/bases", knowledgeHandler.ListKBs) // GET /api/v1/knowledge/bases knowledge.GET("/bases/:id", knowledgeHandler.GetKB) // GET /api/v1/knowledge/bases/:id knowledge.PUT("/bases/:id", knowledgeHandler.UpdateKB) // PUT /api/v1/knowledge/bases/:id knowledge.DELETE("/bases/:id", knowledgeHandler.DeleteKB) // DELETE /api/v1/knowledge/bases/:id // 文档管理 knowledge.POST("/bases/:id/documents", knowledgeHandler.AddDocument) // POST /api/v1/knowledge/bases/:id/documents knowledge.GET("/bases/:id/documents", knowledgeHandler.ListDocuments) // GET /api/v1/knowledge/bases/:id/documents knowledge.GET("/documents/:id", knowledgeHandler.GetDocument) // GET /api/v1/knowledge/documents/:id knowledge.DELETE("/documents/:id", knowledgeHandler.DeleteDocument) // DELETE /api/v1/knowledge/documents/:id // 搜索 knowledge.POST("/search", knowledgeHandler.Search) // POST /api/v1/knowledge/search } // 图片分析 (需要认证) images := protected.Group("/images") { images.POST("/analyze", imageHandler.Analyze) // POST /api/v1/images/analyze images.GET("/analyze/:file_id", imageHandler.AnalyzeByID) // GET /api/v1/images/analyze/:file_id } // Admin 路由 (需要管理员权限) admin := protected.Group("/admin") admin.Use(adminAuth()) { admin.GET("/sessions", sessionHandler.ListActiveSessions) admin.GET("/sessions/active", sessionHandler.GetActiveSessions) admin.GET("/sessions/:id", sessionHandler.GetSession) // 多端客户端管理 admin.GET("/clients", chatHandler.HandleListClients) admin.PUT("/clients/:id/note", chatHandler.HandleUpdateClientNote) // 模型配置管理 models := admin.Group("/models") { models.GET("/providers", modelConfigHandler.ListProviders) models.GET("/providers/:name", modelConfigHandler.GetProvider) models.POST("/providers/:name", modelConfigHandler.SetProvider) models.DELETE("/providers/:name", modelConfigHandler.DeleteProvider) models.GET("/models", modelConfigHandler.ListModels) models.GET("/models/:id", modelConfigHandler.GetModel) models.POST("/models/:id", modelConfigHandler.SetModel) models.DELETE("/models/:id", modelConfigHandler.DeleteModel) models.GET("/routing", modelConfigHandler.ListRouting) models.GET("/routing/:purpose", modelConfigHandler.GetRouting) models.POST("/routing/:purpose", modelConfigHandler.SetRouting) models.DELETE("/routing/:purpose", modelConfigHandler.DeleteRouting) models.POST("/health-check", modelConfigHandler.TestProvider) models.GET("/fetch-models/:name", modelConfigHandler.ProxyListModels) } } } // ========== 内部服务路由 (使用 Internal Service Token 认证) ========== internal := r.Group("/api/v1/internal") internal.Use(notificationHandler.InternalNotifyAuth()) { internal.POST("/notify", notificationHandler.InternalNotify) internal.POST("/proactive-message", chatHandler.HandleProactiveMessage) } // ========== WebSocket路由 ========== // WebSocket升级在HTTP层,token通过query参数或Header传递 wsGroup := r.Group("/ws") { wsGroup.GET("/chat", chatHandler.HandleWebSocket) } // ========== Webhook 路由(第三方平台接入) ========== webhook := r.Group("/api/v1/webhook") webhook.Use(webhookHandler.WebhookAuth()) { webhook.POST("/generic", webhookHandler.HandleGenericWebhook) webhook.POST("/discord", webhookHandler.HandleDiscordWebhook) } // ========== 静态文件服务 (生产环境) ========== if cfg.Env == "production" { r.Static("/assets", "./public/assets") r.StaticFile("/", "./public/index.html") r.NoRoute(func(c *gin.Context) { c.File("./public/index.html") }) } } // adminAuth 管理员权限中间件 (检查认证中间件设置的 is_admin 标记) func adminAuth() gin.HandlerFunc { return func(c *gin.Context) { isAdmin, _ := c.Get(middleware.IsAdminKey) if isAdmin == nil || !isAdmin.(bool) { c.JSON(http.StatusForbidden, gin.H{"error": "需要管理员权限"}) c.Abort() return } c.Next() } }