4e2cd43a55
iotlcm-onelink-mock:OneLink 挡板服务(本地测试替身)。 - Go module 迁移至 git.5iot.com/iotlcm-public/iotlcm-onelink-mock - 修复同毫秒内多次生成卡导致 ICCID/IMSI 唯一约束冲突 - 补 Apache-2.0 LICENSE,README 重写并新增 docs/deploy.md - 移除内部部署资产(CI 触发器 / 镜像推送脚本 / 指定环境部署文档) - 测试凭据改为 demo_appid / demo_password,真实手机号与内网 IP 脱敏 - 统一 LF 行尾并加 .gitattributes
144 lines
4.4 KiB
Go
144 lines
4.4 KiB
Go
package service
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type dbAPN struct {
|
|
APNName string `json:"apnName"`
|
|
Status string `json:"status"`
|
|
DiagnosisStatus string `json:"diagnosisStatus"`
|
|
UsageBytes json.Number `json:"usageBytes"`
|
|
ModifyTime string `json:"modifyTime"`
|
|
OverUseDetails string `json:"overUseDetails"`
|
|
ServiceUsageState string `json:"serviceUsageState"`
|
|
PCCs []dbPCC `json:"pccs"`
|
|
}
|
|
|
|
type dbPCC struct {
|
|
ServiceCode string `json:"serviceCode"`
|
|
Name string `json:"name"`
|
|
PolicyStatus string `json:"policyStatus"`
|
|
ServiceUsageState string `json:"serviceUsageState"`
|
|
ModifyTime string `json:"modifyTime"`
|
|
}
|
|
|
|
func parseAPNs(raw, fallbackName, fallbackStatus string, fallbackUsageKB float64, fallbackUsageBytes int64) []APN {
|
|
var rows []dbAPN
|
|
decoder := json.NewDecoder(strings.NewReader(raw))
|
|
decoder.UseNumber()
|
|
if raw != "" && decoder.Decode(&rows) == nil {
|
|
apns := make([]APN, 0, len(rows))
|
|
for _, row := range rows {
|
|
usageBytes, _ := strconv.ParseFloat(row.UsageBytes.String(), 64)
|
|
pccs := make([]PCC, 0, len(row.PCCs))
|
|
for _, pcc := range row.PCCs {
|
|
pccs = append(pccs, PCC{ServiceCode: pcc.ServiceCode, Name: pcc.Name, PolicyStatus: pcc.PolicyStatus, ServiceUsageState: pcc.ServiceUsageState, ModifyTime: pcc.ModifyTime})
|
|
}
|
|
apns = append(apns, APN{Name: row.APNName, Status: row.Status, DiagnosisStatus: row.DiagnosisStatus, UsageBytes: usageBytes, ModifyTime: row.ModifyTime, OverUseDetails: row.OverUseDetails, ServiceUsageState: row.ServiceUsageState, PCCs: pccs})
|
|
}
|
|
return apns
|
|
}
|
|
usageBytes := float64(fallbackUsageBytes)
|
|
if usageBytes == 0 && fallbackUsageKB > 0 {
|
|
usageBytes = fallbackUsageKB * 1024
|
|
}
|
|
if fallbackName == "" {
|
|
return nil
|
|
}
|
|
return []APN{{Name: fallbackName, Status: fallbackStatus, UsageBytes: usageBytes}}
|
|
}
|
|
|
|
func apnsForDB(apns []APN) []map[string]interface{} {
|
|
out := make([]map[string]interface{}, 0, len(apns))
|
|
for _, apn := range apns {
|
|
out = append(out, map[string]interface{}{
|
|
"apnName": apn.Name,
|
|
"status": apn.Status,
|
|
"diagnosisStatus": apn.DiagnosisStatus,
|
|
"usageBytes": int64(apn.UsageBytes),
|
|
"modifyTime": apn.ModifyTime,
|
|
"overUseDetails": apn.OverUseDetails,
|
|
"serviceUsageState": apn.ServiceUsageState,
|
|
"pccs": pccsForDB(apn.PCCs),
|
|
})
|
|
}
|
|
return out
|
|
}
|
|
|
|
func pccsForDB(pccs []PCC) []map[string]string {
|
|
out := make([]map[string]string, 0, len(pccs))
|
|
for _, pcc := range pccs {
|
|
out = append(out, map[string]string{
|
|
"serviceCode": pcc.ServiceCode, "name": pcc.Name, "policyStatus": pcc.PolicyStatus,
|
|
"serviceUsageState": pcc.ServiceUsageState, "modifyTime": pcc.ModifyTime,
|
|
})
|
|
}
|
|
return out
|
|
}
|
|
|
|
func primaryAPN(card SIMCard) APN {
|
|
for _, apn := range card.APNs {
|
|
if apn.Status == "1" {
|
|
return apn
|
|
}
|
|
}
|
|
if len(card.APNs) > 0 {
|
|
return card.APNs[0]
|
|
}
|
|
return APN{Name: "CMIOT", Status: "1", UsageBytes: card.MonthUsageKB * 1024}
|
|
}
|
|
|
|
func sourceRemark(carrier, packageCode, packageName string) string {
|
|
return fmt.Sprintf("carrier=%s; package=%s; name=%s; channel=%s; supplier=%s", carrier, packageCode, packageName, generatedChanKey, generatedSupplierCode)
|
|
}
|
|
|
|
func mockMetadataFromRemark(remark string) (string, string, string) {
|
|
values := map[string]string{}
|
|
for _, part := range strings.Split(remark, ";") {
|
|
key, value, ok := strings.Cut(strings.TrimSpace(part), "=")
|
|
if ok {
|
|
values[strings.ToLower(strings.TrimSpace(key))] = strings.TrimSpace(value)
|
|
}
|
|
}
|
|
carrier := values["carrier"]
|
|
if carrier == "" {
|
|
carrier = "CMCC"
|
|
}
|
|
packageCode := values["package"]
|
|
if packageCode == "" {
|
|
packageCode = generatedPackageCode
|
|
}
|
|
packageName := values["name"]
|
|
if packageName == "" {
|
|
packageName = generatedPackageCode
|
|
}
|
|
return carrier, packageCode, packageName
|
|
}
|
|
|
|
func dbTimeToRFC3339(value string) string {
|
|
if value == "" {
|
|
return time.Now().Format(time.RFC3339)
|
|
}
|
|
if t, err := time.ParseInLocation("2006-01-02 15:04:05", value, time.Local); err == nil {
|
|
return t.Format(time.RFC3339)
|
|
}
|
|
return value
|
|
}
|
|
|
|
func rfc3339ToDBTime(value string) string {
|
|
if value == "" {
|
|
return ""
|
|
}
|
|
for _, layout := range []string{time.RFC3339Nano, time.RFC3339, "2006-01-02 15:04:05"} {
|
|
if t, err := time.ParseInLocation(layout, value, time.Local); err == nil {
|
|
return t.Format("2006-01-02 15:04:05")
|
|
}
|
|
}
|
|
return value
|
|
}
|