package event import ( "encoding/json" "fmt" "net/http" "strings" "time" "be.ems/lib/config" "be.ems/lib/core/ctx" "be.ems/lib/log" "be.ems/lib/services" "be.ems/src/framework/database/db" "be.ems/src/framework/utils/date" "be.ems/src/framework/utils/parse" neService "be.ems/src/modules/network_element/service" wsService "be.ems/src/modules/ws/service" "github.com/gin-gonic/gin" ) var ( // 走Gin UriUEEventAMF = "/upload-ue/v1/:eventType" // 走Mux UriUEEvent = config.DefaultUriPrefix + "/logManagement/v1/elementType/{elementTypeValue}/objectType/ueEvent" CustomUriUEEvent = config.UriPrefix + "/logManagement/v1/elementType/{elementTypeValue}/objectType/ueEvent" ) // 旧AMF上报处理 func PostUEEventFromAMF(c *gin.Context) { log.Info("PostUEEventFromAMF processing... ") eventType := c.Param("eventType") if eventType == "" { log.Error("eventType is empty") services.ResponseNotFound404UriNotExist(c.Writer, c.Request) return } var body map[string]any if err := c.ShouldBindBodyWithJSON(&body); err != nil { log.Error("Failed to Unmarshal ueEvent:", err) services.ResponseInternalServerError500ProcessError(c.Writer, err) return } // 执行插入表 type UEEvent struct { ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` NeType string `json:"neType" gorm:"column:ne_type"` NeName string `json:"neName" gorm:"column:ne_name"` RmUID string `json:"rmUID" gorm:"column:rm_uid"` // 可能没有 Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到的timestamp秒级存储毫秒时间戳 EventType string `json:"eventType" gorm:"column:event_type"` // 事件类型 auth-result detach cm-state EventJSONStr string `json:"eventJSON" gorm:"column:event_json"` // data JSON String CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 记录创建存储毫秒 } timestamp := time.Now().UnixMilli() data := UEEvent{ NeType: "AMF", NeName: "", RmUID: "", Timestamp: timestamp, EventType: eventType, EventJSONStr: "", CreatedAt: timestamp, } // 从eventJson中获取rmUID if v, ok := body["rmUID"]; ok { data.RmUID = fmt.Sprint(v) } else { data.RmUID = "4400HXAMF001" } if v, ok := body["neName"]; ok { data.NeName = fmt.Sprint(v) } else { data.NeName = "AMF_001" } // 是否存在网元 neInfo := neService.NewNeInfo.FindByRmuid(data.RmUID) if neInfo.NeType != "AMF" || neInfo.RmUID != data.RmUID { services.ResponseInternalServerError500ProcessError(c.Writer, fmt.Errorf("network element does not exist")) return } // 统一格式 eventJson := map[string]any{"cellID": 0, "gNBID": "", "imsi": "", "onlineNumber": 0, "result": "", "tacID": 0, "timestamp": 0, "time": 0, "type": eventType} switch eventType { case "auth-result": // {"authCode":"200","authMessage":"成功","authTime":"2024-12-07 16:48:37","cellID":"3","gNBID":"1","imsi":"460002082100000","onlineNumber":1,"tacID":"81"} if v, ok := body["imsi"]; ok { eventJson["imsi"] = fmt.Sprint(v) } if v, ok := body["cellID"]; ok { eventJson["cellID"] = fmt.Sprint(v) } if v, ok := body["gNBID"]; ok { eventJson["gNBID"] = fmt.Sprint(v) } if v, ok := body["tacID"]; ok { eventJson["tacID"] = fmt.Sprint(v) } if v, ok := body["onlineNumber"]; ok { eventJson["onlineNumber"] = parse.Number(v) } if v, ok := body["authCode"]; ok { eventJson["result"] = fmt.Sprint(v) } if v, ok := body["authTime"]; ok { authTime := date.ParseStrToDate(fmt.Sprint(v), date.YYYY_MM_DD_HH_MM_SS) eventJson["timestamp"] = authTime.Unix() eventJson["time"] = fmt.Sprint(v) } case "detach": // {"detachResult":0,"detachTime":"2024-12-07 18:00:47","imsi":"460002082100000"} if v, ok := body["imsi"]; ok { eventJson["imsi"] = fmt.Sprint(v) } if v, ok := body["detachResult"]; ok { if fmt.Sprint(v) == "0" { eventJson["result"] = "200" } else { eventJson["result"] = "500" } } if v, ok := body["detachTime"]; ok { detachTime := date.ParseStrToDate(fmt.Sprint(v), date.YYYY_MM_DD_HH_MM_SS) eventJson["timestamp"] = detachTime.Unix() eventJson["time"] = fmt.Sprint(v) } case "cm-state": // {"changeTime":"2024-12-07 17:07:52","imsi":"460002082100000","onlineNumber":1,"status":2} if v, ok := body["imsi"]; ok { eventJson["imsi"] = fmt.Sprint(v) } if v, ok := body["onlineNumber"]; ok { eventJson["onlineNumber"] = parse.Number(v) } if v, ok := body["status"]; ok { eventJson["result"] = fmt.Sprint(v) } if v, ok := body["changeTime"]; ok { changeTime := date.ParseStrToDate(fmt.Sprint(v), date.YYYY_MM_DD_HH_MM_SS) eventJson["timestamp"] = changeTime.Unix() eventJson["time"] = fmt.Sprint(v) } } ueByte, err := json.Marshal(eventJson) if err != nil { services.ResponseInternalServerError500ProcessError(c.Writer, err) return } data.EventJSONStr = string(ueByte) if err := db.DB("").Table("ue_event_amf").Create(&data).Error; err != nil { log.Error("Failed to insert ue_event_amf", err) services.ResponseInternalServerError500ProcessError(c.Writer, err) return } // 推送到ws订阅组 if data.NeType == "AMF" { wsService.NewWSSend.ByGroupID(wsService.GROUP_AMF_UE, data) wsService.NewWSSend.ByGroupID(wsService.GROUP_AMF_UE+"_"+neInfo.NeId, data) } services.ResponseStatusOK204NoContent(c.Writer) } // UE上报处理 func PostUEEvent(w http.ResponseWriter, r *http.Request) { log.Info("PostUEEvent processing... ") neType := ctx.GetParam(r, "elementTypeValue") var body struct { NeType string `json:"neType" ` NeName string `json:"neName" ` RmUID string `json:"rmUID" ` Timestamp int64 `json:"timestamp" ` EventType string `json:"eventType" ` EventJson map[string]any `json:"eventJSON" ` } if err := ctx.ShouldBindJSON(r, &body); err != nil { services.ResponseInternalServerError500ProcessError(w, err) return } neTypeLower := strings.ToLower(body.NeType) if neType == "" || neType != neTypeLower { services.ResponseInternalServerError500ProcessError(w, fmt.Errorf("inconsistent network element types")) return } // 是否存在网元 neInfo := neService.NewNeInfo.FindByRmuid(body.RmUID) if neInfo.NeType != body.NeType || neInfo.RmUID != body.RmUID { services.ResponseInternalServerError500ProcessError(w, fmt.Errorf("network element does not exist")) return } ueByte, err := json.Marshal(body.EventJson) if err != nil { services.ResponseInternalServerError500ProcessError(w, err) return } // 执行插入表 type UEEvent struct { ID string `json:"-" gorm:"column:id;primaryKey;autoIncrement"` NeType string `json:"neType" gorm:"column:ne_type"` NeName string `json:"neName" gorm:"column:ne_name"` RmUID string `json:"rmUID" gorm:"column:rm_uid"` // 可能没有 Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到的timestamp秒级存储毫秒时间戳 EventType string `json:"eventType" gorm:"column:event_type"` // 事件类型 auth-result detach cm-state EventJSONStr string `json:"eventJSON" gorm:"column:event_json"` // data JSON String CreatedAt int64 `json:"-" gorm:"column:created_at"` // 记录创建存储毫秒 } data := UEEvent{ NeType: body.NeType, NeName: body.NeName, RmUID: body.RmUID, Timestamp: int64(body.Timestamp) * 1000, EventType: body.EventType, EventJSONStr: string(ueByte), CreatedAt: time.Now().UnixMilli(), } tableName := fmt.Sprintf("ue_event_%s", neTypeLower) if err := db.DB("").Table(tableName).Create(&data).Error; err != nil { log.Error("Failed to insert "+tableName, err) services.ResponseInternalServerError500ProcessError(w, err) return } // 推送到ws订阅组 if body.NeType == "MME" { wsService.NewWSSend.ByGroupID(wsService.GROUP_MME_UE, data) wsService.NewWSSend.ByGroupID(wsService.GROUP_MME_UE+"_"+neInfo.NeId, data) } if body.NeType == "AMF" { wsService.NewWSSend.ByGroupID(wsService.GROUP_AMF_UE, data) wsService.NewWSSend.ByGroupID(wsService.GROUP_AMF_UE+"_"+neInfo.NeId, data) } services.ResponseStatusOK204NoContent(w) }