Răsfoiți Sursa

feat:增加服务端ws框架

Jerry Liang 1 an în urmă
părinte
comite
a2ba331afa

+ 11 - 14
service/controllers/auth.go

@@ -18,16 +18,13 @@ var (
 func Login(c *fiber.Ctx) error {
 	var body dto.LoginParam
 	if err := c.BodyParser(&body); err != nil {
-		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
-			"code":    400,
-			"message": "Invalid request body",
-		})
+		return Fail(c, "Invalid request body")
 	}
 
 	auth, err := services.Login(body)
 	if err != nil {
 		zap.L().Error("登录请求错误。", zap.String("err", err.Error()))
-		return JSONResponseNoData(c, 500, "Login error. (casdoor)")
+		return Error(c, "Login error. (casdoor)")
 	}
 
 	// 设置 HttpOnly cookie 保存 sid
@@ -41,33 +38,33 @@ func Login(c *fiber.Ctx) error {
 		Path:     "/fwh-toolbox/",
 	})
 
-	return JSONResponse(c, 0, "success", auth.AccessToken)
+	return Success(c, auth.AccessToken)
 }
 
 func GetSession(c *fiber.Ctx) error {
 	sid := c.Cookies(sessionCookieName)
 	if sid == "" {
-		return c.Status(403).JSON(fiber.Map{"error": "no session"})
+		return Forbidden(c, "no session")
 	}
 	res, err := services.GetSession(sid)
 	if err != nil {
 		zap.L().Error("读取会话信息失败。", zap.String("err", err.Error()))
-		return JSONResponseNoData(c, 403, "Get session error. (casdoor)")
+		return Forbidden(c, "Get session error. (casdoor)")
 	}
-	return JSONResponse(c, 0, "success", res)
+	return Success(c, res)
 }
 
 func RefreshToken(c *fiber.Ctx) error {
 	sid := c.Cookies(sessionCookieName)
 	if sid == "" {
-		return c.Status(403).JSON(fiber.Map{"error": "no session"})
+		return Forbidden(c, "no session")
 	}
 	res, err := services.RefreshToken(sid)
 	if err != nil {
 		zap.L().Error("刷新Token失败。", zap.String("err", err.Error()))
-		return JSONResponseNoData(c, 403, "Refresh token error. (casdoor)")
+		return Forbidden(c, "Refresh token error. (casdoor)")
 	}
-	return JSONResponse(c, 0, "success", res)
+	return Success(c, res)
 }
 
 func Logout(c *fiber.Ctx) error {
@@ -75,7 +72,7 @@ func Logout(c *fiber.Ctx) error {
 	err := services.Logout(sid)
 	if err != nil {
 		zap.L().Error("登出请求失败。", zap.String("err", err.Error()))
-		return JSONResponseNoData(c, 500, "Logout error. (casdoor)")
+		return Error(c, "Logout error. (casdoor)")
 	}
 
 	// 清除 cookie
@@ -88,5 +85,5 @@ func Logout(c *fiber.Ctx) error {
 		Path:     "/fwh-toolbox/",
 	})
 
-	return c.SendStatus(fiber.StatusNoContent)
+	return NoContent(c)
 }

+ 102 - 0
service/controllers/globalWebSocket.go

