package cdr import ( "encoding/json" "io" "net/http" "time" "be.ems/lib/dborm" "be.ems/lib/global" "be.ems/lib/log" "be.ems/lib/services" "be.ems/restagent/config" wsService "be.ems/src/modules/ws/service" ) var ( UriIMSCDREvent = config.DefaultUriPrefix + "/cdrManagement/v1/elementType/ims/objectType/cdrEvent" UriIMSCDRFile = config.DefaultUriPrefix + "/cdrManagement/v1/elementType/ims/objectType/cdrFile" UriSMFCDREvent = config.DefaultUriPrefix + "/cdrManagement/v1/elementType/smf/objectType/cdrEvent" UriSMFCDRFile = config.DefaultUriPrefix + "/cdrManagement/v1/elementType/smf/objectType/cdrFile" CustomUriIMSCDREvent = config.UriPrefix + "/cdrManagement/v1/elementType/ims/objectType/cdrEvent" CustomUriIMSCDRFile = config.UriPrefix + "/cdrManagement/v1/elementType/ims/objectType/cdrFile" CustomUriSMFCDREvent = config.UriPrefix + "/cdrManagement/v1/elementType/ims/objectType/cdrEvent" CustomUriSMFCDRFile = config.UriPrefix + "/cdrManagement/v1/elementType/ims/objectType/cdrFile" ) // SMF CDR type CdrSubscriptionID struct { SubscriptionIDType string `json:"subscriptionIDType"` SubscriptionIDData string `json:"subscriptionIDData"` } type CdrNetWorkFuctionInfomation struct { NetworkFunctionality string `json:"networkFunctionality"` NetworkFunctionName string `json:"networkFunctionName,omitempty"` NetworkFunctionIPv4Address string `json:"networkFunctionIPv4Address,omitempty"` NetworkFunctionIPv6Address string `json:"networkFunctionIPv6Address,omitempty"` } type SMFTrigger string const ( TimeThresholdReached SMFTrigger = "timeThresholdReached" VolumeThresholdReached SMFTrigger = "volumeThresholdReached" UnitThresholdReached SMFTrigger = "unitThresholdReached" TimeQuotaExhausted SMFTrigger = "timeQuotaExhausted" VolumeQuotaExhausted SMFTrigger = "volumeQuotaExhausted" UnitQuotaExhausted SMFTrigger = "unitQuotaExhausted" ExpiryOfQuotaValidityTime SMFTrigger = "expiryOfQuotaValidityTime" ExpiryOfQuotaHoldingTime SMFTrigger = "expiryOfQuotaHoldingTime" EndOfPDUSession SMFTrigger = "endOfPDUSession" ) type CdrSMFTrigger struct { SMFTrigger SMFTrigger `json:"sMFTrigger"` } type CdrQuotaManagementIndicator string // List of QuotaManagementIndicator const ( Cdr_QMI_ONLINE_CHARGING CdrQuotaManagementIndicator = "ONLINE_CHARGING" Cdr_QMI_OFFLINE_CHARGING CdrQuotaManagementIndicator = "OFFLINE_CHARGING" Cdr_QMI_QUOTA_MANAGEMENT_SUSPENDED CdrQuotaManagementIndicator = "QUOTA_MANAGEMENT_SUSPENDED" ) type CdrUsedUnitContainer struct { ServiceIdentifier *int32 `json:"serviceIdentifier,omitempty"` QuotaManagementIndicatorExt CdrQuotaManagementIndicator `json:"quotaManagementIndicatorExt,omitempty"` Triggers []SMFTrigger `json:"triggers,omitempty"` TriggerTimestamp *time.Time `json:"triggerTimestamp,omitempty"` Time *uint32 `json:"time,omitempty"` DataTotalVolume *uint64 `json:"dataTotalVolume,omitempty"` DataVolumeUplink *uint64 `json:"dataVolumeUplink,omitempty"` DataVolumeDownlink *uint64 `json:"dataVolumeDownlink,omitempty"` ServiceSpecificUnits *uint64 `json:"serviceSpecificUnits,omitempty"` EventTimeStamp *time.Time `json:"eventTimeStamp,omitempty"` LocalSequenceNumber int32 `json:"localSequenceNumber"` //PDUContainerInformation *PduContainerInformation `json:"pDUContainerInformation,omitempty"` //NSPAContainerInformation *NspaContainerInformation `json:"nSPAContainerInformation,omitempty"` } type CdrMultipleUnitUsage struct { RatingGroup uint32 `json:"ratingGroup" yaml:"ratingGroup" bson:"ratingGroup" mapstructure:"RatingGroup"` UsedUnitContainer []CdrUsedUnitContainer `json:"usedUnitContainer,omitempty" yaml:"usedUnitContainer" bson:"usedUnitContainer" mapstructure:"UsedUnitContainer"` //UPFID string `json:"uPFID,omitempty" yaml:"uPFID" bson:"uPFID" mapstructure:"UPFID"` } type CdrSubscriberEquipmentNumber struct { SubscriberEquipmentNumberType string `json:"subscriberEquipmentNumberType"` SubscriberEquipmentNumberData string `json:"subscriberEquipmentNumberData"` } type CdrNetworkSliceInstanceID struct { SST int32 `json:"sST"` SD string `json:"sD,omitempty"` } type CdrPduAddress struct { PDUIPv4Address string `json:"pDUIPv4Address,omitempty"` PDUIPv6AddresswithPrefix string `json:"pDUIPv6AddresswithPrefix,omitempty"` IPV4dynamicAddressFlag bool `json:"iPV4dynamicAddressFlag,omitempty"` IPV6dynamicPrefixFlag bool `json:"iPv6dynamicPrefixFlag,omitempty"` } type CdrArp struct { PriorityLevel int32 `json:"priorityLevel"` PreemptionCapability string `json:"preemptionCapability"` PreemptionVulnerability string `json:"preemptionVulnerability"` } type CdrAuthorizedQosInformation struct { FiveQi int `json:"fiveQi"` ARP *CdrArp `json:"aRP,omitempty"` PriorityLevel *int32 `json:"priorityLevel,omitempty"` AverWindow *int32 `json:"averWindow,omitempty"` MaxDataBurstVol *int32 `json:"maxDataBurstVol,omitempty"` } type CdrSubscribedDefaultQos struct { FiveQi int32 `json:"fiveQi,omitempty"` ARP CdrArp `json:"aRP,omitempty"` PriorityLevel *int32 `json:"priorityLevel,omitempty"` } type CdrSessionAmbr struct { Uplink string `json:"uplink"` Downlink string `json:"downlink"` } type CdrPDUSessionChargingInformation struct { PDUSessionChargingID int32 `json:"pDUSessionChargingID"` UserIdentifier string `json:"userIdentifier,omitempty"` // isdn UserEquipmentInfo *CdrSubscriberEquipmentNumber `json:"userEquipmentInfo,omitempty"` // imei/imeisv //UserLocationInfomation *UserLocation `json:"userLocationinfo,omitempty"` UserRoamerInOut string `json:"userRoamerInOut,omitempty"` PDUSessionId int32 `json:"pDUSessionId"` NetworkSliceInstanceID *CdrNetworkSliceInstanceID `json:"networkSliceInstanceID,omitempty"` //PDUType PduSessionType `json:"pDUType,omitempty"` SSCMode string `json:"sSCMode,omitempty"` DNNID string `json:"dNNID"` SUPIPLMNIdentifier string `json:"sUPIPLMNIdentifier,omitempty"` //ServingNetworkFunctionID *ServingNetworkFunctionId `json:"servingNetworkFunctionID,omitempty"` //RATType RatType `json:"rATType,omitempty"` DataNetworkNameIdentifier string `json:"dataNetworkNameIdentifier,omitempty"` PDUAddress CdrPduAddress `json:"pDUAddress,omitempty"` AuthorizedQoSInformation *CdrAuthorizedQosInformation `json:"authorizedQoSInformation,omitempty"` UETimeZone string `json:"uETimeZone,omitempty"` PDUSessionstartTime *time.Time `json:"pDUSessionstartTime,omitempty"` PDUSessionstopTime *time.Time `json:"pDUSessionstopTime,omitempty"` Diagnostics *int `json:"diagnostics,omitempty"` ChargingCharacteristics string `json:"chargingCharacteristics,omitempty"` ChChSelectionMode string `json:"chChSelectionMode,omitempty"` ThreeGPPPSDataOffStatus string `json:"threeGPPPSDataOffStatus,omitempty"` //RANSecondaryRATUsageReport *RanSecondaryRatUsageReport `json:"rANSecondaryRATUsageReport,omitempty"` SubscribedQoSInformation *CdrSubscribedDefaultQos `json:"subscribedQoSInformation,omitempty"` AuthorizedSessionAMBR *CdrSessionAmbr `json:"authorizedSessionAMBR,omitempty"` SubscribedSessionAMBR *CdrSessionAmbr `json:"subscribedSessionAMBR,omitempty"` ServingCNPLMNID string `json:"servingCNPLMNID,omitempty"` DnnSelectionMode string `json:"dnnSelectionMode,omitempty"` HomeProvidedChargingID int32 `json:"homeProvidedChargingID,omitempty"` //MAPDUNon3GPPUserLocationInfo *UserLocation `json:"mAPDUNon3GPPUserLocationInfo,omitempty" yaml:"mAPDUNon3GPPUserLocationInfo" bson:"mAPDUNon3GPPUserLocationInfo" mapstructure:"MAPDUNon3GPPUserLocationInfo"` //PresenceReportingAreaInformation map[string]PresenceInfo `json:"presenceReportingAreaInformation,omitempty" yaml:"presenceReportingAreaInformation" bson:"presenceReportingAreaInformation" mapstructure:"PresenceReportingAreaInformation"` } type CauseForRecordClosing string const ( NormalRelease CauseForRecordClosing = "normalRelease" PartialRecord CauseForRecordClosing = "partialRecord" AbnormalRelease CauseForRecordClosing = "abnormalRelease" CAMELInitCallRelease CauseForRecordClosing = "cAMELInitCallRelease" VolumeLimit CauseForRecordClosing = "volumeLimit" TimeLimit CauseForRecordClosing = "timeLimit" ServingNodeChange CauseForRecordClosing = "servingNodeChange" MaxChangeCond CauseForRecordClosing = "maxChangeCond" ManagementIntervention CauseForRecordClosing = "managementIntervention" IntraSGSNIntersystemChange CauseForRecordClosing = "intraSGSNIntersystemChange" RATChange CauseForRecordClosing = "rATChange" MSTimeZoneChange CauseForRecordClosing = "mSTimeZoneChange" SGSNPLMNIDChange CauseForRecordClosing = "sGSNPLMNIDChange " SGWChange CauseForRecordClosing = "sGWChange" APNAMBRChange CauseForRecordClosing = "aPNAMBRChange" ) type ChargingRecord struct { RecordType string `json:"recordType"` ChargingID int `json:"chargingID"` RecordingNetworkFunctionID string `json:"recordingNetworkFunctionID"` // UUID SubscriberIdentifier CdrSubscriptionID `json:"subscriberIdentifier,omitempty"` NFunctionConsumerInformation CdrNetWorkFuctionInfomation `json:"nFunctionConsumerInformation"` Triggers []CdrSMFTrigger `json:"triggers,omitempty"` ListOfMultipleUnitUsage []CdrMultipleUnitUsage `json:"listOfMultipleUnitUsage,omitempty"` RecordOpeningTime string `json:"recordOpeningTime"` Duration int `json:"duration"` RecordSequenceNumber int `json:"recordSequenceNumber,omitempty"` CauseForRecClosing CauseForRecordClosing `json:"causeForRecClosing"` Diagnostics *int `json:"diagnostics,omitempty"` LocalRecordSequenceNumber int `json:"localRecordSequenceNumber,omitempty"` PDUSessionChargingInformation CdrPDUSessionChargingInformation `json:"pDUSessionChargingInformation,omitempty"` InvocationTimestamp string `json:"invocationTimestamp,omitempty"` } type CDREvent struct { NeType string `json:"neType" xorm:"ne_type"` NeName string `json:"neName" xorm:"ne_name"` RmUID string `json:"rmUID" xorm:"rm_uid"` Timestamp int `json:"timestamp" xorm:"timestamp"` CDR map[string]any `json:"CDR" xorm:"cdr_json"` } func PostCDREventFromIMS(w http.ResponseWriter, r *http.Request) { log.Info("PostCDREventFromIMS processing... ") // body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) if err != nil { log.Error("Faile to io.ReadAll: ", err) services.ResponseNotFound404UriNotExist(w, r) return } cdrEvent := new(CDREvent) err = json.Unmarshal(body, &cdrEvent) if cdrEvent.NeType == "" || err != nil { log.Error("Failed to Unmarshal cdrEvent:", err) services.ResponseInternalServerError500ProcessError(w, err) return } log.Trace("cdrEvent:", cdrEvent) affected, err := dborm.XormInsertTableOne("cdr_event_ims", cdrEvent) if err != nil && affected <= 0 { log.Error("Failed to insert cdr_event_ims:", err) services.ResponseInternalServerError500ProcessError(w, err) return } // 推送到ws订阅组 if v, ok := cdrEvent.CDR["recordType"]; ok { if v == "MOC" || v == "MTSM" { wsService.NewWSSendImpl.ByGroupID(wsService.GROUP_IMS_CDR, cdrEvent) } } services.ResponseStatusOK204NoContent(w) } func PostCDREventFromSMF(w http.ResponseWriter, r *http.Request) { log.Info("PostCDREventFromSMF processing... ") // body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) if err != nil { log.Error("Faile to io.ReadAll: ", err) services.ResponseNotFound404UriNotExist(w, r) return } cdrEvent := new(CDREvent) err = json.Unmarshal(body, &cdrEvent) if cdrEvent.NeType == "" || err != nil { log.Error("Failed to Unmarshal cdrEvent:", err) services.ResponseInternalServerError500ProcessError(w, err) return } log.Trace("cdrEvent:", cdrEvent) affected, err := dborm.XormInsertTableOne("cdr_event_smf", cdrEvent) if err != nil && affected <= 0 { log.Error("Failed to insert cdr_event_smf:", err) services.ResponseInternalServerError500ProcessError(w, err) return } // 推送到ws订阅组 wsService.NewWSSendImpl.ByGroupID(wsService.GROUP_SMF_CDR, cdrEvent) services.ResponseStatusOK204NoContent(w) }