fix(rock): 兼容 0666.pro 接口 points 字段字符串与数值自适应解析

1. 新增 FlexibleFloat64 类型,解决上游 /api/me 响应中 points 为字符串(如 '8271.2')导致反序列化失败的问题;
2. 服务层与数据库快照存储统一调用 Float64() 保持类型严谨;
3. 单元测试补充真实上游字符串响应场景并全绿通过。
This commit is contained in:
yml2213
2026-10-05 15:42:00 +08:00
parent 80554555d3
commit 7e5cbaf65e
3 changed files with 49 additions and 8 deletions
@@ -285,7 +285,7 @@ func TestRockService_StatsAndPurchase(t *testing.T) {
"id": 10028,
"username": "王大锤",
"role": "merchant",
"points": 8271.2,
"points": "8271.2", // 真实上游 0666.pro 返回字符串格式
"status": "active",
},
})
+46 -5
View File
@@ -8,10 +8,51 @@ import (
"io"
"net/http"
"net/url"
"strconv"
"strings"
"time"
)
// FlexibleFloat64 兼容反序列化 JSON 中的数字或字符串(如 "8271.2")
type FlexibleFloat64 float64
func (f *FlexibleFloat64) UnmarshalJSON(b []byte) error {
if len(b) == 0 || string(b) == "null" {
*f = 0
return nil
}
var n float64
if err := json.Unmarshal(b, &n); err == nil {
*f = FlexibleFloat64(n)
return nil
}
var s string
if err := json.Unmarshal(b, &s); err == nil {
s = strings.TrimSpace(s)
if s == "" {
*f = 0
return nil
}
val, err := strconv.ParseFloat(s, 64)
if err != nil {
*f = 0
return nil
}
*f = FlexibleFloat64(val)
return nil
}
*f = 0
return nil
}
func (f FlexibleFloat64) MarshalJSON() ([]byte, error) {
return json.Marshal(float64(f))
}
func (f FlexibleFloat64) Float64() float64 {
return float64(f)
}
// RockClient 负责与 0666.pro 平台进行 HTTP 通信
type RockClient struct {
baseURL string
@@ -33,11 +74,11 @@ func NewRockClient(baseURL string) *RockClient {
type RockMeResponse struct {
User struct {
ID uint64 `json:"id"`
Username string `json:"username"`
Role string `json:"role"`
Points float64 `json:"points"`
Status string `json:"status"`
ID uint64 `json:"id"`
Username string `json:"username"`
Role string `json:"role"`
Points FlexibleFloat64 `json:"points"`
Status string `json:"status"`
} `json:"user"`
Error string `json:"error,omitempty"`
}
+2 -2
View File
@@ -150,7 +150,7 @@ func (s *RockService) TestConnection(ctx context.Context, bearerToken string) (*
now := time.Now()
_ = s.db.WithContext(ctx).Model(&model.RockConfig{}).Where("id = 1").Updates(map[string]interface{}{
"username": me.User.Username,
"points": me.User.Points,
"points": me.User.Points.Float64(),
"last_heartbeat_at": now,
}).Error
@@ -271,7 +271,7 @@ func (s *RockService) PurchaseTokens(ctx context.Context, count int, isAuto bool
defer cancel()
me, meErr := s.client.GetMe(bgCtx, cfg.BearerToken)
if meErr == nil && me != nil {
_ = s.db.Model(&model.RockConfig{}).Where("id = 1").Update("points", me.User.Points).Error
_ = s.db.Model(&model.RockConfig{}).Where("id = 1").Update("points", me.User.Points.Float64()).Error
}
}()