@@ -0,0 +1,102 @@
+package controllers
+
+import (
+	"encoding/json"
+	"fmt"
+	"time"
+
+	"github.com/gofiber/websocket/v2"
+	"github.com/google/uuid"
+	"go.uber.org/zap"
+)
+
+type WsHandler func(messageType int, p []byte) bool
+
+type Client struct {
+	ID   string
+	Conn *websocket.Conn
+}
+
+type MessageBody struct {
+	Type string
+	Data string
+}
+
+var clients = make(map[string]*Client)
+var handlers = make([]WsHandler, 0)
+
+func GlobalWebSocket(c *websocket.Conn) {
+	sid := c.Cookies("sid")
+	if sid == "" {
+		sid = uuid.New().String()
+	}
+	client := &Client{ID: sid, Conn: c}
+	clients[sid] = client
+	defer func() {
+		delete(clients, sid)
+		c.Close()
+	}()
+
+	fmt.Println("Client connected:", sid)
+
+	// 60 秒未收到任何 Pong/消息就判定断线
+	c.SetReadDeadline(time.Now().Add(60 * time.Second))
+	c.SetPongHandler(func(appData string) error {
+		fmt.Println("📡 收到 pong 响应")
+		c.SetReadDeadline(time.Now().Add(60 * time.Second))
+		return nil
+	})
+
+	// 启动心跳 goroutine
+	go func() {
+		ticker := time.NewTicker(30 * time.Second)
+		defer ticker.Stop()
+		for range ticker.C {
+			if err := c.WriteMessage(websocket.PingMessage, []byte("ping")); err != nil {
+				fmt.Println("❌ 发送 ping 失败,关闭连接:", err)
+				c.Close()
+				return
+			}
+			fmt.Println("🟢 发送 ping")
+		}
+	}()
+
+	for {
+		// 读取消息
+		msgType, msg, err := c.ReadMessage()
+		if err != nil {
+			zap.L().Error("GlobalWebSocket read err", zap.String("err", err.Error()))
+			break
+		}
+		fmt.Printf("[%s] recv: %s\n", sid, string(msg))
+
+		// 处理消息
+		for _, handler := range handlers {
+			ok := handler(msgType, msg)
+			if ok {
+				break
+			}
+		}
+	}
+}
+
+func sendGlobalWebSocketMessage(body MessageBody) {
+	for _, client := range clients {
+		if client == nil {
+			continue
+		}
+
+		payload, err := json.Marshal(body)
+		if err != nil {
+			zap.L().Error("json序列化失败", zap.String("err", err.Error()))
+			continue
+		}
+		client.Conn.WriteMessage(websocket.TextMessage, []byte(payload))
+	}
+}
+
+func RegisterGlobalWebSocketHandle(f WsHandler) {
+	handlers = append(handlers, f)
+}
+
+// 以下实现发送各种消息的接口

+ 104 - 13
service/controllers/response.go

@@ -24,39 +24,130 @@ type ResponseNoData struct {
 	Timestamp int64  `json:"timestamp"`
 }
 
