chore: 并入 iotlcm-admin-svr 历史到 admin-svr/(原提交 49818c6)
This commit is contained in:
@@ -0,0 +1,355 @@
|
||||
package upstream
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model"
|
||||
)
|
||||
|
||||
type ydDataDiagnosisResp struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Result []ydDataDiagnosisResult `json:"result"`
|
||||
}
|
||||
|
||||
type ydDataDiagnosisResult struct {
|
||||
ApnList json.RawMessage `json:"apnList"`
|
||||
}
|
||||
|
||||
type ydDataDiagnosisApnInfo struct {
|
||||
ApnName string `json:"apnName"`
|
||||
ApnStatus string `json:"apnStatus"`
|
||||
ModifyTime string `json:"modifyTime"`
|
||||
OverUseDetails string `json:"overUseDetails"`
|
||||
ApnServiceUsageState string `json:"apnServiceUsageState"`
|
||||
PccList json.RawMessage `json:"pccList"`
|
||||
}
|
||||
|
||||
type ydDataDiagnosisPccInfo struct {
|
||||
PccServiceCode string `json:"pccServiceCode"`
|
||||
PccName string `json:"pccName"`
|
||||
PccNameLower string `json:"pccname"`
|
||||
PccPolicyStatus string `json:"pccPolicyStatus"`
|
||||
PccServiceUsageState string `json:"pccServiceUsageState"`
|
||||
ModifyTime string `json:"modifyTime"`
|
||||
}
|
||||
|
||||
func parseYdDataDiagnosisBody(body json.RawMessage) (model.SimDataDiagnosisItem, error) {
|
||||
var ydResp ydDataDiagnosisResp
|
||||
if err := json.Unmarshal(body, &ydResp); err != nil {
|
||||
return model.SimDataDiagnosisItem{}, err
|
||||
}
|
||||
return buildYdDataDiagnosisItem(ydResp.Result), nil
|
||||
}
|
||||
|
||||
func buildYdDataDiagnosisItem(results []ydDataDiagnosisResult) model.SimDataDiagnosisItem {
|
||||
apnInfos := make([]ydDataDiagnosisApnInfo, 0)
|
||||
for _, result := range results {
|
||||
apnInfos = append(apnInfos, decodeYdDataDiagnosisApnInfos(result.ApnList)...)
|
||||
}
|
||||
if len(apnInfos) == 0 {
|
||||
return model.SimDataDiagnosisItem{
|
||||
RateLimitStatus: "2",
|
||||
RateLimitReason: "上游未返回达量限速明细",
|
||||
}
|
||||
}
|
||||
|
||||
triggered := false
|
||||
reasons := make([]string, 0)
|
||||
details := make([]string, 0, len(apnInfos))
|
||||
apnDetails := make([]model.SimDataDiagnosisApnDetail, 0, len(apnInfos))
|
||||
|
||||
for _, apn := range apnInfos {
|
||||
apnName := strings.TrimSpace(apn.ApnName)
|
||||
displayApn := apnName
|
||||
if displayApn == "" {
|
||||
displayApn = "未命名APN"
|
||||
}
|
||||
|
||||
if overUseText := mapYdOverUseDetailsText(apn.OverUseDetails); overUseText != "" {
|
||||
triggered = true
|
||||
reasons = append(reasons, fmt.Sprintf("%s:%s", displayApn, overUseText))
|
||||
}
|
||||
if stateText, limited := mapYdUsageStateText(apn.ApnServiceUsageState); limited {
|
||||
triggered = true
|
||||
reasons = append(reasons, fmt.Sprintf("%s:%s", displayApn, stateText))
|
||||
}
|
||||
|
||||
pccInfos := decodeYdDataDiagnosisPccInfos(apn.PccList)
|
||||
pccDetails := make([]model.SimDataDiagnosisPccDetail, 0, len(pccInfos))
|
||||
pccText := make([]string, 0, len(pccInfos))
|
||||
for _, pcc := range pccInfos {
|
||||
pccName := firstNonEmpty(pcc.PccName, pcc.PccNameLower, pcc.PccServiceCode)
|
||||
if pccName == "" {
|
||||
pccName = "未命名PCC策略"
|
||||
}
|
||||
if stateText, limited := mapYdUsageStateText(pcc.PccServiceUsageState); limited {
|
||||
triggered = true
|
||||
reasons = append(reasons, fmt.Sprintf("%s/%s:%s", displayApn, pccName, stateText))
|
||||
}
|
||||
pccText = append(pccText, fmt.Sprintf("%s %s %s", pccName, mapYdPccPolicyStatusText(pcc.PccPolicyStatus), mapYdUsageStateTextForDetail(pcc.PccServiceUsageState)))
|
||||
pccDetails = append(pccDetails, model.SimDataDiagnosisPccDetail{
|
||||
PccServiceCode: strings.TrimSpace(pcc.PccServiceCode),
|
||||
PccName: firstNonEmpty(pcc.PccName, pcc.PccNameLower),
|
||||
PccPolicyStatus: strings.TrimSpace(pcc.PccPolicyStatus),
|
||||
PccServiceUsageState: strings.TrimSpace(pcc.PccServiceUsageState),
|
||||
ModifyTime: strings.TrimSpace(pcc.ModifyTime),
|
||||
})
|
||||
}
|
||||
|
||||
detailParts := []string{fmt.Sprintf("%s %s %s", displayApn, mapYdApnStatusText(apn.ApnStatus), mapYdUsageStateTextForDetail(apn.ApnServiceUsageState))}
|
||||
if overUseText := mapYdOverUseDetailsText(apn.OverUseDetails); overUseText != "" {
|
||||
detailParts = append(detailParts, "超停原因:"+overUseText)
|
||||
}
|
||||
if len(pccText) > 0 {
|
||||
detailParts = append(detailParts, "PCC:"+strings.Join(pccText, ";"))
|
||||
}
|
||||
details = append(details, strings.Join(detailParts, ";"))
|
||||
apnDetails = append(apnDetails, model.SimDataDiagnosisApnDetail{
|
||||
ApnName: apnName,
|
||||
ApnStatus: strings.TrimSpace(apn.ApnStatus),
|
||||
ModifyTime: strings.TrimSpace(apn.ModifyTime),
|
||||
OverUseDetails: strings.TrimSpace(apn.OverUseDetails),
|
||||
ApnServiceUsageState: strings.TrimSpace(apn.ApnServiceUsageState),
|
||||
PccDetails: pccDetails,
|
||||
})
|
||||
}
|
||||
|
||||
status := "1"
|
||||
reason := "未发现达量限速或流量关停"
|
||||
if triggered {
|
||||
status = "0"
|
||||
reason = strings.Join(uniqueNonEmptyStrings(reasons), ";")
|
||||
}
|
||||
return model.SimDataDiagnosisItem{
|
||||
RateLimitStatus: status,
|
||||
RateLimitReason: reason,
|
||||
RateLimitDetail: strings.Join(uniqueNonEmptyStrings(details), ";"),
|
||||
ApnDetails: apnDetails,
|
||||
}
|
||||
}
|
||||
|
||||
func decodeYdDataDiagnosisApnInfos(raw json.RawMessage) []ydDataDiagnosisApnInfo {
|
||||
raw = trimJSONRaw(raw)
|
||||
if len(raw) == 0 {
|
||||
return nil
|
||||
}
|
||||
if raw[0] == '{' {
|
||||
var wrapper struct {
|
||||
ApnInfo json.RawMessage `json:"apnInfo"`
|
||||
}
|
||||
if json.Unmarshal(raw, &wrapper) == nil && len(trimJSONRaw(wrapper.ApnInfo)) > 0 {
|
||||
return decodeYdDataDiagnosisApnInfoList(wrapper.ApnInfo)
|
||||
}
|
||||
var item ydDataDiagnosisApnInfo
|
||||
if json.Unmarshal(raw, &item) == nil {
|
||||
return []ydDataDiagnosisApnInfo{item}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if raw[0] == '[' {
|
||||
var wrappers []struct {
|
||||
ApnInfo json.RawMessage `json:"apnInfo"`
|
||||
}
|
||||
if json.Unmarshal(raw, &wrappers) == nil {
|
||||
items := make([]ydDataDiagnosisApnInfo, 0)
|
||||
for _, wrapper := range wrappers {
|
||||
items = append(items, decodeYdDataDiagnosisApnInfoList(wrapper.ApnInfo)...)
|
||||
}
|
||||
if len(items) > 0 {
|
||||
return items
|
||||
}
|
||||
}
|
||||
return decodeYdDataDiagnosisApnInfoList(raw)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeYdDataDiagnosisApnInfoList(raw json.RawMessage) []ydDataDiagnosisApnInfo {
|
||||
raw = trimJSONRaw(raw)
|
||||
if len(raw) == 0 {
|
||||
return nil
|
||||
}
|
||||
if raw[0] == '[' {
|
||||
var items []ydDataDiagnosisApnInfo
|
||||
if json.Unmarshal(raw, &items) == nil && len(items) > 0 {
|
||||
return items
|
||||
}
|
||||
}
|
||||
if raw[0] == '{' {
|
||||
var item ydDataDiagnosisApnInfo
|
||||
if json.Unmarshal(raw, &item) == nil {
|
||||
return []ydDataDiagnosisApnInfo{item}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeYdDataDiagnosisPccInfos(raw json.RawMessage) []ydDataDiagnosisPccInfo {
|
||||
raw = trimJSONRaw(raw)
|
||||
if len(raw) == 0 {
|
||||
return nil
|
||||
}
|
||||
if raw[0] == '{' {
|
||||
var wrapper struct {
|
||||
PccInfo json.RawMessage `json:"pccInfo"`
|
||||
}
|
||||
if json.Unmarshal(raw, &wrapper) == nil && len(trimJSONRaw(wrapper.PccInfo)) > 0 {
|
||||
return decodeYdDataDiagnosisPccInfoList(wrapper.PccInfo)
|
||||
}
|
||||
var item ydDataDiagnosisPccInfo
|
||||
if json.Unmarshal(raw, &item) == nil {
|
||||
return []ydDataDiagnosisPccInfo{item}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if raw[0] == '[' {
|
||||
var wrappers []struct {
|
||||
PccInfo json.RawMessage `json:"pccInfo"`
|
||||
}
|
||||
if json.Unmarshal(raw, &wrappers) == nil {
|
||||
items := make([]ydDataDiagnosisPccInfo, 0)
|
||||
for _, wrapper := range wrappers {
|
||||
items = append(items, decodeYdDataDiagnosisPccInfoList(wrapper.PccInfo)...)
|
||||
}
|
||||
if len(items) > 0 {
|
||||
return items
|
||||
}
|
||||
}
|
||||
return decodeYdDataDiagnosisPccInfoList(raw)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeYdDataDiagnosisPccInfoList(raw json.RawMessage) []ydDataDiagnosisPccInfo {
|
||||
raw = trimJSONRaw(raw)
|
||||
if len(raw) == 0 {
|
||||
return nil
|
||||
}
|
||||
if raw[0] == '[' {
|
||||
var items []ydDataDiagnosisPccInfo
|
||||
if json.Unmarshal(raw, &items) == nil && len(items) > 0 {
|
||||
return items
|
||||
}
|
||||
}
|
||||
if raw[0] == '{' {
|
||||
var item ydDataDiagnosisPccInfo
|
||||
if json.Unmarshal(raw, &item) == nil {
|
||||
return []ydDataDiagnosisPccInfo{item}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func trimJSONRaw(raw json.RawMessage) json.RawMessage {
|
||||
return json.RawMessage(strings.TrimSpace(string(raw)))
|
||||
}
|
||||
|
||||
func firstNonEmpty(values ...string) string {
|
||||
for _, value := range values {
|
||||
if value = strings.TrimSpace(value); value != "" {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func uniqueNonEmptyStrings(values []string) []string {
|
||||
seen := make(map[string]struct{}, len(values))
|
||||
result := make([]string, 0, len(values))
|
||||
for _, value := range values {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[value]; ok {
|
||||
continue
|
||||
}
|
||||
seen[value] = struct{}{}
|
||||
result = append(result, value)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func mapYdOverUseDetailsText(value string) string {
|
||||
parts := strings.FieldsFunc(strings.TrimSpace(value), func(r rune) bool {
|
||||
return r == '|' || r == ',' || r == ';' || r == ',' || r == ';'
|
||||
})
|
||||
texts := make([]string, 0, len(parts))
|
||||
for _, part := range parts {
|
||||
switch strings.TrimSpace(part) {
|
||||
case "12":
|
||||
texts = append(texts, "流量用尽关停")
|
||||
case "17":
|
||||
texts = append(texts, "限额管控关停")
|
||||
case "18":
|
||||
texts = append(texts, "超量关停")
|
||||
case "":
|
||||
default:
|
||||
texts = append(texts, strings.TrimSpace(part))
|
||||
}
|
||||
}
|
||||
return strings.Join(uniqueNonEmptyStrings(texts), ";")
|
||||
}
|
||||
|
||||
func mapYdUsageStateText(value string) (text string, limited bool) {
|
||||
switch strings.TrimSpace(value) {
|
||||
case "", "1":
|
||||
return "正常速率", false
|
||||
case "91":
|
||||
return "限速至2Mbps(月初不自动恢复)", true
|
||||
case "92":
|
||||
return "限速至2Mbps(月初自动恢复)", true
|
||||
case "95":
|
||||
return "限速至1Mbps(月初不自动恢复)", true
|
||||
case "96":
|
||||
return "限速至1Mbps(月初自动恢复)", true
|
||||
case "97":
|
||||
return "达量限速2M", true
|
||||
case "98":
|
||||
return "达量限速1M", true
|
||||
default:
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
return "", false
|
||||
}
|
||||
return value, value != "0"
|
||||
}
|
||||
}
|
||||
|
||||
func mapYdUsageStateTextForDetail(value string) string {
|
||||
text, _ := mapYdUsageStateText(value)
|
||||
return text
|
||||
}
|
||||
|
||||
func mapYdApnStatusText(value string) string {
|
||||
switch strings.TrimSpace(value) {
|
||||
case "", "0", "1":
|
||||
return "APN已停用"
|
||||
case "2":
|
||||
return "APN已激活"
|
||||
case "3":
|
||||
return "APN已删除"
|
||||
case "4":
|
||||
return "APN已暂停"
|
||||
default:
|
||||
return strings.TrimSpace(value)
|
||||
}
|
||||
}
|
||||
|
||||
func mapYdPccPolicyStatusText(value string) string {
|
||||
switch strings.TrimSpace(value) {
|
||||
case "", "0", "1":
|
||||
return "策略已停用"
|
||||
case "2":
|
||||
return "策略已激活"
|
||||
case "3":
|
||||
return "策略已删除"
|
||||
case "4":
|
||||
return "策略已暂停"
|
||||
default:
|
||||
return strings.TrimSpace(value)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user