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:
1 parent
00a98e210d
commit
e4f1018ca1
13 files changed
+508
-58
No files matched your search
@@ -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)
|
||||
|
||||
Reference in new issue
Block a user