-func JSONResponse[T any](c *fiber.Ctx, code int, message string, data T) error {
+// 成功返回 200
+func Success[T any](c *fiber.Ctx, data T, msg ...string) error {
+	message := "success"
+	if len(msg) > 0 {
+		message = msg[0]
+	}
+
 	traceId := c.Get(traceIdHeader) // 从请求头取
 	if traceId == "" {
 		traceId = uuid.New().String() // 没有就生成
+		// 设置到响应头,让前端也能拿到
+		c.Set(traceIdHeader, traceId)
 	}
 
-	// 设置到响应头,让前端也能拿到
-	c.Set(traceIdHeader, traceId)
-
-	resp := Response[T]{
-		Code:      code,
+	return c.Status(fiber.StatusOK).JSON(Response[T]{
+		Code:      0,
 		Message:   message,
 		Data:      data,
 		TraceID:   traceId,
 		Timestamp: time.Now().UnixMilli(),
+	})
+}
+
+// 失败返回 400
+func Fail(c *fiber.Ctx, msg string) error {
+	traceId := c.Get(traceIdHeader) // 从请求头取
+	if traceId == "" {
+		traceId = uuid.New().String() // 没有就生成
+		// 设置到响应头,让前端也能拿到
+		c.Set(traceIdHeader, traceId)
 	}
-	return c.JSON(resp)
+
+	return c.Status(fiber.StatusBadRequest).JSON(ResponseNoData{
+		Code:      1,
+		Message:   msg,
+		TraceID:   traceId,
+		Timestamp: time.Now().UnixMilli(),
+	})
+}
+
+// 401 未认证
+func Unauthorized(c *fiber.Ctx, msg ...string) error {
+	message := "unauthorized"
+	if len(msg) > 0 {
+		message = msg[0]
+	}
+
+	traceId := c.Get(traceIdHeader) // 从请求头取
+	if traceId == "" {
+		traceId = uuid.New().String() // 没有就生成
+		// 设置到响应头,让前端也能拿到
+		c.Set(traceIdHeader, traceId)
+	}
+
+	return c.Status(fiber.StatusUnauthorized).JSON(ResponseNoData{
+		Code:      401,
+		Message:   message,
+		TraceID:   traceId,
+		Timestamp: time.Now().UnixMilli(),
+	})
 }
 
-func JSONResponseNoData(c *fiber.Ctx, code int, message string) error {
+// 403 禁止访问
+func Forbidden(c *fiber.Ctx, msg ...string) error {
+	message := "forbidden"
+	if len(msg) > 0 {
+		message = msg[0]
+	}
+
 	traceId := c.Get(traceIdHeader) // 从请求头取
 	if traceId == "" {
 		traceId = uuid.New().String() // 没有就生成
+		// 设置到响应头,让前端也能拿到
+		c.Set(traceIdHeader, traceId)
 	}
 
-	// 设置到响应头,让前端也能拿到
-	c.Set(traceIdHeader, traceId)
+	return c.Status(fiber.StatusForbidden).JSON(ResponseNoData{
+		Code:      403,
+		Message:   message,
+		TraceID:   traceId,
+		Timestamp: time.Now().UnixMilli(),
+	})
+}
+
+// 404 或无数据
+func NotFound(c *fiber.Ctx, msg ...string) error {
+	message := "not found"
+	if len(msg) > 0 {
+		message = msg[0]
+	}
 
-	resp := ResponseNoData{
-		Code:      code,
+	traceId := c.Get(traceIdHeader) // 从请求头取
+	if traceId == "" {
+		traceId = uuid.New().String() // 没有就生成
+		// 设置到响应头,让前端也能拿到
+		c.Set(traceIdHeader, traceId)
+	}
+
+	return c.Status(fiber.StatusNotFound).JSON(ResponseNoData{
+		Code:      1,
 		Message:   message,
 		TraceID:   traceId,
 		Timestamp: time.Now().UnixMilli(),
+	})
+}
+
+// 空响应(204 No Content)
+func NoContent(c *fiber.Ctx) error {
+	return c.SendStatus(fiber.StatusNoContent)
+}
+
+// 服务器错误 500
+func Error(c *fiber.Ctx, msg string) error {
+	traceId := c.Get(traceIdHeader) // 从请求头取
+	if traceId == "" {
+		traceId = uuid.New().String() // 没有就生成
+		// 设置到响应头,让前端也能拿到
+		c.Set(traceIdHeader, traceId)
 	}
-	return c.JSON(resp)
+
+	return c.Status(fiber.StatusInternalServerError).JSON(ResponseNoData{
+		Code:      500,
+		Message:   msg,
+		TraceID:   traceId,
+		Timestamp: time.Now().UnixMilli(),
+	})
 }

+ 23 - 35
service/controllers/sitesAnalysisControllers.go

@@ -23,10 +23,7 @@ func GetSitesAnalysisList(c *fiber.Ctx) error {
 	sizeInt, _ := strconv.Atoi(c.Query("pageSize", "20"))
 
 	if pageInt <= 0 || sizeInt <= 0 {
-		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
-			"code":    400,
-			"message": "Invalid request para",
-		})
+		return Fail(c, "Invalid request para")
 	}
 
 	sn := c.Query("sn", "")
@@ -44,9 +41,9 @@ func GetSitesAnalysisList(c *fiber.Ctx) error {
 
 	listPage, err := services.GetSiteAnalysisManageList(uint(pageInt), uint(sizeInt), snP, progressP)
 	if err != nil {
-		return JSONResponseNoData(c, 500, "Database read failed. (MongoDb)")
+		return Error(c, "Database read failed. (MongoDb)")
 	}
-	return JSONResponse(c, 0, "success", listPage)
+	return Success(c, listPage)
 }
 
 // 创建一个分析配置
@@ -54,16 +51,13 @@ func GetSitesAnalysisList(c *fiber.Ctx) error {
 func CreateSitesAnalysis(c *fiber.Ctx) error {
 	var body domain.SiteAnalysisConfigWrite
 	if err := c.BodyParser(&body); err != nil {
-		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
-			"code":    400,
-			"message": "Invalid request body",
-		})
+		return Fail(c, "Invalid request body")
 	}
 
 	if err := services.InsertSiteAnalysisConfig(body); err != nil {
-		return JSONResponseNoData(c, 500, "Database write failed. (MongoDb)")
+		return Error(c, "Database write failed. (MongoDb)")
 	}
-	return JSONResponse(c, 0, "success", body)
+	return Success(c, body)
 }
 
 // 获取单个分析配置
@@ -73,14 +67,14 @@ func GetOneSiteAnalysisConfig(c *fiber.Ctx) error {
 
 	objID, err := primitive.ObjectIDFromHex(id)
 	if err != nil {
-		return JSONResponseNoData(c, 400, "Invalid request para :id")
+		return Fail(c, "Invalid request para :id")
 	}
 
 	config, err := services.GetSiteAnalysisConfig(objID)
 	if err != nil {
-		return JSONResponseNoData(c, 500, "Database read failed. (MongoDb)")
+		return Error(c, "Database read failed. (MongoDb)")
 	}
-	return JSONResponse(c, 0, "success", config)
+	return Success(c, config)
 }
 
 // 更新一个分析配置
@@ -89,21 +83,18 @@ func UpdateOneSiteAnalysisConfig(c *fiber.Ctx) error {
 	id := c.Params("id")
 	var body domain.SiteAnalysisConfigWrite
 	if err := c.BodyParser(&body); err != nil {
-		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
-			"code":    400,
-			"message": "Invalid request body",
-		})
+		return Fail(c, "Invalid request body")
 	}
 
 	objID, err := primitive.ObjectIDFromHex(id)
 	if err != nil {
-		return JSONResponseNoData(c, 400, "Invalid request para :id")
+		return Fail(c, "Invalid request para :id")
 	}
 
 	if err := services.UpdateSiteAnalysisConfig(objID, body); err != nil {
-		return JSONResponseNoData(c, 500, "Database write failed. (MongoDb)")
+		return Error(c, "Database write failed. (MongoDb)")
 	}
-	return JSONResponse(c, 0, "success", body)
+	return Success(c, body)
 }
 
 // 更新一个分析配置
