feat(ws): A3 WebSocket 统一连接管理 — 心跳/注册表/监控/优雅关闭

- 新增 pkg/wshub/manager.go 统一 WebSocket 连接管理器 (WSManager)
- 6 个 WebSocket handler 全部迁移: WebShell/kubectl/PodExec/Audit/Metrics/Pipeline
- 心跳机制: ping(30s) + pong handler + read deadline(60s) 自动检测死连接
- 连接注册表: 元数据(类型/用户/远程地址/连接时间/最后活跃)
- 每用户连接限制 MaxConnsPerUser=15 防资源耗尽
- 监控端点: GET /api/v1/ws/stats + GET /api/v1/ws/connections
- 优雅关闭: CloseAll() 发送 CloseGoingAway 帧并关闭所有连接
- 消除 3 个重复 websocket.Upgrader 变量统一为 WSManager 内部 upgrader
- 6/6 A3 测试通过, 17/17 回归测试通过
This commit is contained in:
attacker committed 2026-06-27 07:20:11 +08:00
1 parent 00a98e210d
commit e4f1018ca1
13 files changed
+508 -58

No files matched your search

+31 -6
View File
@@ -8,6 +8,7 @@ import (
"ezops/service"
ezredis "ezops/pkg/redis"
"ezops/pkg/toolinstaller"
"ezops/pkg/wshub"
"fmt"
"strconv"
@@ -62,9 +63,13 @@ func Register(r *gin.Engine, db *gorm.DB, log *zap.Logger, cfg *config.Config, c
})
})
// === A3: 统一 WebSocket 连接管理器 === // Logan.Li
// 所有 WebSocket handler 共享同一个 WSManager(心跳、连接注册、监控、优雅关闭)
wsMgr := wshub.New(wshub.DefaultConfig())
// WebSocket终端 (JWT 鉴权,支持 ?token= 查询参数;终端会话录制) // Logan.Li
auditHub := controller.NewAuditHub()
webShellHandler := controller.NewWebShellHandler(db, auditHub)
auditHub := controller.NewAuditHub(wsMgr)
webShellHandler := controller.NewWebShellHandler(db, auditHub, wsMgr)
r.GET("/ws/terminal", middleware.JWTAuth(&cfg.JWT, db), webShellHandler.Terminal)
// WebSocket 审计实时流 — 在线会话实时查看 // Logan.Li
@@ -92,11 +97,11 @@ func Register(r *gin.Engine, db *gorm.DB, log *zap.Logger, cfg *config.Config, c
// WebSocket 实时指标推送(JWT 鉴权) // Logan.Li
metricsHub := controller.NewMetricsHub()
metricsWSHandler := controller.NewMetricsWSHandler(metricsHub)
metricsWSHandler := controller.NewMetricsWSHandler(metricsHub, wsMgr)
r.GET("/ws/metrics", middleware.JWTAuth(&cfg.JWT, db), metricsWSHandler.ServeWS)
// WebSocket 流水线日志推流
wsLogHandler := controller.NewWSPipelineLogHandler(db, redisCache)
wsLogHandler := controller.NewWSPipelineLogHandler(db, redisCache, wsMgr)
r.GET("/ws/pipeline/:runId/log", wsLogHandler.StreamLog)
r.GET("/api/v1/pipelines/runs/:runId/log-stream", wsLogHandler.GetLogHistory)
@@ -106,7 +111,7 @@ func Register(r *gin.Engine, db *gorm.DB, log *zap.Logger, cfg *config.Config, c
r.GET("/api/v1/pipelines/runs/:runId/files/download", workspaceFilesHandler.DownloadFile)
// WebSocket K8s exec 交互终端 // Logan.Li
k8sHandler := controller.NewKubernetesHandler(db)
k8sHandler := controller.NewKubernetesHandler(db, wsMgr)
r.GET("/ws/kubernetes-exec/:id/namespaces/:namespace/pods/:podName", middleware.JWTAuth(&cfg.JWT, db), k8sHandler.ExecTerminal)
// ToolInstaller(工具懒加载服务 — kubectl/maven/node/helm)// Logan.Li
@@ -116,9 +121,29 @@ func Register(r *gin.Engine, db *gorm.DB, log *zap.Logger, cfg *config.Config, c
svcs := service.NewServices(db, redisCache, cfg.JWT.Secret)
// WebSocket kubectl 命令行终端 // Logan.Li
kubectlShellHandler := controller.NewKubectlShellHandler(db, ti)
kubectlShellHandler := controller.NewKubectlShellHandler(db, ti, wsMgr)
r.GET("/ws/kubectl", middleware.JWTAuth(&cfg.JWT, db), kubectlShellHandler.Terminal)
// === A3: WebSocket 连接监控端点 === // Logan.Li
wsAPI := api.Group("/ws", middleware.JWTAuth(&cfg.JWT, db))
{
// GET /api/v1/ws/connections — 列出所有活跃 WS 连接
wsAPI.GET("/connections", func(c *gin.Context) {
connections := wsMgr.ListConnections()
c.JSON(200, gin.H{
"code": 200,
"data": connections,
})
})
// GET /api/v1/ws/stats — 聚合统计(总数 + 按类型/用户分布)
wsAPI.GET("/stats", func(c *gin.Context) {
c.JSON(200, gin.H{
"code": 200,
"data": wsMgr.GetStats(),
})
})
}
// 公开路由
authHandler := controller.NewUserHandler(db, cfg)
api.POST("/auth/login", authHandler.Login)