// Package handler provides HTTP handlers for various endpoints. package handler import ( "context" "errors" "fmt" "net/http" "modelRT/constants" "modelRT/database" "modelRT/diagram" "modelRT/logger" "modelRT/network" "modelRT/orm" "github.com/gin-gonic/gin" ) type linkSetConfig struct { CurrKey string PrevKeyTemplate string PrevIsNil bool } var linkSetConfigs = map[int]linkSetConfig{ // grid hierarchy 0: {CurrKey: constants.RedisAllGridSetKey, PrevIsNil: true}, // zone hierarchy 1: {CurrKey: constants.RedisAllZoneSetKey, PrevKeyTemplate: constants.RedisSpecGridZoneSetKey}, // station hierarchy 2: {CurrKey: constants.RedisAllStationSetKey, PrevKeyTemplate: constants.RedisSpecZoneStationSetKey}, // component nspath hierarchy 3: {CurrKey: constants.RedisAllCompNSPathSetKey, PrevKeyTemplate: constants.RedisSpecStationCompNSPATHSetKey}, // component tag hierarchy 4: {CurrKey: constants.RedisAllCompTagSetKey, PrevKeyTemplate: constants.RedisSpecStationCompTagSetKey}, // config hierarchy 5: {CurrKey: constants.RedisAllConfigSetKey, PrevIsNil: true}, } // DiagramNodeLinkHandler defines the diagram node link process api func DiagramNodeLinkHandler(c *gin.Context) { var request network.DiagramNodeLinkRequest clientToken := c.GetString("client_token") if clientToken == "" { err := constants.ErrGetClientToken logger.Error(c, "failed to get client token from context", "error", err) c.JSON(http.StatusOK, network.FailureResponse{ Code: http.StatusBadRequest, Msg: err.Error(), }) return } if err := c.ShouldBindJSON(&request); err != nil { logger.Error(c, "failed to unmarshal diagram node process request", "error", err) c.JSON(http.StatusOK, network.FailureResponse{ Code: http.StatusBadRequest, Msg: "invalid request body format: " + err.Error(), }) return } var err error pgClient := database.GetPostgresDBClient() nodeID := request.NodeID nodeLevel := request.NodeLevel action := request.Action prevNodeInfo, currNodeInfo, err := database.QueryNodeInfoByID(c, pgClient, nodeID, nodeLevel) if err != nil { logger.Error(c, "failed to query diagram node info by nodeID and level from postgres", "node_id", nodeID, "level", nodeLevel, "error", err) c.JSON(http.StatusOK, network.FailureResponse{ Code: http.StatusBadRequest, Msg: "failed to query measurement info record: " + err.Error(), Payload: map[string]any{ "node_id": nodeID, "node_level": nodeLevel, "action": action, }, }) return } prevLinkSet, currLinkSet := generateLinkSet(c, nodeLevel, prevNodeInfo) err = processLinkSetData(c, action, nodeLevel, prevLinkSet, currLinkSet, prevNodeInfo, currNodeInfo) if err != nil { c.JSON(http.StatusOK, network.FailureResponse{ Code: http.StatusBadRequest, Msg: err.Error(), Payload: map[string]any{ "node_id": nodeID, "node_level": nodeLevel, "action": action, }, }) return } logger.Info(c, "process diagram node link success", "node_id", nodeID, "level", nodeLevel, "action", request.Action) c.JSON(http.StatusOK, network.SuccessResponse{ Code: http.StatusOK, Msg: "diagram node link process success", Payload: map[string]any{ "node_id": nodeID, "node_level": nodeLevel, "action": action, }, }) } func generateLinkSet(ctx context.Context, level int, prevNodeInfo orm.CircuitDiagramNodeInterface) (*diagram.RedisSet, *diagram.RedisSet) { config, ok := linkSetConfigs[level] // level not supported if !ok { return nil, nil } currLinkSet := diagram.NewRedisSet(ctx, config.CurrKey, 0, false) if config.PrevIsNil { return nil, currLinkSet } prevLinkSetKey := fmt.Sprintf(config.PrevKeyTemplate, prevNodeInfo.GetTagName()) prevLinkSet := diagram.NewRedisSet(ctx, prevLinkSetKey, 0, false) return prevLinkSet, currLinkSet } func processLinkSetData(ctx context.Context, action string, level int, prevLinkSet, currLinkSet *diagram.RedisSet, prevNodeInfo, currNodeInfo orm.CircuitDiagramNodeInterface) error { var currMember string var prevMember string var err1, err2 error switch level { case 0, 1, 2, 4: // grid、zone、station、component tag hierarchy currMember = currNodeInfo.GetTagName() if prevLinkSet != nil { prevMember = prevNodeInfo.GetTagName() } case 3: // component NSPath hierarchy currMember = currNodeInfo.GetNSPath() prevMember = prevNodeInfo.GetTagName() case 5: // TODO[NONEED-ISSUE]暂无此层级增加或删除需求 #2 err := fmt.Errorf("currently hierarchy no need to add or delete this level: %d", level) logger.Error(ctx, "no need level for link process", "level", level, "action", action, "error", err) return nil default: err := fmt.Errorf("unsupported diagram node level: %d", level) logger.Error(ctx, "unsupport diagram node level for link process", "level", level, "action", action, "error", err) return err } switch action { case constants.SearchLinkAddAction: err1 = currLinkSet.SADD(currMember) if prevLinkSet != nil { err2 = prevLinkSet.SADD(prevMember) } case constants.SearchLinkDelAction: err1 = currLinkSet.SREM(currMember) if prevLinkSet != nil { err2 = prevLinkSet.SREM(prevMember) } default: err := constants.ErrUnsupportedLinkAction logger.Error(ctx, "unsupport diagram node link process action", "action", action, "error", err) return err } return processDiagramLinkError(err1, err2, action) } func processDiagramLinkError(err1, err2 error, action string) error { var err error if err1 != nil && err2 != nil { err = errors.Join(err1, err2) err = fmt.Errorf("process diagram node link failed, currLinkSet %s operation and prevLinkSet %s operation failed: %w", action, action, err) } else if err1 != nil { err = fmt.Errorf("process diagram node currLinkSet link failed: currLinkSet %s operation failed: %w", action, err1) } else { err = fmt.Errorf("process diagram node prevLinkSet link failed: prevLinkSet %s operation: %w", action, err2) } return err }