@@ -112,21 +103,18 @@ func UpdateOneSiteAnalysisDescription(c *fiber.Ctx) error {
 	id := c.Params("id")
 	var body string
 	if err := c.BodyParser(&body); err != nil {
-		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
-			"code":    400,
-			"message": "Invalid request body",
-		})
+		return Fail(c, "Invalid request body")
 	}
 
 	objID, err := primitive.ObjectIDFromHex(id)
 	if err != nil {
-		return JSONResponseNoData(c, 400, "Invalid request para :id")
+		return Fail(c, "Invalid request para :id")
 	}
 
 	if err := services.UpdateSiteAnalysisDescription(objID, body); err != nil {
-		return JSONResponseNoData(c, 500, "Database write failed. (MongoDb)")
+		return Error(c, "Database write failed. (MongoDb)")
 	}
-	return JSONResponse(c, 0, "success", body)
+	return Success(c, body)
 }
 
 // 删除一个分析数据
@@ -136,14 +124,14 @@ func DeleteOneSiteAnalysis(c *fiber.Ctx) error {
 
 	objID, err := primitive.ObjectIDFromHex(id)
 	if err != nil {
-		return JSONResponseNoData(c, 400, "Invalid request para :id")
+		return Fail(c, "Invalid request para :id")
 	}
 
 	err = services.DeleteSiteAnalysisConfig(objID)
 	if err != nil {
-		return JSONResponseNoData(c, 500, "Database delete failed. (MongoDb)")
+		return Error(c, "Database delete failed. (MongoDb)")
 	}
-	return JSONResponseNoData(c, 0, "success")
+	return NoContent(c)
 }
 
 // 获取指定ID的分析数据
