fix: Gateway 响应类型兼容 — 新增 FlexBool/FlexInt 处理设备返回的字符串类型字段
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m4s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m4s
部分设备厂商(如华为)的 Gateway 响应中 bool/int 字段返回为字符串(wifi_enabled: "1"、battery_level: "30"), 导致 sonic 严格类型检查反序列化失败,整个设备实时数据丢失。 - 新增 FlexBool 类型:兼容 true/false、"1"/"0"、"true"/"false" - 新增 FlexInt 类型:兼容 30、"30"、null - SyncDeviceInfoResp 所有 bool/int 字段改用 Flex 类型 - 更新 B 端和 C 端 DTO 映射函数的类型转换
This commit is contained in:
@@ -3,6 +3,7 @@ package gateway
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -24,6 +25,27 @@ func (b *FlexBool) UnmarshalJSON(data []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FlexInt 灵活整数类型
|
||||||
|
// 与 FlexBool 同理,Gateway 部分设备返回 int 字段时使用字符串(如 "30")而非 JSON number。
|
||||||
|
type FlexInt int
|
||||||
|
|
||||||
|
// UnmarshalJSON 实现 json.Unmarshaler 接口
|
||||||
|
// 支持:30, "30", null
|
||||||
|
func (i *FlexInt) UnmarshalJSON(data []byte) error {
|
||||||
|
raw := strings.Trim(string(data), "\"")
|
||||||
|
if raw == "" || raw == "null" {
|
||||||
|
*i = 0
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
n, err := strconv.Atoi(raw)
|
||||||
|
if err != nil {
|
||||||
|
*i = 0
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
*i = FlexInt(n)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// GatewayResponse 是 Gateway API 的通用响应结构
|
// GatewayResponse 是 Gateway API 的通用响应结构
|
||||||
type GatewayResponse struct {
|
type GatewayResponse struct {
|
||||||
Code int `json:"code" description:"业务状态码(200 = 成功)"`
|
Code int `json:"code" description:"业务状态码(200 = 成功)"`
|
||||||
@@ -173,17 +195,17 @@ type SyncDeviceInfoResp struct {
|
|||||||
WifiEnabled FlexBool `json:"wifi_enabled" description:"WiFi开关状态"`
|
WifiEnabled FlexBool `json:"wifi_enabled" description:"WiFi开关状态"`
|
||||||
SwitchMode string `json:"switch_mode" description:"切卡模式:0=自动,1=手动"`
|
SwitchMode string `json:"switch_mode" description:"切卡模式:0=自动,1=手动"`
|
||||||
RSSI string `json:"rssi" description:"接收信号强度"`
|
RSSI string `json:"rssi" description:"接收信号强度"`
|
||||||
BatteryLevel *int `json:"battery_level" description:"电池电量百分比(无电池时为null)"`
|
BatteryLevel *FlexInt `json:"battery_level" description:"电池电量百分比(无电池时为null)"`
|
||||||
OnlineStatus int `json:"online_status" description:"在线状态:1=在线,2=离线"`
|
OnlineStatus FlexInt `json:"online_status" description:"在线状态:1=在线,2=离线"`
|
||||||
LastUpdateTime string `json:"last_update_time" description:"设备信息最后更新时间(ISO 8601)"`
|
LastUpdateTime string `json:"last_update_time" description:"设备信息最后更新时间(ISO 8601)"`
|
||||||
LastOnlineTime string `json:"last_online_time" description:"设备最后在线时间(ISO 8601)"`
|
LastOnlineTime string `json:"last_online_time" description:"设备最后在线时间(ISO 8601)"`
|
||||||
RunTime string `json:"run_time" description:"本次开机运行时间(秒)"`
|
RunTime string `json:"run_time" description:"本次开机运行时间(秒)"`
|
||||||
DailyUsage string `json:"daily_usage" description:"日使用流量(字节)"`
|
DailyUsage string `json:"daily_usage" description:"日使用流量(字节)"`
|
||||||
|
|
||||||
// 信号相关(D-10 补全)
|
// 信号相关(D-10 补全)
|
||||||
Rsrp int `json:"rsrp" description:"参考信号接收功率(dBm)"`
|
Rsrp FlexInt `json:"rsrp" description:"参考信号接收功率(dBm)"`
|
||||||
Rsrq int `json:"rsrq" description:"参考信号接收质量(dB)"`
|
Rsrq FlexInt `json:"rsrq" description:"参考信号接收质量(dB)"`
|
||||||
Sinr int `json:"sinr" description:"信噪比(dB)"`
|
Sinr FlexInt `json:"sinr" description:"信噪比(dB)"`
|
||||||
|
|
||||||
// WiFi 相关(D-10 补全)
|
// WiFi 相关(D-10 补全)
|
||||||
WifiPassword string `json:"wifi_password" description:"WiFi密码"`
|
WifiPassword string `json:"wifi_password" description:"WiFi密码"`
|
||||||
@@ -194,14 +216,14 @@ type SyncDeviceInfoResp struct {
|
|||||||
LANIP string `json:"lan_ip" description:"局域网网关IP地址"`
|
LANIP string `json:"lan_ip" description:"局域网网关IP地址"`
|
||||||
|
|
||||||
// 连接相关(D-10 补全)
|
// 连接相关(D-10 补全)
|
||||||
MaxClients int `json:"max_clients" description:"最大连接客户端数"`
|
MaxClients FlexInt `json:"max_clients" description:"最大连接客户端数"`
|
||||||
ConnectTime string `json:"connect_time" description:"设备本次联网时间(秒)"`
|
ConnectTime string `json:"connect_time" description:"设备本次联网时间(秒)"`
|
||||||
|
|
||||||
// 设备属性(D-10 补全)
|
// 设备属性(D-10 补全)
|
||||||
Status int `json:"status" description:"设备状态:1=正常,0=禁用"`
|
Status FlexInt `json:"status" description:"设备状态:1=正常,0=禁用"`
|
||||||
IMSI string `json:"imsi" description:"IMSI用户标识码"`
|
IMSI string `json:"imsi" description:"IMSI用户标识码"`
|
||||||
ULStats string `json:"ul_stats" description:"本次开机上传流量(字节)"`
|
ULStats string `json:"ul_stats" description:"本次开机上传流量(字节)"`
|
||||||
DLStats string `json:"dl_stats" description:"本次开机下载流量(字节)"`
|
DLStats string `json:"dl_stats" description:"本次开机下载流量(字节)"`
|
||||||
LimitSpeed int `json:"limit_speed" description:"限速速率(KB/s)"`
|
LimitSpeed FlexInt `json:"limit_speed" description:"限速速率(KB/s)"`
|
||||||
SyncInterval int `json:"sync_interval" description:"信息上报周期(秒)"`
|
SyncInterval FlexInt `json:"sync_interval" description:"信息上报周期(秒)"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -363,15 +363,15 @@ func (s *Service) fetchDeviceGatewayInfo(ctx context.Context, deviceID uint) *dt
|
|||||||
// 使用指针字段,未赋值的字段保持 nil(omitempty)
|
// 使用指针字段,未赋值的字段保持 nil(omitempty)
|
||||||
func mapSyncRespToDeviceGatewayInfo(r *gateway.SyncDeviceInfoResp) *dto.DeviceGatewayInfo {
|
func mapSyncRespToDeviceGatewayInfo(r *gateway.SyncDeviceInfoResp) *dto.DeviceGatewayInfo {
|
||||||
info := &dto.DeviceGatewayInfo{
|
info := &dto.DeviceGatewayInfo{
|
||||||
OnlineStatus: &r.OnlineStatus,
|
OnlineStatus: flexIntPtr(r.OnlineStatus),
|
||||||
RunTime: strPtr(r.RunTime),
|
RunTime: strPtr(r.RunTime),
|
||||||
ConnectTime: strPtr(r.ConnectTime),
|
ConnectTime: strPtr(r.ConnectTime),
|
||||||
LastOnlineTime: strPtr(r.LastOnlineTime),
|
LastOnlineTime: strPtr(r.LastOnlineTime),
|
||||||
LastUpdateTime: strPtr(r.LastUpdateTime),
|
LastUpdateTime: strPtr(r.LastUpdateTime),
|
||||||
Rsrp: &r.Rsrp,
|
Rsrp: flexIntPtr(r.Rsrp),
|
||||||
Rsrq: &r.Rsrq,
|
Rsrq: flexIntPtr(r.Rsrq),
|
||||||
Rssi: strPtr(r.RSSI),
|
Rssi: strPtr(r.RSSI),
|
||||||
Sinr: &r.Sinr,
|
Sinr: flexIntPtr(r.Sinr),
|
||||||
SSID: strPtr(r.SSID),
|
SSID: strPtr(r.SSID),
|
||||||
WifiEnabled: flexBoolPtr(r.WifiEnabled),
|
WifiEnabled: flexBoolPtr(r.WifiEnabled),
|
||||||
WifiPassword: strPtr(r.WifiPassword),
|
WifiPassword: strPtr(r.WifiPassword),
|
||||||
@@ -382,21 +382,22 @@ func mapSyncRespToDeviceGatewayInfo(r *gateway.SyncDeviceInfoResp) *dto.DeviceGa
|
|||||||
DailyUsage: strPtr(r.DailyUsage),
|
DailyUsage: strPtr(r.DailyUsage),
|
||||||
DLStats: strPtr(r.DLStats),
|
DLStats: strPtr(r.DLStats),
|
||||||
ULStats: strPtr(r.ULStats),
|
ULStats: strPtr(r.ULStats),
|
||||||
LimitSpeed: &r.LimitSpeed,
|
LimitSpeed: flexIntPtr(r.LimitSpeed),
|
||||||
CurrentIccid: strPtr(r.CurrentIccid),
|
CurrentIccid: strPtr(r.CurrentIccid),
|
||||||
MaxClients: &r.MaxClients,
|
MaxClients: flexIntPtr(r.MaxClients),
|
||||||
SoftwareVersion: strPtr(r.SoftwareVersion),
|
SoftwareVersion: strPtr(r.SoftwareVersion),
|
||||||
SwitchMode: strPtr(r.SwitchMode),
|
SwitchMode: strPtr(r.SwitchMode),
|
||||||
SyncInterval: &r.SyncInterval,
|
SyncInterval: flexIntPtr(r.SyncInterval),
|
||||||
DeviceID: strPtr(r.DeviceID),
|
DeviceID: strPtr(r.DeviceID),
|
||||||
DeviceName: strPtr(r.DeviceName),
|
DeviceName: strPtr(r.DeviceName),
|
||||||
DeviceType: strPtr(r.DeviceType),
|
DeviceType: strPtr(r.DeviceType),
|
||||||
IMEI: strPtr(r.IMEI),
|
IMEI: strPtr(r.IMEI),
|
||||||
IMSI: strPtr(r.IMSI),
|
IMSI: strPtr(r.IMSI),
|
||||||
Status: &r.Status,
|
Status: flexIntPtr(r.Status),
|
||||||
}
|
}
|
||||||
if r.BatteryLevel != nil {
|
if r.BatteryLevel != nil {
|
||||||
info.BatteryLevel = r.BatteryLevel
|
n := int(*r.BatteryLevel)
|
||||||
|
info.BatteryLevel = &n
|
||||||
}
|
}
|
||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
@@ -415,6 +416,11 @@ func flexBoolPtr(fb gateway.FlexBool) *bool {
|
|||||||
return &b
|
return &b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func flexIntPtr(fi gateway.FlexInt) *int {
|
||||||
|
n := int(fi)
|
||||||
|
return &n
|
||||||
|
}
|
||||||
|
|
||||||
// Refresh 刷新资产数据(调网关同步)
|
// Refresh 刷新资产数据(调网关同步)
|
||||||
func (s *Service) Refresh(ctx context.Context, assetType string, id uint) (*dto.AssetRealtimeStatusResponse, error) {
|
func (s *Service) Refresh(ctx context.Context, assetType string, id uint) (*dto.AssetRealtimeStatusResponse, error) {
|
||||||
switch assetType {
|
switch assetType {
|
||||||
@@ -505,7 +511,7 @@ func (s *Service) updateDeviceFromSyncInfo(ctx context.Context, deviceID uint, r
|
|||||||
|
|
||||||
// 更新设备 5 个存储字段
|
// 更新设备 5 个存储字段
|
||||||
updates := map[string]any{
|
updates := map[string]any{
|
||||||
"online_status": resp.OnlineStatus,
|
"online_status": int(resp.OnlineStatus),
|
||||||
"software_version": resp.SoftwareVersion,
|
"software_version": resp.SoftwareVersion,
|
||||||
"switch_mode": resp.SwitchMode,
|
"switch_mode": resp.SwitchMode,
|
||||||
"last_gateway_sync_at": now,
|
"last_gateway_sync_at": now,
|
||||||
|
|||||||
Reference in New Issue
Block a user