From 9c3eba23276bf860e77b3b8f80a711bf88e15c7d Mon Sep 17 00:00:00 2001 From: NightStar Date: Tue, 28 Jul 2026 17:09:39 +0800 Subject: [PATCH] fix: PascalCase JSON fields + code:200 success + Unix timestamp ExpDate --- internal/provider/rainyun/client.go | 4 +++- internal/provider/rainyun/listdata.go | 7 +++---- internal/provider/rainyun/server.go | 8 ++++---- internal/provider/rainyun/server_test.go | 8 ++++---- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/internal/provider/rainyun/client.go b/internal/provider/rainyun/client.go index a845685..2f792c7 100644 --- a/internal/provider/rainyun/client.go +++ b/internal/provider/rainyun/client.go @@ -114,7 +114,9 @@ func (c *client) do(ctx context.Context, method, path string, body, result any, var apiResp apiResponse if err := json.Unmarshal(respBody, &apiResp); err == nil { - if resp.StatusCode >= 400 || apiResp.Code != 0 { + // Rainyun uses code:200 and code:0 both as success indicators + isError := resp.StatusCode >= 400 || (apiResp.Code != 0 && apiResp.Code != 200) + if isError { return &APIError{ StatusCode: resp.StatusCode, Method: method, diff --git a/internal/provider/rainyun/listdata.go b/internal/provider/rainyun/listdata.go index ee83eab..27c9147 100644 --- a/internal/provider/rainyun/listdata.go +++ b/internal/provider/rainyun/listdata.go @@ -13,9 +13,8 @@ func listOptions() map[string]string { } // listResponse is the JSON envelope returned by Rainyun list endpoints. -// The API wraps data in {"code":0,"data":{"records":[...],"totalRecords":N}}. -// Our client extracts apiResp.Data ({"records":[...]}), then we unmarshal into this. +// API uses PascalCase: {"code":200,"data":{"Records":[...],"TotalRecords":N}} type listResponse struct { - Records []any `json:"records"` - TotalRecords int `json:"totalRecords"` + Records []any `json:"Records"` + TotalRecords int `json:"TotalRecords"` } diff --git a/internal/provider/rainyun/server.go b/internal/provider/rainyun/server.go index d602884..28b257c 100644 --- a/internal/provider/rainyun/server.go +++ b/internal/provider/rainyun/server.go @@ -13,9 +13,9 @@ type ServerService struct { client *client } -// rainyunServer mirrors the Rainyun RCS API JSON fields. +// rainyunServer mirrors the Rainyun RCS API JSON fields (PascalCase). type rainyunServer struct { - ID int `json:"id"` + ID int `json:"ID"` Name string `json:"name"` Status string `json:"status"` IP string `json:"ip"` @@ -24,7 +24,7 @@ type rainyunServer struct { Disk int `json:"disk"` OS string `json:"os"` Region string `json:"zone_name"` - ExpireDate string `json:"expire_date"` + ExpireDate int64 `json:"ExpDate"` // Unix timestamp } func (s *ServerService) List(ctx context.Context) ([]provider.Server, error) { @@ -87,7 +87,7 @@ func (s *ServerService) Upgrade(ctx context.Context, id, plan string) error { // toServer maps a rainyunServer to the provider.Server model. func toServer(r rainyunServer) provider.Server { - expire, _ := time.Parse("2006-01-02", r.ExpireDate) + expire := time.Unix(r.ExpireDate, 0) return provider.Server{ ID: fmt.Sprintf("%d", r.ID), Name: r.Name, diff --git a/internal/provider/rainyun/server_test.go b/internal/provider/rainyun/server_test.go index 4a7c5c6..0a45faa 100644 --- a/internal/provider/rainyun/server_test.go +++ b/internal/provider/rainyun/server_test.go @@ -16,9 +16,9 @@ func TestServerList(t *testing.T) { resp := map[string]any{ "code": 0, "data": map[string]any{ - "records": []map[string]any{ + "Records": []map[string]any{ { - "id": 12001, + "ID": 12001, "name": "web-server", "status": "running", "ip": "1.2.3.4", @@ -26,10 +26,10 @@ func TestServerList(t *testing.T) { "memory": 4096, "disk": 50, "os": "Ubuntu 22.04", - "expire_date": "2026-08-15", + "ExpDate": 1756656000, }, }, - "totalRecords": 1, + "TotalRecords": 1, }, } json.NewEncoder(w).Encode(resp)