@@ -153,12 +141,12 @@ func GetOneSiteAnalysisData(c *fiber.Ctx) error {
 
 	objID, err := primitive.ObjectIDFromHex(id)
 	if err != nil {
-		return JSONResponseNoData(c, 400, "Invalid request para :id")
+		return Fail(c, "Invalid request para :id")
 	}
 
 	data, err := services.GetSiteAnalysisData(objID)
 	if err != nil {
-		return JSONResponseNoData(c, 500, "Database read failed. (MongoDb)")
+		return Error(c, "Database read failed. (MongoDb)")
 	}
-	return JSONResponse(c, 0, "success", data)
+	return Success(c, data)
 }

+ 30 - 42
service/controllers/sitesMonitorControllers.go

@@ -16,9 +16,9 @@ func GetSitesMonitorNameList(c *fiber.Ctx) error {
 	names, err := services.GetSiteMonitorNameList()
 	if err != nil {
 		zap.L().Error("查询站点监控管理名称表错误。", zap.String("err", err.Error()))
-		return JSONResponseNoData(c, 500, "Database read failed. (MongoDb)")
+		return Error(c, "Database read failed. (MongoDb)")
 	}
-	return JSONResponse(c, 0, "success", names)
+	return Success(c, names)
 }
 
 // 获取单个监控配置
@@ -28,11 +28,11 @@ func GetSitesMonitorConfig(c *fiber.Ctx) error {
 	configList, err := services.GetOneSiteMonitorConfig(name)
 	if err != nil {
 		zap.L().Error("查询单个监控配置错误。", zap.String("err", err.Error()))
-		return JSONResponseNoData(c, 500, "Database read failed. (MongoDb)")
+		return Error(c, "Database read failed. (MongoDb)")
 	} else if len(configList) != 1 {
-		return JSONResponseNoData(c, 204, "User not found")
+		return Success(c, []domain.SitesMonitorConfig{})
 	}
-	return JSONResponse(c, 0, "success", configList[0])
+	return Success(c, configList[0])
 }
 
 // 更新一个监控配置
@@ -41,17 +41,14 @@ func UpdateSitesMonitorConfig(c *fiber.Ctx) error {
 	name := c.Params("name")
 	var body domain.SitesMonitorConfig
 	if err := c.BodyParser(&body); err != nil {
-		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
-			"code":    400,
-			"message": "Invalid request body",
-		})
+		return Fail(c, "Invalid request body")
 	}
 	err := services.UpdateSiteMonitorConfig(name, body)
 	if err != nil {
 		zap.L().Error("更新一个监控配置错误。", zap.String("err", err.Error()))
-		return JSONResponseNoData(c, 500, "Database write failed. (MongoDb)")
+		return Error(c, "Database write failed. (MongoDb)")
 	}
-	return JSONResponse(c, 0, "success", body)
+	return Success(c, body)
 }
 
 // 更新一个监控页面配置
