feat: rainyun server service — list/get/start/stop/reboot/vnc/upgrade

This commit is contained in:
2026-07-28 16:02:59 +08:00
parent b817c56e9a
commit 7a19c154d0
3 changed files with 256 additions and 0 deletions
+120
View File
@@ -0,0 +1,120 @@
package rainyun
import (
"context"
"fmt"
"time"
"git.yoresee.cc/nightstar/ry/internal/provider"
)
// ServerService implements provider.ServerService for 雨云.
type ServerService struct {
client *client
}
// rainyunServer mirrors the Rainyun RCS API JSON fields.
type rainyunServer struct {
ID int `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
IP string `json:"ip"`
VCPU int `json:"vcpu"`
Memory int `json:"memory"`
Disk int `json:"disk"`
OS string `json:"os"`
Region string `json:"zone_name"`
ExpireDate string `json:"expire_date"`
}
// Response wrappers — the client unmarshals the full API envelope (code + data).
type serverListResponse struct {
Code int `json:"code"`
Data []rainyunServer `json:"data"`
}
type serverGetResponse struct {
Code int `json:"code"`
Data rainyunServer `json:"data"`
}
type vncResponse struct {
Code int `json:"code"`
Data struct {
VNCURL string `json:"vnc_url"`
} `json:"data"`
}
func (s *ServerService) List(ctx context.Context) ([]provider.Server, error) {
var resp serverListResponse
if err := s.client.get(ctx, "/product/rcs/", &resp); err != nil {
return nil, err
}
servers := make([]provider.Server, len(resp.Data))
for i, r := range resp.Data {
servers[i] = toServer(r)
}
return servers, nil
}
func (s *ServerService) Get(ctx context.Context, id string) (*provider.Server, error) {
var resp serverGetResponse
path := fmt.Sprintf("/product/rcs/%s/", id)
if err := s.client.get(ctx, path, &resp); err != nil {
return nil, err
}
sv := toServer(resp.Data)
return &sv, nil
}
func (s *ServerService) Start(ctx context.Context, id string) error {
return s.client.post(ctx, fmt.Sprintf("/product/rcs/%s/start", id), nil, nil)
}
func (s *ServerService) Stop(ctx context.Context, id string) error {
return s.client.post(ctx, fmt.Sprintf("/product/rcs/%s/stop", id), nil, nil)
}
func (s *ServerService) Reboot(ctx context.Context, id string) error {
return s.client.post(ctx, fmt.Sprintf("/product/rcs/%s/reboot", id), nil, nil)
}
func (s *ServerService) Reinstall(ctx context.Context, id, osTemplate string) error {
body := map[string]string{"os": osTemplate}
return s.client.post(ctx, fmt.Sprintf("/product/rcs/%s/changeos", id), body, nil)
}
func (s *ServerService) ResetPassword(ctx context.Context, id string) error {
return s.client.post(ctx, fmt.Sprintf("/product/rcs/%s/reset-password", id), nil, nil)
}
func (s *ServerService) GetVNC(ctx context.Context, id string) (string, error) {
var resp vncResponse
if err := s.client.get(ctx, fmt.Sprintf("/product/rcs/%s/vnc", id), &resp); err != nil {
return "", err
}
return resp.Data.VNCURL, nil
}
func (s *ServerService) Upgrade(ctx context.Context, id, plan string) error {
body := map[string]string{"plan": plan}
return s.client.post(ctx, fmt.Sprintf("/product/rcs/%s/upgrade", id), body, nil)
}
// toServer maps a rainyunServer to the provider.Server model.
func toServer(r rainyunServer) provider.Server {
expire, _ := time.Parse("2006-01-02", r.ExpireDate)
return provider.Server{
ID: fmt.Sprintf("%d", r.ID),
Name: r.Name,
Status: r.Status,
IP: r.IP,
CPU: r.VCPU,
Memory: r.Memory,
Disk: r.Disk,
OS: r.OS,
Region: r.Region,
ExpireAt: expire,
Raw: r,
}
}