@@ -60,17 +57,14 @@ func UpdateSitesMonitorPageConfig(c *fiber.Ctx) error {
 	name := c.Params("name")
 	var body domain.MonitorPageConfig
 	if err := c.BodyParser(&body); err != nil {
-		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
-			"code":    400,
-			"message": "Invalid request body",
-		})
+		return Fail(c, "Invalid request body")
 	}
 	err := services.UpdateSiteMonitorPageConfig(name, body)
 	if err != nil {
 		zap.L().Error("更新一个监控页面配置错误。", zap.String("err", err.Error()))
-		return JSONResponseNoData(c, 500, "Database write failed. (MongoDb)")
+		return Error(c, "Database write failed. (MongoDb)")
 	}
-	return JSONResponse(c, 0, "success", body)
+	return Success(c, body)
 }
 
 // 删除一个监控
@@ -80,9 +74,9 @@ func DeleteSitesMonitorConfig(c *fiber.Ctx) error {
 	err := services.DeleteSiteMonitorConfig(name)
 	if err != nil {
 		zap.L().Error("删除一个监控错误。", zap.String("err", err.Error()))
-		return JSONResponseNoData(c, 500, "Database delete failed. (MongoDb)")
+		return Error(c, "Database delete failed. (MongoDb)")
 	}
-	return JSONResponseNoData(c, 0, "success")
+	return NoContent(c)
 }
 
 // 获取所有监控配置
@@ -91,9 +85,9 @@ func GetSitesMonitorAllConfig(c *fiber.Ctx) error {
 	configList, err := services.GetSiteMonitorConfig()
 	if err != nil {
 		zap.L().Error("查询所有监控配置错误。", zap.String("err", err.Error()))
-		return JSONResponseNoData(c, 500, "Database read failed. (MongoDb)")
+		return Error(c, "Database read failed. (MongoDb)")
 	}
-	return JSONResponse(c, 0, "success", configList)
+	return Success(c, configList)
 }
 
 // 创建一个监控配置
@@ -101,17 +95,14 @@ func GetSitesMonitorAllConfig(c *fiber.Ctx) error {
 func CreateSitesMonitorConfig(c *fiber.Ctx) error {
 	var body domain.SitesMonitorConfig
 	if err := c.BodyParser(&body); err != nil {
-		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
-			"code":    400,
-			"message": "Invalid request body",
-		})
+		return Fail(c, "Invalid request body")
 	}
 	err := services.InsertSiteMonitorConfig(body)
 	if err != nil {
 		zap.L().Error("创建一个监控配置错误。", zap.String("err", err.Error()))
-		return JSONResponseNoData(c, 500, "Database write failed. (MongoDb)")
+		return Error(c, "Database write failed. (MongoDb)")
 	}
-	return JSONResponse(c, 0, "success", body)
+	return Success(c, body)
 }
 
 // 批量获取站点信息表
@@ -119,17 +110,14 @@ func CreateSitesMonitorConfig(c *fiber.Ctx) error {
 func GetSiteInfoList(c *fiber.Ctx) error {
 	var body dto.SiteBaseInfoPara
 	if err := c.BodyParser(&body); err != nil {
-		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
-			"code":    400,
-			"message": "Invalid request body",
-		})
+		return Fail(c, "Invalid request body")
 	}
 	infoList, err := services.QuerySiteBaseInfoList(body)
 	if err != nil {
 		zap.L().Error("查询批量站点信息表错误。", zap.String("err", err.Error()))
-		return JSONResponseNoData(c, 500, "Database write failed. (MongoDb)")
+		return Error(c, "Database write failed. (MongoDb)")
 	}
-	return JSONResponse(c, 0, "success", infoList)
+	return Success(c, infoList)
 }
 
 // 获取单个站点信息
@@ -143,9 +131,9 @@ func GetOneSiteInfo(c *fiber.Ctx) error {
 	})
 	if err != nil {
 		zap.L().Error("查询单个站点信息错误。", zap.String("err", err.Error()))
-		return JSONResponseNoData(c, 500, "fwh_pro query failed.")
+		return Error(c, "fwh_pro query failed.")
 	}
-	return JSONResponse(c, 0, "success", siteInfo)
+	return Success(c, siteInfo)
 }
 
 // 获取单个站点工作模式信息
@@ -155,9 +143,9 @@ func GetOneSiteModeInfo(c *fiber.Ctx) error {
 	siteModeInfo, err := services.QuerySiteModeInfo(site)
 	if err != nil {
 		zap.L().Error("查询单个站点工作模式信息错误。", zap.String("err", err.Error()))
-		return JSONResponseNoData(c, 500, "fwh_pro query failed.")
+		return Error(c, "fwh_pro query failed.")
 	}
-	return JSONResponse(c, 0, "success", siteModeInfo)
+	return Success(c, siteModeInfo)
 }
 
 // 获取单个站点功率流
@@ -168,15 +156,15 @@ func GetOneSitePowerFlow(c *fiber.Ctx) error {
 	dayTime, err := time.Parse(time.DateOnly, day)
 	if err != nil {
 		zap.L().Error("查询单个站点功率流参数错误。(day)", zap.String("err", err.Error()))
-		return JSONResponseNoData(c, 500, "day parament error.")
+		return Error(c, "day parament error.")
 	}
 
 	sitePowerFlow, err := services.QuerySitePowerFlow(site, dayTime)
 	if err != nil {
 		zap.L().Error("查询单个站点功率流错误。", zap.String("err", err.Error()))
-		return JSONResponseNoData(c, 500, "fwh_pro query failed.")
+		return Error(c, "fwh_pro query failed.")
 	}
-	return JSONResponse(c, 0, "success", sitePowerFlow)
+	return Success(c, sitePowerFlow)
 }
 
 // 获取单个站点告警列表
@@ -187,7 +175,7 @@ func GetOneSiteAlarmList(c *fiber.Ctx) error {
 	siteAlarmList, err := services.QuerySiteAlarmList(site)
 	if err != nil {
 		zap.L().Error("查询单个站点告警列表错误。", zap.String("err", err.Error()))
-		return JSONResponseNoData(c, 500, "fwh_pro query failed.")
+		return Error(c, "fwh_pro query failed.")
 	}
-	return JSONResponse(c, 0, "success", siteAlarmList)
+	return Success(c, siteAlarmList)
 }

+ 5 - 11
service/controllers/xlogControllers.go

@@ -15,14 +15,11 @@ func GetXlogManageSiteList(c *fiber.Ctx) error {
 	sizeInt, _ := strconv.Atoi(c.Query("pageSize", "20"))
 
 	if pageInt <= 0 || sizeInt <= 0 {
-		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
-			"code":    400,
-			"message": "Invalid request para",
-		})
+		return Fail(c, "Invalid request para")
 	}
 
 	listPage := services.GetXlogManageList(uint(pageInt), uint(sizeInt))
-	return JSONResponse(c, 0, "success", listPage)
+	return Success(c, listPage)
 }
 
 // 发送命令
@@ -32,15 +29,12 @@ func PostXlogTerminalSend(c *fiber.Ctx) error {
 	logger.Std.Println(uuid)
 	var body string
 	if err := c.BodyParser(&body); err != nil {
-		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
-			"code":    400,
-			"message": "Invalid request body",
-		})
+		return Fail(c, "Invalid request body")
 	}
 
 	data, err := services.SendXlogCmd(uuid, body)
 	if err != nil {
-		return JSONResponseNoData(c, 500, err.Error())
+		return Error(c, err.Error())
 	}
-	return JSONResponse(c, 0, "success", data)
+	return Success(c, data)
 }

BIN
service/fwh-toolbox-server


+ 3 - 0
service/go.mod

@@ -35,6 +35,7 @@ require (
 	github.com/andybalholm/brotli v1.1.0 // indirect
 	github.com/cespare/xxhash/v2 v2.3.0 // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
+	github.com/fasthttp/websocket v1.5.3 // indirect
 	github.com/fsnotify/fsnotify v1.8.0 // indirect
 	github.com/go-openapi/jsonpointer v0.19.5 // indirect
 	github.com/go-openapi/jsonreference v0.19.6 // indirect
@@ -42,6 +43,7 @@ require (
 	github.com/go-openapi/swag v0.19.15 // indirect
 	github.com/go-sql-driver/mysql v1.9.3 // indirect
 	github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
+	github.com/gofiber/websocket/v2 v2.2.1 // indirect
 	github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
 	github.com/golang/snappy v0.0.4 // indirect
 	github.com/jackc/pgpassfile v1.0.0 // indirect
@@ -61,6 +63,7 @@ require (
 	github.com/pelletier/go-toml/v2 v2.2.3 // indirect
 	github.com/rivo/uniseg v0.2.0 // indirect
 	github.com/sagikazarmark/locafero v0.7.0 // indirect
+	github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
 	github.com/sourcegraph/conc v0.3.0 // indirect
 	github.com/spf13/afero v1.12.0 // indirect
 	github.com/spf13/cast v1.7.1 // indirect

+ 6 - 0
service/go.sum

@@ -24,6 +24,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/fasthttp/websocket v1.5.3 h1:TPpQuLwJYfd4LJPXvHDYPMFWbLjsT91n3GpWtCQtdek=
+github.com/fasthttp/websocket v1.5.3/go.mod h1:46gg/UBmTU1kUaTcwQXpUxtRwG2PvIZYeA8oL6vF3Fs=
 github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
 github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
 github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
@@ -46,6 +48,8 @@ github.com/gofiber/fiber/v2 v2.52.9 h1:YjKl5DOiyP3j0mO61u3NTmK7or8GzzWzCFzkboyP5
 github.com/gofiber/fiber/v2 v2.52.9/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
 github.com/gofiber/swagger v1.1.1 h1:FZVhVQQ9s1ZKLHL/O0loLh49bYB5l1HEAgxDlcTtkRA=
 github.com/gofiber/swagger v1.1.1/go.mod h1:vtvY/sQAMc/lGTUCg0lqmBL7Ht9O7uzChpbvJeJQINw=
+github.com/gofiber/websocket/v2 v2.2.1 h1:C9cjxvloojayOp9AovmpQrk8VqvVnT8Oao3+IUygH7w=
+github.com/gofiber/websocket/v2 v2.2.1/go.mod h1:Ao/+nyNnX5u/hIFPuHl28a+NIkrqK7PRimyKaj4JxVU=
 github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
 github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
 github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
@@ -118,6 +122,8 @@ github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZV
 github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
 github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
 github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
+github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
+github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
 github.com/sigurn/crc16 v0.0.0-20240131213347-83fcde1e29d1 h1:NVK+OqnavpyFmUiKfUMHrpvbCi2VFoWTrcpI7aDaJ2I=
 github.com/sigurn/crc16 v0.0.0-20240131213347-83fcde1e29d1/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA=
 github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=

+ 17 - 0
service/routes/globalWebSocketRoutes.go

@@ -0,0 +1,17 @@
+/*
+ * Global WebSocket
+ * /ws/:id - 全局ws
+ */
+package routes
+
+import (
+	"fwh-toolbox-server/controllers"
+
+	"github.com/gofiber/fiber/v2"
+	"github.com/gofiber/websocket/v2"
+)
+
+func GlobalWebSocketSetup(api fiber.Router) {
+	// 全局ws
+	api.Get("/ws/global/:id", websocket.New(controllers.GlobalWebSocket))
+}

+ 1 - 0
service/routes/routes.go

@@ -15,6 +15,7 @@ func Setup(app *fiber.App) {
 	api := app.Group("/api", middleware.AuthMiddleware())
 
 	LogoutSetup(api)
+	GlobalWebSocketSetup(api)
 
 	// api.Get("/keyAccounts/sunrun/state", controllers.GetUsers)
 	// api.Get("/keyAccounts/sunrun/abnormalList", controllers.GetUsers)