Merge branch 'feat/rcs-migration'

This commit is contained in:
2026-08-13 13:11:03 +08:00
101 changed files with 6543 additions and 15 deletions
+5
View File
@@ -41,3 +41,8 @@ opencode.json
.claude/ .claude/
.opencode/ .opencode/
.hermers/ .hermers/
# Build output (Makefile)
bin/
coverage.out
coverage.html
+43
View File
@@ -0,0 +1,43 @@
.PHONY: all build test vet fmt lint cover install tidy clean help
BINARY := ry
MAIN_PKG := ./cmd/ry
GO := go
GOFLAGS :=
OUTPUT := bin/$(BINARY)
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
LDFLAGS := -X main.version=$(VERSION) -X main.commit=$(COMMIT)
BUILD_FLAGS := -ldflags "$(LDFLAGS)"
all: build
build: ## Build the CLI binary into bin/
$(GO) build $(GOFLAGS) $(BUILD_FLAGS) -o $(OUTPUT) $(MAIN_PKG)
install: ## Install the CLI binary to GOPATH/bin
$(GO) install $(GOFLAGS) $(BUILD_FLAGS) $(MAIN_PKG)
test: ## Run all tests
$(GO) test $(GOFLAGS) -race ./...
vet: ## Run go vet
$(GO) vet ./...
fmt: ## Format all Go source files
gofmt -s -w .
$(GO) mod tidy
cover: ## Run tests with coverage and generate HTML report
$(GO) test $(GOFLAGS) -race -coverprofile=coverage.out ./...
$(GO) tool cover -html=coverage.out -o coverage.html
tidy: ## Run go mod tidy
$(GO) mod tidy
clean: ## Remove build artifacts and coverage files
rm -rf bin/ coverage.out coverage.html
help: ## Show this help message
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-10s\033[0m %s\n", $$1, $$2}'
+5
View File
@@ -6,3 +6,8 @@ type StandQueryParameters struct {
Page int `json:"page"` Page int `json:"page"`
PerPage int `json:"perPage"` PerPage int `json:"perPage"`
} }
type BasicOperationResponse struct {
Code int `json:"code"`
Data string `json:"data"`
}
+6 -6
View File
@@ -6,12 +6,12 @@ import (
) )
type queryParamsSample struct { type queryParamsSample struct {
IsRGpu *bool `json:"is_rgpu"` IsRGpu *bool `json:"is_rgpu"`
Limit int `json:"limit"` Limit int `json:"limit"`
Name string `json:"name"` Name string `json:"name"`
Options StandQueryParameters `json:"options"` Options StandQueryParameters `json:"options"`
Tags []string `json:"tags"` Tags []string `json:"tags"`
Skip string `json:"-"` Skip string `json:"-"`
NoTag string NoTag string
} }
+19
View File
@@ -0,0 +1,19 @@
package common
import "strconv"
type VncConnectionInfo struct {
Code int `json:"code"`
Data VncConnectionData `json:"data"`
}
type VncConnectionData struct {
RequestURL string `json:"RequestURL"` // 空
RedirectURL string `json:"RedirectURL"` // 空
PVEAuth string `json:"PVEAuth"` // 空
VNCProxyURL string `json:"VNCProxyURL"` // PVE代理地址(连接地址),里面会有一个unicode码(\u0026)(&),转码后就是可以直接在浏览器上使用的VNC连接地址
}
func GetVncConnectURL(v *VncConnectionInfo) (string, error) {
return strconv.Unquote(v.Data.VNCProxyURL)
}
+73
View File
@@ -0,0 +1,73 @@
package domain
import (
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 备案域名过白
//
// domain: 域名
//
// region: 区域:cn-sq1/cn-nb1/cn-xy1/cn-cq1
func (s *DomainService) AddDomainToWhiteList(domain, region string) (*common.BasicOperationResponse, error) {
path := "/product/domain_white_list"
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, AddDomainToWhiteListRequest{
Domain: domain,
Region: region,
}, &resp)
return &resp, err
}
// 获取域名白名单列表
func (s *DomainService) GetDomainWhiteList(req *GetDomainWhiteListRequest) (*GetDomainWhiteListResponse, error) {
path := "/product/domain/whitelist"
var resp GetDomainWhiteListResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
// 获取已验证域名列表
func (s *DomainService) GetVerifiedDomainList(req *GetVerifiedDomainListRequest) (*GetVerifiedDomainListResponse, error) {
path := "/product/domain/certify"
var resp GetVerifiedDomainListResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
// 添加域名认证
//
// domain: 域名
func (s *DomainService) AddDomainCertify(domain string) (*GetDomainVerificationInfoResponse, error) {
path := "/product/domain/certify"
var resp GetDomainVerificationInfoResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, AddDomainVerificationRequest{Domain: domain}, &resp)
return &resp, err
}
// 域名认证校验
//
// domain: 域名
func (s *DomainService) VerifyDomainCertify(domain string) (*common.BasicOperationResponse, error) {
path := "/product/domain/certify/verify"
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, AddDomainVerificationRequest{Domain: domain}, &resp)
return &resp, err
}
+11
View File
@@ -0,0 +1,11 @@
package domain
import "github.com/XingfenD/rainyun_api_go_sdk/apis"
type DomainService struct {
client *apis.RyClient
}
func NewDomainService(c *apis.RyClient) *DomainService {
return &DomainService{client: c}
}
+98
View File
@@ -0,0 +1,98 @@
package domain
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 添加域名DNS解析
//
// id: 域名ID
func (s *DomainService) AddDomainDNSRecord(id int, req *AddDomainDNSRecordRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/domain/%d/dns", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 修改域名DNS解析
//
// req.RecordID 指定要修改的记录
func (s *DomainService) UpdateDomainDNSRecord(id int, req *AddDomainDNSRecordRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/domain/%d/dns", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PATCH, path, nil, req, &resp)
return &resp, err
}
// 删除域名DNS解析
func (s *DomainService) DeleteDomainDNSRecord(id, recordID int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/domain/%d/dns", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_DELETE, path, nil, DeleteDomainDNSRecordRequest{RecordID: recordID}, &resp)
return &resp, err
}
// 添加域名DNSSEC
func (s *DomainService) AddDomainDNSSEC(id int, req *AddDomainDNSSECRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/domain/%d/dnssec", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 删除域名DNSSEC
func (s *DomainService) DeleteDomainDNSSEC(id int, req *DeleteDomainDNSSECRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/domain/%d/dnssec/delete", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 同步域名DNSSEC
func (s *DomainService) SyncDomainDNSSEC(id int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/domain/%d/dnssec/sync", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
// 获取域名DNS解析记录列表
//
// domainID: 域名ID
func (s *DomainService) GetDomainDNSRecordList(domainID int) (*GetDomainDNSRecordListResponse, error) {
path := fmt.Sprintf("/product/domain/%d/dns", domainID)
var resp GetDomainDNSRecordListResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
// DNS 记录列表响应
type GetDomainDNSRecordListResponse struct {
Code int `json:"code"`
Data []DomainDNSRecord `json:"data"`
}
// 域名DNS解析记录
type DomainDNSRecord struct {
ID int `json:"id"`
RecordType string `json:"record_type"`
Host string `json:"host"`
Value string `json:"value"`
TTL int `json:"ttl"`
}
+104
View File
@@ -0,0 +1,104 @@
package domain
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 关闭域名锁定
func (s *DomainService) UnlockDomain(id int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/domain/%d/lock/disable", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PUT, path, nil, nil, &resp)
return &resp, err
}
// 开启域名锁定
func (s *DomainService) LockDomain(id int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/domain/%d/lock/enable", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PUT, path, nil, nil, &resp)
return &resp, err
}
// 修改域名NS服务器
func (s *DomainService) UpdateDomainNS(id int, nss []string) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/domain/%d/nameservers", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PUT, path, nil, UpdateDomainNSRequest{NameServers: nss}, &resp)
return &resp, err
}
// 重置域名NS服务器
func (s *DomainService) ResetDomainNS(id int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/domain/%d/nameservers/reset", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
// 续费域名
func (s *DomainService) RenewDomain(id, years int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/domain/%d/renew", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, RenewDomainRequest{Years: years}, &resp)
return &resp, err
}
// 域名过户
func (s *DomainService) TransferDomain(id int, req *DomainTransferRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/domain/%d/transfer", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 更新域名管理密码
func (s *DomainService) UpdateDomainPassword(id int, password string) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/domain/%d/password", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, UpdateDomainPasswordRequest{Password: password}, &resp)
return &resp, err
}
// 获取域名whois信息
func (s *DomainService) GetDomainWhoisInfo(req *GetDomainWhoisInfoRequest) (*GetDomainWhoisInfoResponse, error) {
path := "/product/domain/whois"
var resp GetDomainWhoisInfoResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
// 检查域名能否注册
func (s *DomainService) CheckDomainAvailability(req *CheckDomainAvailableRequest) (*CheckDomainAvailableResponse, error) {
path := "/product/domain/check"
var resp CheckDomainAvailableResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
+44
View File
@@ -0,0 +1,44 @@
package domain
import (
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 获取域名列表查询参数
type GetDomainListRequest struct {
Options common.StandQueryParameters `json:"options"`
}
// 域名列表响应
type GetDomainListResponse struct {
Code int `json:"code"`
Data DomainListData `json:"data"`
}
// 域名列表数据
type DomainListData struct {
TotalRecords int `json:"TotalRecords"`
Records []DomainRecord `json:"Records"`
}
// 域名记录
type DomainRecord struct {
ID int `json:"id"`
DomainName string `json:"domain_name"`
Status string `json:"status"`
ExpireDate string `json:"expire_date"`
}
// 获取域名列表
func (s *DomainService) GetDomainList(req *GetDomainListRequest) (*GetDomainListResponse, error) {
path := "/product/domain/"
var resp GetDomainListResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
+264
View File
@@ -0,0 +1,264 @@
package domain
import "github.com/XingfenD/rainyun_api_go_sdk/apis/common"
// 添加域名过白请求
type AddDomainToWhiteListRequest struct {
Domain string `json:"domain"` // 域名
Region string `json:"region"` // 区域:cn-sq1/cn-nb1/cn-xy1/cn-cq1
}
// 获取域名白名单列表查询参数
type GetDomainWhiteListRequest struct {
Options common.StandQueryParameters `json:"options"`
}
// 域名白名单列表响应
type GetDomainWhiteListResponse struct {
Code int `json:"code"`
Data DomainWhiteListData `json:"data"`
}
// 域名白名单列表数据
type DomainWhiteListData struct {
TotalRecords int `json:"TotalRecords"`
Records []DomainWhiteListRecord `json:"Records"`
}
// 域名白名单记录
type DomainWhiteListRecord struct {
ID int `json:"id"` // ID
UID int `json:"uid"`
Domain string `json:"domain"` // 域名
SiteLicense string `json:"site_license"` // 备案号(貌似只有早期过白的会有这个)
Region string `json:"region"` // 区域
AddTime int `json:"add_time"` // 时间
Status int `json:"status"` // 状态: 1:已处理
}
// 获取已验证域名列表查询参数
type GetVerifiedDomainListRequest struct {
Options common.StandQueryParameters `json:"options"`
}
// 已验证域名列表响应
type GetVerifiedDomainListResponse struct {
Code int `json:"code"`
Data VerifiedDomainListData `json:"data"`
}
// 已验证域名列表数据
type VerifiedDomainListData struct {
TotalRecords int `json:"TotalRecords"`
Records []VerifiedDomainRecord `json:"Records"`
}
// 已验证域名记录
type VerifiedDomainRecord struct {
ID int `json:"id"` // id
UID int `json:"uid"`
Domain string `json:"domain"` // 域名
AddTime int `json:"add_time"` // 时间
}
// 添加域名认证请求
type AddDomainVerificationRequest struct {
Domain string `json:"domain"`
}
// 域名验证信息响应
type GetDomainVerificationInfoResponse struct {
Code int `json:"code"`
Data DomainVerificationData `json:"data"`
}
// 域名验证信息数据
type DomainVerificationData struct {
Rr string `json:"rr"` // 主机名
TopDomain string `json:"top_domain"` // 主域名
Record string `json:"record"` // 记录值
}
// 添加域名DNS解析请求
type AddDomainDNSRecordRequest struct {
Host string `json:"host"` // 主机名
Level int `json:"level"` // 优先等级
Line string `json:"line"` // 线路,必须有一个默认的才可以 DEFAULT/LTEL/LCNC/LMOB/LEDU/LSEO/LFOR
RainProductID int `json:"rain_product_id"` // 雨云产品id(搭配其它产品时使用)
RainProductType string `json:"rain_product_type"` // 雨云产品类型(搭配其它产品时使用) rcs/rvh/rgs/rbm
RecordID int `json:"record_id"` // 记录id(修改时使用)
TTL int `json:"ttl"` // 解析生效时间
Type string `json:"type"` // 解析类型 A/AAAA/CNAME/TXT/MX/SRV
Value string `json:"value"` // 解析值
}
// 删除域名DNS解析请求
type DeleteDomainDNSRecordRequest struct {
RecordID int `json:"record_id"` // 记录id
}
// 添加域名DNSSEC请求
type AddDomainDNSSECRequest struct {
Domain string `json:"domain"`
Keyalg string `json:"keyalg"`
Keydigest string `json:"keydigest"`
Keytag string `json:"keytag"`
Keytype string `json:"keytype"`
}
// 删除域名DNSSEC请求
type DeleteDomainDNSSECRequest struct {
Domain string `json:"domain"`
Keydigest string `json:"keydigest"`
Keytag int `json:"keytag"`
}
// 修改域名NS服务器请求
type UpdateDomainNSRequest struct {
NameServers []string `json:"name_servers"`
}
// 续费域名请求
type RenewDomainRequest struct {
Years int `json:"years"` // 续费年限
}
// 域名过户请求
type DomainTransferRequest struct {
NewTemplateInfo EditDomainTemplateRequest `json:"new_template_info"` // 和SysID二选一,如果没模板就用这个新建模板
SysID string `json:"sys_id"` // 新域名模板ID
}
// 查询域名模板列表查询参数
type GetDomainTemplateListRequest struct {
Options common.StandQueryParameters `json:"options"`
}
// 域名模板列表响应
type GetDomainTemplateListResponse struct {
Code int `json:"code"`
Data DomainTemplateListData `json:"data"`
}
// 域名模板列表数据
type DomainTemplateListData struct {
TotalRecords int `json:"TotalRecords"`
Records []DomainTemplateDetail `json:"Records"` // 域名模板详情
}
// 删除域名信息模板请求
type DeleteDomainTemplateRequest struct {
SysID string `json:"sys_id"` // 模板标识
}
// 获取域名模板详情请求
type GetDomainTemplateDetailRequest struct {
SysID string `json:"sys_id"` // 模板标识
}
// 获取域名模板详情响应
type GetDomainTemplateDetailResponse struct {
Code int `json:"code"`
Data DomainTemplateDetail `json:"data"`
}
// 域名模板详情
type DomainTemplateDetail struct {
ID int `json:"id"`
UID int `json:"uid"`
AddTime int `json:"add_time"` // 添加时间
SysID string `json:"sys_id"` // 模板标识
Type string `json:"type"` // 所有者类型,I是个人,E是企业
Owner string `json:"owner"` // 模板所有者
ContactName string `json:"contact_name"` // 联系人姓名
CompanyName string `json:"company_name"` // 企业名称,如果是企业模板就有这个
Email string `json:"email"` // 联系人邮箱
Country string `json:"country"` // 所在国家
Province string `json:"province"` // 中文,省
City string `json:"city"` // 中文,市
ZipCode string `json:"zip_code"` // 中文,邮编
Phone string `json:"phone"` // 联系电话
Address string `json:"address"` // 中文,通讯地址
IDType string `json:"id_type"` // 证件类型,如SFZ
IDNum string `json:"id_num"` // 证件值
CStatus string `json:"c_status"` // 不明, 1
CFailInfo string `json:"c_fail_info"` // 模板失败信息
RStatus string `json:"r_status"` // 不明, 1
RFailInfo string `json:"r_fail_info"` // 不明
}
// 更新域名管理密码请求
type UpdateDomainPasswordRequest struct {
Password string `json:"password"`
}
// 编辑域名模板请求
type EditDomainTemplateRequest struct {
Address string `json:"address"` // 中文,通讯地址
City string `json:"city"` // 中文,市
CompanyEnName string `json:"company_en_name"` // 企业英文名称,如果类型是企业就要传入
CompanyName string `json:"company_name"` // 企业名称,如果类型是企业就要传入
Country string `json:"country"` // 所在国家
Email string `json:"email"` // 联系人邮箱
IDImg string `json:"id_img"` // base64编码的证件照片
IDNum string `json:"id_num"` // 证件值
IDType string `json:"id_type"` // 证件类型,如SFZ
Name string `json:"name"` // 联系人名
Phone string `json:"phone"` // 联系电话
Province string `json:"province"` // 中文,省
SysID string `json:"sys_id"` // 模板标识(修改时使用)
Type string `json:"type"` // 所有者类型,I是个人,E是企业
ZipCode string `json:"zip_code"` // 中文,邮编
}
// 获取域名whois信息请求
type GetDomainWhoisInfoRequest struct {
Domain string `json:"domain"`
}
// 域名WHOIS信息响应
type GetDomainWhoisInfoResponse struct {
Code int `json:"code"`
Data DomainWhoisInfoData `json:"data"`
}
// 域名WHOIS信息数据
type DomainWhoisInfoData struct {
RegDate string `json:"reg_date"` // 注册时间
ExpDate string `json:"exp_date"` // 到期时间
Status string `json:"status"` // 域名状态
Owner string `json:"owner"` // 域名所有者
Registrar string `json:"registrar"` // 域名注册商
Email string `json:"email"` // 域名所有者邮箱
Nameserver string `json:"nameserver"` // 域名服务器
BizServer string `json:"biz_server"`
Body string `json:"body"` // 域名WHOIS信息原文
Updated string `json:"updated"` // WHOIS信息更新时间
}
// 检查域名能否注册请求
type CheckDomainAvailableRequest struct {
Domain string `json:"domain"` // 要检查的域名(中文域名同时支持汉字及punycode转码)
Suffix string `json:"suffix"` // 要检查的后缀,多个的话,用英文逗号分割
}
// 检查域名能否注册响应
type CheckDomainAvailableResponse struct {
Code int `json:"code"`
Data []CheckDomainAvailableItem `json:"data"`
}
// 检查域名能否注册数据
type CheckDomainAvailableItem struct {
IsAvail bool `json:"is_avail"` // 是否可注册
SpecialType string `json:"special_type"`
Name string `json:"name"` // 域名
Price DomainPrice `json:"price"`
}
// 域名价格
type DomainPrice struct {
FirstYearPrice int `json:"first_year_price"` // 首年价格
BuyPrice int `json:"buy_price"` // 购买价格
RenewPrice int `json:"renew_price"` // 续费价格
}
+52
View File
@@ -0,0 +1,52 @@
package domain
import (
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 查询域名模板列表
func (s *DomainService) GetDomainTemplateList(req *GetDomainTemplateListRequest) (*GetDomainTemplateListResponse, error) {
path := "/product/domain/template/"
var resp GetDomainTemplateListResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
// 删除域名信息模板
func (s *DomainService) DeleteDomainTemplate(sysID string) (*common.BasicOperationResponse, error) {
path := "/product/domain/template/"
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_DELETE, path, nil, DeleteDomainTemplateRequest{SysID: sysID}, &resp)
return &resp, err
}
// 编辑域名模板
func (s *DomainService) EditDomainTemplate(req *EditDomainTemplateRequest) (*common.BasicOperationResponse, error) {
path := "/product/domain/template"
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PUT, path, nil, req, &resp)
return &resp, err
}
// 获取域名模板详情
func (s *DomainService) GetDomainTemplateDetail(req *GetDomainTemplateDetailRequest) (*GetDomainTemplateDetailResponse, error) {
path := "/product/domain/template/detail/"
var resp GetDomainTemplateDetailResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
+11
View File
@@ -0,0 +1,11 @@
package expense
import "github.com/XingfenD/rainyun_api_go_sdk/apis"
type ExpenseService struct {
client *apis.RyClient
}
func NewExpenseService(c *apis.RyClient) *ExpenseService {
return &ExpenseService{client: c}
}
+45
View File
@@ -0,0 +1,45 @@
package expense
import (
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 订单列表查询参数
type GetOrdersListRequest struct {
Options common.StandQueryParameters `json:"options"`
}
// 订单列表响应
type GetOrdersListResponse struct {
Code int `json:"code"`
Data OrdersListData `json:"data"`
}
// 订单列表数据
type OrdersListData struct {
TotalRecords int `json:"TotalRecords"`
Records []Order `json:"Records"`
}
// 订单
type Order struct {
ID int `json:"id"`
ProductName string `json:"product_name"`
Amount float64 `json:"amount"`
Status string `json:"status"`
CreateDate string `json:"create_date"`
}
// 获取订单列表
func (s *ExpenseService) GetOrdersList(req *GetOrdersListRequest) (*GetOrdersListResponse, error) {
path := "/expense/orders/list"
var resp GetOrdersListResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
+11
View File
@@ -0,0 +1,11 @@
package product
import "github.com/XingfenD/rainyun_api_go_sdk/apis"
type ProductService struct {
client *apis.RyClient
}
func NewProductService(c *apis.RyClient) *ProductService {
return &ProductService{client: c}
}
+72
View File
@@ -0,0 +1,72 @@
package product
import (
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 产品数量
type ProductCount struct {
TotalCount int `json:"TotalCount"`
}
// RbmProductCount 域名转售(RBM)产品数量
type RbmProductCount struct {
TotalCount int `json:"TotalCount"`
AboutToExpire any `json:"AboutToExpire"`
}
// 产品数量列表
type ProductCountData struct {
Ros ProductCount `json:"ros"`
Rvh ProductCount `json:"rvh"`
Rcs ProductCount `json:"rcs"`
Rgpu ProductCount `json:"rgpu"`
Rgs ProductCount `json:"rgs"`
Ssl ProductCount `json:"ssl"`
Rbm RbmProductCount `json:"rbm"`
Domain ProductCount `json:"domain"`
Rcdn ProductCount `json:"rcdn"`
Rca ProductCount `json:"rca"`
}
type GetProductCountListResponse struct {
Code int `json:"code"`
Data ProductCountData `json:"data"`
}
// 产品ID列表
type ProductIDListData struct {
Rca []int `json:"rca"`
Rcs []int `json:"rcs"`
Ros []int `json:"ros"`
Rvh []int `json:"rvh"`
Rgpu []int `json:"rgpu"`
Rgs []int `json:"rgs"`
Ssl []int `json:"ssl"`
Rbm []int `json:"rbm"`
Domain []int `json:"domain"`
Rcdn []int `json:"rcdn"`
}
type GetProductIDListResponse struct {
Code int `json:"code"`
Data ProductIDListData `json:"data"`
}
// 获取各产品数量
func (s *ProductService) GetProductCountList() (*GetProductCountListResponse, error) {
path := "/product/"
var resp GetProductCountListResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
// 获取产品ID列表
func (s *ProductService) GetProductIDList() (*GetProductIDListResponse, error) {
path := "/product/id_list"
var resp GetProductIDListResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
+112
View File
@@ -0,0 +1,112 @@
package product
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 增减面板用户产品请求
type ModifyPanelUserProductRequests struct {
Action string `json:"action"` // 操作:add/del
ProductID int `json:"product_id"` // 产品ID
ProductType string `json:"product_type"` // 产品类型: rcs/rgs/ros/rbm 只支持这四种产品
Name string `json:"name"` // 子用户名
}
// 面板用户请求
type PanelUserRequest struct {
Name string `json:"name"`
Password string `json:"password"`
}
// 面板用户产品
type PanelUserProduct struct {
Name string `json:"name"` // 自用户名
ProductType string `json:"product_type"` // 产品类型: rcs/rgs/ros/rbm 只支持这四种产品
ProductID int `json:"product_id"` // 产品ID
}
// 面板用户记录
type PanelUserRecord struct {
Name string `json:"name"` // 面板用户名
Password string `json:"password"` // 面板用户密码
UserID int `json:"user_id"` // 你的UID
CreateDate int `json:"create_date"` // 创建时间
Products []PanelUserProduct `json:"products"` // 产品列表
}
// 面板用户列表
type PanelUserListData struct {
TotalRecords int `json:"TotalRecords"` // 面板用户总数
Records []PanelUserRecord `json:"Records"`
}
type GetPanelUserListRequest struct {
Options common.StandQueryParameters `json:"options"`
}
type GetPanelUserListResponse struct {
Code int `json:"code"`
Data PanelUserListData `json:"data"`
}
// 获取面板用户列表
func (s *ProductService) GetPanelUserList(req *GetPanelUserListRequest) (*GetPanelUserListResponse, error) {
path := "/product/panel_users/"
var resp GetPanelUserListResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
// 增减面板用户产品
func (s *ProductService) ModifyPanelUserProduct(req *ModifyPanelUserProductRequests) (*common.BasicOperationResponse, error) {
path := "/product/panel_users/"
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PUT, path, nil, req, &resp)
return &resp, err
}
// 创建面板用户
//
// name: 子用户用户名
//
// pass: 子用户密码
func (s *ProductService) CreatePanelUser(name string, pass string) (*common.BasicOperationResponse, error) {
path := "/product/panel_users/"
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, PanelUserRequest{Name: name, Password: pass}, &resp)
return &resp, err
}
// 面板用户改密
//
// name: 子用户用户名
//
// pass: 子用户新密码
func (s *ProductService) ChangePanelUserPassword(name string, pass string) (*common.BasicOperationResponse, error) {
path := "/product/panel_users/"
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PATCH, path, nil, PanelUserRequest{Name: name, Password: pass}, &resp)
return &resp, err
}
// 删除面板用户
//
// name: 子用户用户名
func (s *ProductService) DeletePanelUser(name string) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/panel_users/%s", name)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_DELETE, path, nil, nil, &resp)
return &resp, err
}
+22
View File
@@ -0,0 +1,22 @@
package product
import (
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 积分续费请求
type PointRenewalRequest struct {
DurationDay int `json:"duration_day"` // 续费天数
ProductID int `json:"product_id"` // 产品ID
ProductType string `json:"product_type"` // 产品类型: rcs/rgs/ros/rvh/rcdn
}
// 积分续费
func (s *ProductService) PointRenewal(req *PointRenewalRequest) (*common.BasicOperationResponse, error) {
path := "/product/point_renew"
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
+41
View File
@@ -0,0 +1,41 @@
package public
import "github.com/XingfenD/rainyun_api_go_sdk/constant"
// https://api.rainyun.com/#/paths/product~1rgs~1egg_type/get
// 获取蛋(游戏类型)类型列表
type GetEggTypeListResponse struct {
Code int `json:"code"`
Data []EggTypeItem `json:"data"`
}
type EggTypeItem struct {
ID int `json:"id"` // 蛋(游戏类型)ID
EggName string `json:"egg_name"` // 蛋(游戏类型)名称
Egg EggItem `json:"egg"`
Docker string `json:"docker"` // docker镜像地址
McsmDocker string `json:"mcsm_docker"`
Env EggTypeEnv `json:"env"`
Order int `json:"order"`
IsHidden bool `json:"is_hidden"`
UpdateTime int `json:"update_time"`
AutoUpdate bool `json:"auto_update"`
}
type EggTypeEnv struct {
ServerType string `json:"SERVER_TYPE"`
ServerVersion string `json:"SERVER_VERSION"`
Subver string `json:"SUBVER"`
Latest bool `json:"LATEST"`
Prerelease bool `json:"PRERELEASE"`
}
func (s *PublicService) GetEggTypeList() (*GetEggTypeListResponse, error) {
path := "/product/rgs/egg_type"
var resp GetEggTypeListResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
+31
View File
@@ -0,0 +1,31 @@
package public
import "github.com/XingfenD/rainyun_api_go_sdk/constant"
// https://api.rainyun.com/#/paths/product~1rgs~1egg/get
// 获取蛋(游戏)列表
type GetEggListResponse struct {
Code int `json:"code"`
Data []EggItem `json:"data"`
}
type EggItem struct {
Name string `json:"name"` // 名称
EggGroup string `json:"egg_group"` // 分组
Title string `json:"title"` // 标题
Desc string `json:"desc"` // 描述
IconURL string `json:"icon_url"` // 图标
Order int `json:"order"` // 排序
IsHidden bool `json:"is_hidden"` // 是否隐藏
SaveDirs []string `json:"save_dirs"` // 重装时建议的需要保留的目录
}
func (s *PublicService) GetEggList() (*GetEggListResponse, error) {
path := "/product/rgs/egg"
var resp GetEggListResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
+39
View File
@@ -0,0 +1,39 @@
package public
import "github.com/XingfenD/rainyun_api_go_sdk/constant"
// https://api.rainyun.com/#/paths/product~1rcs~1os-templates/get
// 获取RCS操作系统列表
type GetRcsOSListResponse struct {
Code int `json:"code"`
Data []RcsOSListItem `json:"data"`
}
type RcsOSListItem struct {
ID int `json:"id"` // 系统ID
Region string `json:"region"` // 地域
Subtype string `json:"subtype"` // 类型(kvm)
Machine string `json:"machine"` // unknown
Name string `json:"name"` // 英文名
Version string `json:"version"` // 版本
SyncStatus string `json:"sync_status"`
OsType string `json:"os_type"` // 系统类型(windows/linux)
ChineseName string `json:"chinese_name"` // 中文名
Icon string `json:"icon"` // 图标
IsWithBbr bool `json:"is_with_bbr"` // 是否支持BBR
IsEol bool `json:"is_eol"` // 是否已过时
IsAvailable bool `json:"is_available"` // 是否可用
Order int `json:"order"` // 排序
LatestFilename string `json:"latest_filename"` // 最新文件名
NoVMAgent bool `json:"no_vm_agent"` // 是否无虚拟机Agent
}
func (s *PublicService) GetRcsOSList() (*GetRcsOSListResponse, error) {
path := "/product/rcs/os-templates"
var resp GetRcsOSListResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
+39
View File
@@ -0,0 +1,39 @@
package public
import "github.com/XingfenD/rainyun_api_go_sdk/constant"
// https://api.rainyun.com/#/paths/product~1rgs~1os-templates/get
// 获取游戏云系统列表
type GetRgsOSListResponse struct {
Code int `json:"code"`
Data []RgsOSListItem `json:"data"`
}
type RgsOSListItem struct {
ID int `json:"id"`
Region string `json:"region"`
Subtype string `json:"subtype"`
Machine string `json:"machine"`
Name string `json:"name"`
Version string `json:"version"`
SyncStatus string `json:"sync_status"`
OsType string `json:"os_type"`
ChineseName string `json:"chinese_name"`
Icon string `json:"icon"`
IsWithBbr bool `json:"is_with_bbr"`
IsEol bool `json:"is_eol"`
IsAvailable bool `json:"is_available"`
Order int `json:"order"`
LatestFilename string `json:"latest_filename"`
NoVMAgent bool `json:"no_vm_agent"`
}
func (s *PublicService) GetRgsOSList() (*GetRgsOSListResponse, error) {
path := "/product/rgs/os-templates"
var resp GetRgsOSListResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
+38
View File
@@ -0,0 +1,38 @@
package public
import "github.com/XingfenD/rainyun_api_go_sdk/constant"
// https://api.rainyun.com/#/paths/product~1ros~1plans/get
// 获取对象存储套餐列表
type GetRosPlanListResponse struct {
Code int `json:"code"`
Data []RosPlanItem `json:"data"`
}
type RosPlanItem struct {
ID int `json:"id"`
Region string `json:"region"`
Subtype string `json:"subtype"`
PlanName string `json:"plan_name"`
Machine string `json:"machine"`
ChargeType string `json:"charge_type"`
Chinese string `json:"chinese"`
IsFree bool `json:"is_free"`
PointRenewPrice any `json:"point_renew_price"` // 积分续费价格
IsSelling bool `json:"is_selling"`
Price int `json:"price"`
StorageSize int `json:"storage_size"`
Bandwidth int `json:"bandwidth"`
ExtraTransferPrice float64 `json:"extra_transfer_price"`
ExtraStoragePrice float64 `json:"extra_storage_price"`
}
func (s *PublicService) GetRosPlanList() (*GetRosPlanListResponse, error) {
path := "/product/ros/plans"
var resp GetRosPlanListResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
+22
View File
@@ -0,0 +1,22 @@
package rbm
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// RBM实例更换系统请求
type RBMChangeOSRequest struct {
OsID int `json:"os_id"`
}
// RBM实例更换系统
func (s *RbmService) ChangeRBMOS(id int, req *RBMChangeOSRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rbm/%d/changeos", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
+11
View File
@@ -0,0 +1,11 @@
package rbm
import "github.com/XingfenD/rainyun_api_go_sdk/apis"
type RbmService struct {
client *apis.RyClient
}
func NewRbmService(c *apis.RyClient) *RbmService {
return &RbmService{client: c}
}
+60
View File
@@ -0,0 +1,60 @@
package rbm
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 创建并绑定弹性IP到RBM请求
type RBMAssociateEIPRequest struct {
WithFlags string `json:"with_flags"` // IP特征(可选)
WithIPNum int `json:"with_ip_num"` // 数量
WithIPType string `json:"with_ip_type"` // IPv4/IPv6
}
// 更换IP请求
type RBMChangeIPRequest struct {
DisableOldIPReason string `json:"disable_old_ip_reason"` // 禁用旧IP的原因(可选)
IP string `json:"ip"` // 旧IP地址
ToIP string `json:"to_ip"` // 不明,可选
}
// 设置IP描述请求
type RBMSetIPDescriptionRequest struct {
Description string `json:"description"`
IP string `json:"ip"`
}
// 放弃IP请求
type RBMReleaseIPRequest struct {
IP string `json:"ip"`
}
// 创建并绑定弹性IP到RBM
func (s *RbmService) AssociateEIP(id int, req *RBMAssociateEIPRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rbm/%d/eip", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 设置IP描述
func (s *RbmService) SetIPDescription(id int, req *RBMSetIPDescriptionRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rbm/%d/eip/description", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 放弃IP
func (s *RbmService) ReleaseIP(id int, req *RBMReleaseIPRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rbm/%d/eip/discard", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
+44
View File
@@ -0,0 +1,44 @@
package rbm
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// RBM实例启动KVM代理
func (s *RbmService) StartKVMAgent(id int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rbm/%d/kvm-proxy", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
// RBM重新启动KVM
func (s *RbmService) RestartKVM(id int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rbm/%d/kvm-reboot", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
// RBM实例关机
func (s *RbmService) ShutdownRBM(id int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rbm/%d/poweroff", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
// RBM实例开机
func (s *RbmService) StartRBM(id int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rbm/%d/poweron", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
+42
View File
@@ -0,0 +1,42 @@
package rbm
import "github.com/XingfenD/rainyun_api_go_sdk/constant"
type GetRbmPlanListResponse struct {
Code int `json:"code"`
Data []RbmPlan `json:"data"`
}
// RbmPlan RBM套餐
type RbmPlan struct {
ID int `json:"id"` // 套餐ID
Region string `json:"region"` // 地域
Line string `json:"line"` // 线路 3c/single/bgp
Subtype string `json:"subtype"` // rbm
PlanName string `json:"plan_name"` // 套餐名称
Machine string `json:"machine"` // 意义不明 generic/generic_2
ChargeType string `json:"charge_type"` // 计费方式 package(流量不限)/package_traffic(流量叠加)
Chinese string `json:"chinese"` // 中文名
IsFree bool `json:"is_free"` // 是否免费(为什么会有这种参数)
PointRenewPrice any `json:"point_renew_price"` // 积分续费价格,全是 null
IsSelling bool `json:"is_selling"` // 是否在售
Price int `json:"price"` // 价格
TrafficBaseGb int `json:"traffic_base_gb"` // 流量基数,单位GB
TrafficPrice any `json:"traffic_price"` // 流量价格,单位GB,package_traffic 计费方式才有值
CPU int `json:"cpu"` // cpu核数
Memory int `json:"memory"` // 内存,单位GB
Storage int `json:"storage"` // 存储,单位GB
NetIn int `json:"net_in"` // 入网带宽,单位Mbps
NetOut int `json:"net_out"` // 出网带宽,单位Mbps
AvailableStock int `json:"available_stock"` // 可用库存
IPPrices any `json:"ip_prices"` // IP价格,单位元/月
}
// 获取RBM套餐列表
func (s *RbmService) GetRBMPlanList() (*GetRbmPlanListResponse, error) {
path := "/product/rbm/models"
var resp GetRbmPlanListResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
+22
View File
@@ -0,0 +1,22 @@
package rbm
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 充流量请求
type RBMChargeTrafficRequest struct {
TrafficInGb int `json:"traffic_in_gb"`
}
// 充流量
func (s *RbmService) ChargeTraffic(id int, req *RBMChargeTrafficRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rbm/%d/traffic/charge", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
+172
View File
@@ -0,0 +1,172 @@
package rca
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 云应用创建App模板请求
type RcaCreateAppTemplateRequest struct {
CrossVersionUpdate bool `json:"cross_version_update"` // 是否支持跨版本更新
Description string `json:"description"` // 描述
DisableUpdate bool `json:"disable_update"` // 是否禁用版本更新功能,禁用后已安装应用无法检测到更新
Logo string `json:"logo"` // logo(base64),最大50KB,可以不传
Name string `json:"name"` // 应用名称(英文标识)
ProjectLink string `json:"project_link"` // 应用项目链接
Readme string `json:"readme"` // 介绍(markdown)
Tags []string `json:"tags"` // 标签,多选,目前支持的tag可以参考现有应用
Title string `json:"title"` // 应用标题
Website string `json:"website"` // 应用官方网站链接
}
// App模板
type AppTemplate struct {
ID int `json:"id"` // 模板id
UID int `json:"uid"`
Name string `json:"name"`
Title string `json:"title"`
Description string `json:"description"`
Logo string `json:"logo"`
Type string `json:"type"`
Tags []string `json:"tags"`
Website string `json:"website"`
Github string `json:"github"`
CreateDate int `json:"create_date"`
Readme string `json:"readme"`
Provider string `json:"provider"`
CrossVersionUpdate bool `json:"cross_version_update"`
Downloads int `json:"downloads"`
IsPublic bool `json:"is_public"`
ReviewStatus string `json:"review_status"`
ReviewComment string `json:"review_comment"`
StopReason string `json:"stop_reason"`
DisableUpdate bool `json:"disable_update"`
}
type RcaCreateAppTemplateResponse struct {
Code int `json:"code"`
Data AppTemplate `json:"data"`
}
// App模板版本
type AppTemplateVersion struct {
ID int `json:"id"`
Version string `json:"version"`
IsPublic bool `json:"is_public"`
}
type AppTemplateVersionData struct {
Data AppTemplate `json:"data"`
Versions []AppTemplateVersion `json:"versions"`
}
type CreateAppTemplateVersionResponse struct {
Code int `json:"code"`
Data AppTemplateVersionData `json:"data"`
}
// 配置文件
type AppTemplateConfigMap struct {
ContainerPath string `json:"container_path"` // 配置文件存放在容器里面的目录
Content string `json:"content"` // 文件内容,最大1MB
FileName string `json:"file_name"` // 文件名
}
// 环境变量
type AppTemplateEnv struct {
Key string `json:"key"` // 键
Value string `json:"value"` // 值,允许空白
}
// 安装选项
type AppTemplateOption struct {
Default string `json:"default"` // 默认值
Disabled bool `json:"disabled"` // 是否不允许编辑
EnvKey string `json:"env_key"` // 绑定到环境变量的Key
Label string `json:"label"` // 标签,告知用户这个选项是干什么用的,例如root用户密码
Random bool `json:"random"` // 是否进行随机化生成
Required bool `json:"required"` // 是否必选
Rule string `json:"rule"` // 规则,可用项目按照前端已实现支持的规则来
Type string `json:"type"` // 类型,如:password number等
Value string `json:"value"` // 填入值
Values []AppTemplateOptionValue `json:"values"` // 选项,type为select时提供给客户选择
}
// 选项可选值
type AppTemplateOptionValue struct {
Label string `json:"label"` // 提示显示
Value string `json:"value"` // 对应值
}
// 资源需求
type AppTemplateResourceRequest struct {
MinCPU int `json:"min_cpu"` // 如1000,单位是m
MinMemory int `json:"min_memory"` // 如4096,单位是Mi
}
// 脚本钩子
type AppTemplateScripts struct {
Install string `json:"install"` // install(安装应用的时候执行,可以用于下载特定的持久化文件,可以指定运行环境,在底层这个是用initContainer来实现
InstallImage string `json:"install_image"` // 执行安装脚本所使用的容器镜像,其他阶段会使用运行时镜像
PostStart string `json:"post_start"` // poststart(容器创建后立即执行)
PreStop string `json:"pre_stop"` // prestop(终止前运行)
}
// 服务
type AppTemplateService struct {
ExternalPort string `json:"external_port"` // 外部端口,之所以是string,因为支持以变量形式传入
InternalPort string `json:"internal_port"` // 内部端口,对应AppPort,之所以是string,因为支持以变量形式传入
Label string `json:"label"` // 标签,可以是中文
Name string `json:"name"` // 服务名称
Protocol string `json:"protocol"` // 协议
Type string `json:"type"` // 类型,可以是internal或external,对应clusterIP或者lb
}
// 文件目录挂载
type AppTemplateVolumeMount struct {
MountContentType string `json:"mount_content_type"` // 挂载类型,文件file或目录dir
MountPath string `json:"mount_path"` // 容器内路径
Name string `json:"name"` // 挂载描述
PreContent string `json:"pre_content"` // file类型专用,以base64存储的预先准备二进制数据,这个是用于一些小型二进制文件例如.db或者如/etc/localtime等的预先准备,模拟在docker中如"./data/cloudreve.db:/cloudreve/cloudreve.db"或/etc/timezone:/etc/timezone:ro
SubPath string `json:"sub_path"` // Project卷内路径,不能以.或者/开头
}
// 创建App模板版本请求
//
// 我尝试创建了一个函数用于将docker compose文件转换成这种格式,但在编写了近1000行代码后,我成功的放弃了这个想法
// :(
type CreateAppTemplateVersionRequest struct {
Args []string `json:"args"` // 运行参数
Command []string `json:"command"` // 运行命令
ConfigMaps []AppTemplateConfigMap `json:"config_maps"`
Env []AppTemplateEnv `json:"env"` // 环境变量
Image string `json:"image"` // 容器镜像,如nginx:1.21.0
Options []AppTemplateOption `json:"options"`
ReleaseID int `json:"release_id"` // 更新用release ID
ResourceRequest AppTemplateResourceRequest `json:"resource_request"` // 资源需求
Scripts AppTemplateScripts `json:"scripts"` // 脚本钩子
Services []AppTemplateService `json:"services"`
Version string `json:"version"` // 版本号,如1.21.0
VolumeMounts []AppTemplateVolumeMount `json:"volume_mounts"` // 文件目录,如data:/var/lib/mysql
}
// 云应用创建App模板
func (s *RcaService) CreateRcaAppTemplate(req *RcaCreateAppTemplateRequest) (*RcaCreateAppTemplateResponse, error) {
path := "/product/rca/appstore/"
var resp RcaCreateAppTemplateResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 创建App模板版本
//
// id: APP模板ID
func (s *RcaService) CreateRcaAppTemplateVersion(id int, req *CreateAppTemplateVersionRequest) (*CreateAppTemplateVersionResponse, error) {
path := fmt.Sprintf("/product/rca/appstore/%d/release", id)
var resp CreateAppTemplateVersionResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
+11
View File
@@ -0,0 +1,11 @@
package rca
import "github.com/XingfenD/rainyun_api_go_sdk/apis"
type RcaService struct {
client *apis.RyClient
}
func NewRcaService(c *apis.RyClient) *RcaService {
return &RcaService{client: c}
}
+254
View File
@@ -0,0 +1,254 @@
package rca
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 云应用区域信息
type PriceInfo struct {
Cpu float64 `json:"cpu"`
Memory float64 `json:"memory"`
Ipv4 float64 `json:"ipv4"`
Traffic float64 `json:"traffic"`
Disk float64 `json:"disk"`
}
type RcaRegion struct {
ID int `json:"id"`
Name string `json:"name"`
ChineseName string `json:"chinese_name"`
WebsiteServiceDomain string `json:"website_service_domain"`
SftpServiceDomain string `json:"sftp_service_domain"`
PublicServiceDomain string `json:"public_service_domain"`
PriceInfo PriceInfo `json:"price_info"`
}
type GetRcaRegionInfoResponse struct {
Code int `json:"code"`
Data []RcaRegion `json:"data"`
}
// 开通云应用产品请求
type ActivateRcaRequest struct {
RegionID int `json:"region_id"`
}
// 创建云应用项目请求
type CreateRcaProjectRequest struct {
ChargeType string `json:"charge_type"` // 计费类型: 动态计费: elastic
CPULimit int `json:"cpu_limit"` // (仅限package模式)CPU限制(毫核),1核心=1000,0.1核=100
DiskSize int `json:"disk_size"` // 磁盘大小(GiB)
Ipv4Count int `json:"ipv4_count"` // 要添加的IPv4地址数量
Ipv6Count int `json:"ipv6_count"` // 要添加的IPv6地址数量
MemoryLimit int `json:"memory_limit"` // (仅限package模式)内存限制(MiB)
Name string `json:"name"` // 名称
RegionID int `json:"region_id"` // 部署区域
}
// 云应用节点信息
type RcaNode struct {
UUID string `json:"UUID"`
AuthKey string `json:"AuthKey"`
Region string `json:"Region"`
IPRegion string `json:"IpRegion"`
Machine string `json:"Machine"`
Product string `json:"Product"`
Subtype string `json:"Subtype"`
ChineseName string `json:"ChineseName"`
PhysicalNode string `json:"PhysicalNode"`
Config string `json:"Config"`
Stock any `json:"Stock"`
StatusData string `json:"StatusData"`
ShowMonitorData string `json:"ShowMonitorData"`
UpdateTime string `json:"UpdateTime"`
GitRepositoryName string `json:"GitRepositoryName"`
CertifyRequired bool `json:"CertifyRequired"`
IsDisableBackup bool `json:"IsDisableBackup"`
IsHidden bool `json:"IsHidden"`
NodeName string `json:"NodeName"`
}
type RcaResourceLimits struct {
MaxCPU int `json:"max_cpu"`
MaxMemory int `json:"max_memory"`
}
// 云应用项目资源使用情况
type RcaProjectUsageData struct {
CPU int `json:"cpu"`
Memory int `json:"memory"`
NetOut int `json:"net_out"`
NetIn int `json:"net_in"`
DiskUsage int `json:"disk_usage"`
TrafficToday int `json:"traffic_today"`
Status string `json:"status"`
StatusReason string `json:"status_reason"`
AllocatedCPU int `json:"allocated_cpu"`
AllocatedMemory int `json:"allocated_memory"`
AppCount int `json:"app_count"`
WebsiteCount int `json:"website_count"`
DatabaseCount int `json:"database_count"`
Ipv4Count int `json:"ipv4_count"`
HealthyPods int `json:"healthy_pods"`
UnhealthyPods int `json:"unhealthy_pods"`
}
// 备份目标
type RcaBackupTarget struct {
Type string `json:"type"` // 目标类型,支持项目本地备份或者远程S3存储(local/s3)
S3Endpoint string `json:"s3_endpoint"` // S3的端点(仅支持Virtual Host,不支持Path-Style模式)
S3Bucket string `json:"s3_bucket"` // S3存储桶名
S3AccessKey string `json:"s3_access_key"` // S3的AK
S3SecretKey string `json:"s3_secret_key"` // S3的SK
S3BackupDirectory string `json:"s3_backup_directory"` // s3备份存储的目录
}
// 云应用项目
type RcaProject struct {
ID int `json:"ID"`
UID int `json:"UID"`
PlanID int `json:"PlanID"`
CreateDate int `json:"CreateDate"` // 创建时间
NodeUUID string `json:"NodeUUID"`
Node RcaNode `json:"Node"`
Status string `json:"Status"`
StopReason string `json:"StopReason"`
RewardPointsToBeCollect int `json:"RewardPointsToBeCollect"`
Tag string `json:"Tag"`
ExpDate int `json:"ExpDate"`
ExpireNotice int `json:"ExpireNotice"`
AutoRenew bool `json:"AutoRenew"`
UnsubscribeAble bool `json:"UnsubscribeAble"`
Try bool `json:"Try"`
Name string `json:"name"`
RegionID int `json:"region_id"`
Region *RcaRegion `json:"region"`
Namespace string `json:"namespace"`
APIToken string `json:"APIToken"`
ResourceLimits RcaResourceLimits `json:"resource_limits"`
UsageData RcaProjectUsageData `json:"usage_data"`
VolumeSize int `json:"volume_size"`
ChargeType string `json:"charge_type"` // 计费类型: elastic
HourlyPrice float64 `json:"hourly_price"` // 小时价格
NextChargeTime int `json:"next_charge_time"`
BackupTarget RcaBackupTarget `json:"backup_target"` // 备份目标
SftpSetting any `json:"sftp_setting"`
IdleAlarmFlag bool `json:"idle_alarm_flag"`
PaymentDueEnd int `json:"payment_due_end"`
}
type CreateRcaProjectResponse struct {
Code int `json:"code"`
Data RcaProject `json:"data"`
}
type RcaProjectListData struct {
TotalRecords int `json:"TotalRecords"`
Records []RcaProject `json:"Records"`
}
type GetRcaProjectListResponse struct {
Code int `json:"code"`
Data RcaProjectListData `json:"data"`
}
// 云应用项目的指标信息,示例如下:
type RcaProjectMetricsData struct {
Columns []string `json:"Columns"`
Values [][]float64 `json:"Values"`
}
type GetRcaProjectMetricsResponse struct {
Code int `json:"code"`
Data RcaProjectMetricsData `json:"data"`
}
type RcaProjectDetailData struct {
Data RcaProject `json:"Data"`
}
type GetRcaProjectDetailResponse struct {
Code int `json:"code"`
Data RcaProjectDetailData `json:"data"`
}
// 云应用获取区域信息
func (s *RcaService) GetRcaRegionInfo() (*GetRcaRegionInfoResponse, error) {
path := "/product/rca/region"
var resp GetRcaRegionInfoResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
// 开通云应用产品
//
// regionID: 地域ID
func (s *RcaService) ActivateRca(regionID int) (*common.BasicOperationResponse, error) {
path := "/product/rca/activate"
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, ActivateRcaRequest{RegionID: regionID}, &resp)
return &resp, err
}
// 创建云应用项目
func (s *RcaService) CreateRcaProject(req *CreateRcaProjectRequest) (*CreateRcaProjectResponse, error) {
path := "/product/rca/project/"
var resp CreateRcaProjectResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 云应用列出项目
//
// options: 查询参数 可以用 EncodingStandardQueryParameters 获取.
func (s *RcaService) ListRcaProjects(options string) (*GetRcaProjectListResponse, error) {
path := "/product/rca/project/"
querys := map[string]string{"no_metrics": "false", "options": options} // no_metrics 含义不明
var resp GetRcaProjectListResponse
err := s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
// 销毁云应用项目
//
// id: RCA项目ID
func (s *RcaService) DestroyRcaProject(id int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rca/project/%d/", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_DELETE, path, nil, nil, &resp)
return &resp, err
}
// 获取Rca项目的指标信息
//
// id: RCA项目ID
//
// starttime: 开始时间(timestamp)
//
// endtime: 结束时间(timestamp)
func (s *RcaService) GetRcaProjectMetrics(id int, startTime int, endTime int) (*GetRcaProjectMetricsResponse, error) {
path := fmt.Sprintf("/product/rca/project/%d/metrics?start_time=%d&end_time=%d", id, startTime, endTime)
var resp GetRcaProjectMetricsResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
// 获取云应用项目详情
//
// id: RCA项目ID
func (s *RcaService) GetRcaProjectDetail(id int) (*GetRcaProjectDetailResponse, error) {
path := fmt.Sprintf("/product/rca/project/%d/", id)
var resp GetRcaProjectDetailResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
+128
View File
@@ -0,0 +1,128 @@
package rca
import (
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 云应用雨点余额使用情况
type RcaRaindropUsageData struct {
ExpectedRemainDays int `json:"expected_remain_days"` // 预计剩余天数
LastMonthUsage float64 `json:"last_month_usage"` // 上月使用量
ExpectedNextMonthUsage float64 `json:"expected_next_month_usage"` // 预计下月使用量
FreeTrialRemainDays int `json:"free_trial_remain_days"` // 剩余免费试用天数
IsBeforeFirstPayment bool `json:"is_before_first_payment"`
}
type GetRcaRaindropUsageResponse struct {
Code int `json:"code"`
Data RcaRaindropUsageData `json:"data"`
}
// 雨点套餐
type RaindropPlan struct {
ID int `json:"id"`
Amount int `json:"amount"`
Price int `json:"price"`
IsSelling bool `json:"is_selling"`
PlanName string `json:"plan_name"`
Chinese string `json:"chinese"`
}
type GetRcaRaindropPlansListResponse struct {
Code int `json:"code"`
Data []RaindropPlan `json:"data"`
}
// 雨点消费明细
type RaindropConsumeData struct {
BasicPrice float64 `json:"basic_price"`
TrafficBytes int `json:"traffic_bytes"`
TrafficPrice float64 `json:"traffic_price"`
}
// 雨点消费记录
type RaindropConsumeRecord struct {
ID int `json:"id"`
UID int `json:"uid"`
Time int `json:"time"`
Type string `json:"type"`
ProductID int `json:"product_id"`
Amount float64 `json:"amount"`
Data RaindropConsumeData `json:"data"`
}
// 雨点消费历史
type RaindropConsumeLogData struct {
TotalRecords int `json:"TotalRecords"`
Records []RaindropConsumeRecord `json:"Records"`
}
type GetRaindropConsumeLogResponse struct {
Code int `json:"code"`
Data RaindropConsumeLogData `json:"data"`
}
// 云应用购买雨点请求
type BuyRaindropRequest struct {
PlanID int `json:"plan_id"`
WithCouponID int `json:"with_coupon_id"`
}
// 雨点余额
type GetRcaRaindropBalanceResponse struct {
Code int `json:"code"`
Data float64 `json:"data"`
}
// 云应用获取雨点余额使用情况
func (s *RcaService) GetRcaRaindropUsage() (*GetRcaRaindropUsageResponse, error) {
path := "/product/rca/raindrop/usage"
var resp GetRcaRaindropUsageResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
// 云应用获取雨点套餐列表
func (s *RcaService) GetRcaRaindropPlansList() (*GetRcaRaindropPlansListResponse, error) {
path := "/product/rca/raindrop/plans"
var resp GetRcaRaindropPlansListResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
// 云应用获取雨点消费历史
//
// options: 查询参数 可以用 EncodingStandardQueryParameters 获取.
func (s *RcaService) GetRaindropConsumeLog(options string) (*GetRaindropConsumeLogResponse, error) {
path := "/product/rca/raindrop/consume_log"
querys := map[string]string{"options": options}
var resp GetRaindropConsumeLogResponse
err := s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
// 云应用购买雨点
//
// planID: 雨点套餐ID
//
// couponID: 优惠券ID
func (s *RcaService) BuyRaindrop(planID int, couponID int) (*common.BasicOperationResponse, error) {
path := "/product/rca/raindrop"
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, BuyRaindropRequest{PlanID: planID, WithCouponID: couponID}, &resp)
return &resp, err
}
// 云应用获取雨点余额
func (s *RcaService) GetRcaRaindropBalance() (*GetRcaRaindropBalanceResponse, error) {
path := "/product/rca/raindrop"
var resp GetRcaRaindropBalanceResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
+130
View File
@@ -0,0 +1,130 @@
package rca
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 云应用项目设置备份目标请求
type SetRcaProjectBackupTargetRequest struct {
S3AccessKey string `json:"s3_access_key"` // S3的AK
S3BackupDirectory string `json:"s3_backup_directory"` // s3备份存储的目录
S3Bucket string `json:"s3_bucket"` // S3存储桶名
S3Endpoint string `json:"s3_endpoint"` // S3的端点(仅支持Virtual Host,不支持Path-Style模式)
S3SecretKey string `json:"s3_secret_key"` // S3的SK
TargetType string `json:"target_type"` // 目标类型,支持项目本地备份或者远程S3存储(local/s3)
}
// 云应用项目磁盘扩容请求
type RcaProjectDiskExpansionRequest struct {
NewDiskSize int `json:"new_disk_size"` // 以GB显示的新项目磁盘大小
}
// 云应用增加IP地址请求
type RcaAddsIpAddressRequest struct {
Ipv4Count int `json:"ipv4_count"` // 要添加的IPv4地址数量
Ipv6Count int `json:"ipv6_count"` // 要添加的IPv6地址数量
}
// 云应用移除IP地址请求
type RcaRemoveIPRequest struct {
IPID int `json:"ip_id"` // 要删除的IP地址ID
}
// 云应用项目修改SFTP设置请求
type RcaProjectSetSftpConfigRequest struct {
Password string `json:"password"`
Username string `json:"username"`
}
// 云应用IP信息
type RcaIP struct {
ID int `json:"id"` // ip id
Region string `json:"region"` // 地域
Type string `json:"type"` // ip类型(IPv4/IPv6)
IP string `json:"ip"` // ip地址
AddressPool string `json:"address_pool"` // ip池(user-ip-pool)
Gateway string `json:"gateway"` // 网关
Block string `json:"block"` // CIDR(24)
UID int `json:"uid"` // 用户id
ProjectID int `json:"project_id"`
Info string `json:"info"`
AllocatedDate int `json:"allocated_date"` // 分配时间
}
type GetRcaProjectIPsResponse struct {
Code int `json:"code"`
Data []RcaIP `json:"data"`
}
// 云应用项目设置备份目标
//
// id: RCA项目ID
func (s *RcaService) SetRcaProjectBackupTarget(id int, req *SetRcaProjectBackupTargetRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rca/project/%d/backup_target", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PATCH, path, nil, req, &resp)
return &resp, err
}
// 云应用项目磁盘扩容
//
// id: RCA项目ID
func (s *RcaService) ExpandRcaProjectDisk(id int, req *RcaProjectDiskExpansionRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rca/project/%d/disk_expand", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 云应用增加IP地址
//
// id: RCA项目ID
func (s *RcaService) AddRcaProjectIP(id int, req *RcaAddsIpAddressRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rca/project/%d/eip", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 云应用移除IP地址
//
// id: RCA项目ID
func (s *RcaService) RemoveRcaProjectIP(id int, req *RcaRemoveIPRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rca/project/%d/eip", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_DELETE, path, nil, req, &resp)
return &resp, err
}
// 云应用项目修改SFTP设置
//
// id: RCA项目ID
//
// password: 密码
//
// username: 用户名
func (s *RcaService) SetRcaProjectSFTPConfig(id int, password string, username string) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rca/project/%d/sftp", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PATCH, path, nil, RcaProjectSetSftpConfigRequest{Password: password, Username: username}, &resp)
return &resp, err
}
// 云应用项目列出IP地址
//
// id: RCA项目ID
func (s *RcaService) ListRcaProjectIPs(id int) (*GetRcaProjectIPsResponse, error) {
path := fmt.Sprintf("/product/rca/project/%d/eip", id)
var resp GetRcaProjectIPsResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
+58
View File
@@ -0,0 +1,58 @@
package rcs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
type CreateRcsBackupRequest struct {
Label string `json:"label"` // 备份名称
}
type RcsSetBackupOptionsRequest struct {
AutoBackupHour int `json:"auto_backup_hour"` // 自动备份时间的小时
AutoBackupMinute int `json:"auto_backup_minute"` // 自动备份时间的分钟
KeepLast int `json:"keep_last"` // 保留份数(1/3/7)
}
func (s *RcsService) CreateRcsBackup(id int, label string) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/backup", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, CreateRcsBackupRequest{Label: label}, &resp)
return &resp, err
}
func (s *RcsService) DeleteRcsBackup(id, bid int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/backup/%d", id, bid)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_DELETE, path, nil, nil, &resp)
return &resp, err
}
func (s *RcsService) CancelRcsBackup(id, bid int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/backup/%d/cancel", id, bid)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
func (s *RcsService) RestoreRcsBackup(id, bid int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/backup/%d/restore", id, bid)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
func (s *RcsService) EnableRcsAutoBackup(id int, req *RcsSetBackupOptionsRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/backup/setting", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PATCH, path, nil, req, &resp)
return &resp, err
}
+26
View File
@@ -0,0 +1,26 @@
package rcs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
type ReinstallRcsRequest struct {
AppVars []struct {
AppID int `json:"app_id"`
Retry bool `json:"retry"` // 重发之前的任务,此项存在时,无需传入参数
Vars any `json:"vars"`
} `json:"app_vars"` // 当空数组时,进行单次任务下发
OsID int `json:"os_id"` // 系统ID
ResetOsd bool `json:"reset_osd"` // 重置系统盘容量
}
func (s *RcsService) ReinstallRcs(id int, req *ReinstallRcsRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/changeos", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
+36
View File
@@ -0,0 +1,36 @@
package rcs
import (
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
type CreateRcsRequest struct {
AddDiskSize int `json:"add_disk_size"` // 额外硬盘容量GB
PlanID int `json:"plan_id"` // 套餐ID
Duration int `json:"duration"` // 创建时长(月)
OsID int `json:"os_id"` // 系统ID
WithEipNum int `json:"with_eip_num"` // 创建IP数量
WithEipFlags string `json:"with_eip_flags"` // 是否开启高防,us_ddosip -> 美国高防,nb_ddosip -> 宁波高防
WithEipType string `json:"with_eip_type"` // ipv4(默认)/ipv6
WithCouponID int `json:"with_coupon_id"` // 优惠券ID
Try bool `json:"try"` // 是否为试用
NodeUUID string `json:"node_uuid"` // 指定节点(管理员可用,用户不可用)
AppVars []struct {
AppID int `json:"app_id"`
Vars any `json:"vars,omitempty"`
} `json:"app_vars"` // 预装应用
Zone string `json:"zone"` // 内网可用区
}
type CreateRcsResponse struct {
Code int `json:"code"`
Data RcsRecord `json:"data"`
}
func (s *RcsService) CreateRcs(req *CreateRcsRequest) (*CreateRcsResponse, error) {
path := "/product/rcs"
var resp CreateRcsResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
+36
View File
@@ -0,0 +1,36 @@
package rcs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
type RcsManagesElasticCloudDisksRequest struct {
Actions []struct {
Type string `json:"type"` // 操作类型: expand: 扩容, create: 创建
Action any `json:"action"` // 操作参数, RcsManagesElasticCloudDisksExpand或RcsManagesElasticCloudDisksCreate
} `json:"actions"`
}
type RcsManagesElasticCloudDisksExpand struct {
EdiskID int `json:"edisk_id"` // 弹性云盘ID
SizeInGb int `json:"size_in_gb"` // 操作容量
Backup bool `json:"backup"` // 支持备份
}
type RcsManagesElasticCloudDisksCreate struct {
SizeInGb int `json:"size_in_gb"` // 操作容量
DiskType string `json:"disk_type"` // 磁盘类型(ssd/hdd)
Backup bool `json:"backup"` // 支持备份
Tag string `json:"tag"` // 标签
}
func (s *RcsService) RcsManagesElasticCloudDisks(id int, req *RcsManagesElasticCloudDisksRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/edisk", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
+61
View File
@@ -0,0 +1,61 @@
package rcs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
type SetRcsEipDescriptionRequest struct {
IP string `json:"ip"`
Description string `json:"description"`
}
type CreateAndBindIpToRcsRequest struct {
WithFlags string `json:"with_flags"` // IP特征(可选): 应该是高防: us_ddosip -> 美国高防,nb_ddosip -> 宁波高防
WithIPNum int `json:"with_ip_num"` // IP数量
WithIPType string `json:"with_ip_type"` // ipv4/ipv6
}
type ChangeRcsIPRequest struct {
DisableOldIPReason string `json:"disable_old_ip_reason"` // 可选
IP string `json:"ip"` // IP地址
ToIP string `json:"to_ip"` // 可选
}
type DisCardRcsIPRequest struct {
IP string `json:"ip"`
}
func (s *RcsService) SetRcsEipDescription(id int, ip, desc string) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/eip/description", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, SetRcsEipDescriptionRequest{IP: ip, Description: desc}, &resp)
return &resp, err
}
func (s *RcsService) CreateAndBindElasticIpToRcs(id int, req *CreateAndBindIpToRcsRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/eip", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
func (s *RcsService) ChangeRcsIP(id int, req *ChangeRcsIPRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/eip/change", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
func (s *RcsService) DisCardRcsIP(id int, req DisCardRcsIPRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/eip/discard", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
+86
View File
@@ -0,0 +1,86 @@
package rcs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
type GetRcsFirewallRulesRequest struct {
Options common.StandQueryParameters `json:"options"`
}
type GetRcsFirewallRulesResponse struct {
Code int `json:"code"`
Data RcsFirewallRuleList `json:"data"`
}
type RcsFirewallRuleList struct {
TotalRecords int `json:"TotalRecords"`
Records []RcsFirewallRule `json:"Records"`
}
type RcsFirewallRule struct {
ID int `json:"ID"`
VID int `json:"v_id"`
IsEnable bool `json:"is_enable"`
Pos int `json:"pos"`
SourceAddress string `json:"source_address"`
DestPort string `json:"dest_port"`
SourcePort string `json:"source_port"`
Protocol string `json:"protocol"`
Action string `json:"action"`
Description string `json:"description"`
}
type SetRcsFirewallRuleRequest struct {
Action string `json:"action"` // 动作,accept/drop,接受或者丢弃
Description string `json:"description"` // 备注(可选)
DestPort string `json:"dest_port"` // 代表本机的目的端口,可以用-来链接,空白代表所有端口(可选)
ID int `json:"id"` // 规则ID(可选)
IsEnable bool `json:"is_enable"` // 是否启用该规则(可选)
Protocol string `json:"protocol"` // 协议,udp/tcp/icmp,空白代表所有(可选)
SourceAddress string `json:"source_address"` // 代表来源的地址,可以用-链接范围,或者用逗号来分割多个地址,可以使用网络,CIDR格式,空则代表所有地址(可选)
SourcePort string `json:"source_port"` // 一般不填(防反射)(可选)
}
type MobileRcsFirewallRulePriorityRequest struct {
NewPos int `json:"newPos"`
}
func (s *RcsService) GetRcsFirewallRules(id int, req *GetRcsFirewallRulesRequest) (*GetRcsFirewallRulesResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/firewall/rule", id)
var resp GetRcsFirewallRulesResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
func (s *RcsService) SetRcsFirewallRule(id int, req *SetRcsFirewallRuleRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/firewall/rule", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
func (s *RcsService) DeleteRcsFirewallRule(id, ruleID int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/firewall/rule/%d", id, ruleID)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_DELETE, path, nil, nil, &resp)
return &resp, err
}
func (s *RcsService) MobileRcsFirewallRulePriority(id, ruleID int, req MobileRcsFirewallRulePriorityRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/firewall/rule/%d/pos", id, ruleID)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PUT, path, nil, req, &resp)
return &resp, err
}
+124
View File
@@ -0,0 +1,124 @@
package rcs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
type GetRcsDetailResponse struct {
Code int `json:"code"`
Data RcsDetail `json:"data"`
}
type RcsDetail struct {
Data RcsRecord `json:"Data"`
UpgradeablePlans []UpgradeablePlan `json:"UpgradeablePlans"`
RBSList []RBSItem `json:"RBSList"`
NatList []any `json:"NatList"`
EDiskList []EDiskItem `json:"EDiskList"`
EIPList []EIPItem `json:"EIPList"`
RenewPointPrice RenewPointPrice `json:"RenewPointPrice"`
FastInstallAppTask []any `json:"FastInstallAppTask"`
VNets []any `json:"VNets"`
}
type UpgradeablePlan struct {
ID int `json:"id"`
Region string `json:"region"`
Subtype string `json:"subtype"`
PlanName string `json:"plan_name"`
Machine string `json:"machine"`
ChargeType string `json:"charge_type"`
Chinese string `json:"chinese"`
IsFree bool `json:"is_free"`
PointRenewPrice any `json:"point_renew_price"`
IsSelling bool `json:"is_selling"`
Price int `json:"price"`
TrafficBaseGb int `json:"traffic_base_gb"`
TrafficPrice any `json:"traffic_price"`
CPU int `json:"cpu"`
Memory int `json:"memory"`
NetIn int `json:"net_in"`
NetOut int `json:"net_out"`
IPPrices any `json:"ip_prices"`
IPSelling any `json:"ip_selling"`
AutoRestock int `json:"auto_restock"`
AvailableStock int `json:"available_stock"`
GpuMemorySize int `json:"gpu_memory_size"`
DgpuDevType string `json:"dgpu_dev_type"`
WebbarConfig any `json:"webbar_config"`
NoBackup bool `json:"no_backup"`
DiskPrice DiskPrice `json:"disk_price"`
}
type RBSItem struct {
ID int `json:"ID"`
UID int `json:"UID"`
ProductID int `json:"ProductID"`
NodeUUID string `json:"NodeUUID"`
Node Node `json:"Node"`
Label string `json:"Label"`
FileName string `json:"FileName"`
PackSize int64 `json:"PackSize"`
CreateTime int `json:"CreateTime"`
FinishTime int `json:"FinishTime"`
Retry int `json:"Retry"`
AdditionalInfo RBSAdditionalInfo `json:"AdditionalInfo"`
Status string `json:"Status"`
}
type RBSAdditionalInfo struct {
Osid int `json:"OSID"`
OSName string `json:"OSName"`
OSBaseDiskSize int `json:"OSBaseDiskSize"`
OSDataDiskSize int `json:"OSDataDiskSize"`
Slots map[string]RBSSlot `json:"Slots"`
}
type RBSSlot struct {
DiskType string `json:"DiskType"`
Backup bool `json:"Backup"`
Size int `json:"Size"`
}
type EDiskItem struct {
ID int `json:"ID"`
Slot int `json:"Slot"`
UID int `json:"UID"`
DiskType string `json:"DiskType"`
Tag string `json:"Tag"`
OSName string `json:"OSName"`
Vid int `json:"VID"`
Size int `json:"Size"`
Backup bool `json:"Backup"`
}
type EIPItem struct {
ID int `json:"ID"`
IPRegion string `json:"IpRegion"`
Region string `json:"Region"`
Type string `json:"Type"`
IP string `json:"IP"`
Gateway string `json:"Gateway"`
Block string `json:"Block"`
UID int `json:"UID"`
Vid int `json:"VID"`
CreateDate int `json:"CreateDate"`
Flags string `json:"Flags"`
VlanID int `json:"VlanID"`
Description string `json:"Description"`
}
type RenewPointPrice struct {
Num7 int `json:"7"`
Num31 int `json:"31"`
}
func (s *RcsService) GetRcsDetail(id int) (*GetRcsDetailResponse, error) {
path := fmt.Sprintf("/product/rcs/%d", id)
var resp GetRcsDetailResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
+2 -2
View File
@@ -47,9 +47,9 @@ type UsageData struct {
UsedMem int `json:"UsedMem"` UsedMem int `json:"UsedMem"`
Disks DiskUsageData `json:"Disks"` Disks DiskUsageData `json:"Disks"`
DiskRead int `json:"DiskRead"` DiskRead int `json:"DiskRead"`
DiskWrite int `json:"DiskWrite"` DiskWrite float64 `json:"DiskWrite"`
NetOut float64 `json:"NetOut"` NetOut float64 `json:"NetOut"`
NetIn int `json:"NetIn"` NetIn float64 `json:"NetIn"`
SmartHealth any `json:"SmartHealth"` SmartHealth any `json:"SmartHealth"`
SmartTemp int `json:"SmartTemp"` SmartTemp int `json:"SmartTemp"`
UpdateTime int `json:"UpdateTime"` UpdateTime int `json:"UpdateTime"`
+64
View File
@@ -0,0 +1,64 @@
package rcs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
type ResetRcsPasswordRequest struct {
Password string `json:"password"` // 新密码,留空则自动生成
}
type SetRcsTagRequest struct {
TagName string `json:"tag_name"`
}
func (s *RcsService) FreeRcs(id int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/free", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
func (s *RcsService) RebootRcs(id int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/reboot", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
func (s *RcsService) ResetRcsPassword(id int, newPass string) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/reset-password", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, ResetRcsPasswordRequest{Password: newPass}, &resp)
return &resp, err
}
func (s *RcsService) StartRcs(id int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/start", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
func (s *RcsService) StopRcs(id int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/stop", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
func (s *RcsService) SetRcsTag(id int, tag string) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/tag", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, SetRcsTagRequest{TagName: tag}, &resp)
return &resp, err
}
+36
View File
@@ -0,0 +1,36 @@
package rcs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
type GetRcsMonitorDataRequest struct {
StartDate int `json:"start_date"` // 开始时间(时间戳)
EndDate int `json:"end_date"` // 结束时间(时间戳)
}
type GetRcsMonitorDataResponse struct {
Code int `json:"code"`
Data RcsMonitorData `json:"data"`
}
// RcsMonitorData 监控数据, Columns 与 Values 一一对应
type RcsMonitorData struct {
Columns []string `json:"Columns"`
Values [][]float64 `json:"Values"`
}
func (s *RcsService) GetRcsMonitorData(id int, req *GetRcsMonitorDataRequest) (*GetRcsMonitorDataResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/monitor", id)
var resp GetRcsMonitorDataResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
+39
View File
@@ -0,0 +1,39 @@
package rcs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
type AddRcsNatPortMappingRequest struct {
PortIn int `json:"port_in"` // >= 1 <= 65535
PortOut int `json:"port_out"` // >= 10000 <= 60000
PortType string `json:"port_type"` // tcp/udp/tcp_udp
Tag string `json:"tag"` // 可选
}
type DeleteRcsNatPortMappingRequest struct {
NatID int `json:"nat_id"`
}
func (s *RcsService) AddRcsNatPortMapping(id int, req *AddRcsNatPortMappingRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/nat", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
func (s *RcsService) DeleteRcsNatPortMapping(id int, req *DeleteRcsNatPortMappingRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/nat", id)
var resp common.BasicOperationResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_DELETE, path, querys, nil, &resp)
return &resp, err
}
+82
View File
@@ -0,0 +1,82 @@
package rcs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
type GetRcsRenewPriceRequest struct {
ProductID int `json:"product_id"`
Duration int `json:"duration"`
WithCouponID int `json:"with_coupon_id"`
}
type GetRcsRenewPriceResponse struct {
Code int `json:"code"`
Data RcsRenewPrice `json:"data"`
}
type RcsRenewPrice struct {
Detail RcsRenewPriceDetail `json:"detail"`
Price float64 `json:"price"`
}
type RcsRenewPriceDetail struct {
Price float64 `json:"price"`
AgentPrice float64 `json:"agent_price"`
StockPrice float64 `json:"stock_price"`
DefaultPrice int `json:"default_price"`
CouponValue int `json:"coupon_value"`
SaleReward int `json:"sale_reward"`
AgentReward int `json:"agent_reward"`
AgentID int `json:"agent_id"`
IgnoreAgent bool `json:"ignore_agent"`
PerScene RcsRenewPerScene `json:"per_scene"`
}
type RcsRenewPerScene struct {
Eip int `json:"eip"`
Renew float64 `json:"renew"` // 配置价格
RenewEip float64 `json:"renew_eip"` // IP价格
}
type RenewRcsRequest struct {
Duration int `json:"duration"` // 续费时长(月)
WithCouponID int `json:"with_coupon_id"` // 优惠券ID
}
type EnableRcsAutoRenewRequest struct {
AutoRenewOption bool `json:"auto_renew_option"`
}
func (s *RcsService) GetRcsRenewPrice(req *GetRcsRenewPriceRequest) (*GetRcsRenewPriceResponse, error) {
path := "/product/rcs/price"
var resp GetRcsRenewPriceResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
querys["scene"] = "renew"
querys["is_old"] = "true"
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
func (s *RcsService) RenewRcs(id int, req RenewRcsRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/renew", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
func (s *RcsService) EnableRcsAutoRenew(id int, req EnableRcsAutoRenewRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/renew/option", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
+33
View File
@@ -0,0 +1,33 @@
package rcs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
type ChargeRcsTraficRequest struct {
TrafficInGb int `json:"traffic_in_gb"` // 充多少G
}
type LimitRcsTrafficRequest struct {
DayTrafficInGb int `json:"day_traffic_in_gb"` // 日流量阈值(G)
TrafficLimit int `json:"traffic_limit"` // 限制带宽(M)
}
func (s *RcsService) ChargeRcsTrafic(id, count int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/traffic/charge", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, ChargeRcsTraficRequest{TrafficInGb: count}, &resp)
return &resp, err
}
func (s *RcsService) LimitRcsTrafic(id, threshold, limit int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/traffic/limit", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, LimitRcsTrafficRequest{DayTrafficInGb: threshold, TrafficLimit: limit}, &resp)
return &resp, err
}
+21
View File
@@ -0,0 +1,21 @@
package rcs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
type UpgradeRcsRequest struct {
DestPlan int `json:"dest_plan"` // 升级到的套餐ID
WithCouponID int `json:"with_coupon_id"` // 优惠券ID,默认为0
}
func (s *RcsService) UpgradeRcs(id, plan, coupon int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rcs/%d/upgrade", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, UpgradeRcsRequest{DestPlan: plan, WithCouponID: coupon}, &resp)
return &resp, err
}
+36
View File
@@ -0,0 +1,36 @@
package rcs
import (
"fmt"
"net/url"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// GetRcsVnc 连接VNC
//
// consoleType: 控制台类型,可选值: novnc,xtermjs
func (s *RcsService) GetRcsVnc(id int, consoleType string) (*common.VncConnectionInfo, error) {
path := fmt.Sprintf("/product/rcs/%d/vnc", id)
var resp common.VncConnectionInfo
querys := map[string]string{"console_type": consoleType}
err := s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
// GetRcsPveAddress 获取RCS对应的PVE地址
func (s *RcsService) GetRcsPveAddress(id int) (string, error) {
v, err := s.GetRcsVnc(id, "novnc")
if err != nil {
return "", err
}
parsedURL, err := url.Parse(v.Data.RequestURL)
if err != nil {
return "", err
}
return parsedURL.Hostname(), nil
}
+68
View File
@@ -0,0 +1,68 @@
package rgs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/apis/rcs"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 游戏云创建备份
//
// id: 游戏云 ID
//
// label: 备份标签
func (s *RgsService) CreateRgsBackup(id int, label string) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/backup", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, rcs.CreateRcsBackupRequest{Label: label}, &resp)
return &resp, err
}
// 游戏云删除备份
//
// id: 游戏云 ID, bid: 备份ID
func (s *RgsService) DeleteRgsBackup(id, bid int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/backup/%d", id, bid)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_DELETE, path, nil, nil, &resp)
return &resp, err
}
// 游戏云取消备份
//
// id: RGS ID, bid: 备份ID
func (s *RgsService) CancelRgsBackup(id, bid int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/backup/%d/cancel", id, bid)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
// 游戏云还原备份
//
// id: 游戏云 ID, bid: 备份ID
func (s *RgsService) RestoreRgsBackup(id, bid int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/backup/%d/restore", id, bid)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
// 游戏云设置备份选项
//
// id: RGS ID
//
// 没错就是Rcs,这俩是一样的
func (s *RgsService) EnableRgsAutoBackup(id int, req *rcs.RcsSetBackupOptionsRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/backup/setting", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PATCH, path, nil, req, &resp)
return &resp, err
}
+20
View File
@@ -0,0 +1,20 @@
package rgs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/apis/rcs"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 游戏云重装系统
//
// id: RGS ID
func (s *RgsService) ReinstallRgs(id int, req *rcs.ReinstallRcsRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/changeos", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
+11
View File
@@ -0,0 +1,11 @@
package rgs
import "github.com/XingfenD/rainyun_api_go_sdk/apis"
type RgsService struct {
client *apis.RyClient
}
func NewRgsService(c *apis.RyClient) *RgsService {
return &RgsService{client: c}
}
+157
View File
@@ -0,0 +1,157 @@
package rgs
import "github.com/XingfenD/rainyun_api_go_sdk/constant"
// 创建游戏云请求
type CreateRgsRequest struct {
AppVars []RgsAppVar `json:"app_vars"` // 当空数组时,进行单次任务下发(可选)
Config RgsConfig `json:"config"`
CPULimitMode bool `json:"cpu_limit_mode"`
Duration int `json:"duration"` // 创建时长(月)
EggTypeID int `json:"egg_type_id"` // 游戏类型
NodeUUID string `json:"node_uuid"`
OnlineMode bool `json:"online_mode"`
OsID int `json:"os_id"`
PanelUser string `json:"panel_user"` // 游戏云面板用户
PayMode string `json:"pay_mode"`
PlanID int `json:"plan_id"`
Subtype string `json:"subtype"` // kvm/mcsm
Try bool `json:"try"`
WithCouponID int `json:"with_coupon_id"`
WithEipFlags string `json:"with_eip_flags"` // 是否开启高防,us_ddosip -> 美国高防,nb_ddosip -> 宁波高防
WithEipNum int `json:"with_eip_num"`
WithEipType string `json:"with_eip_type"`
Zone string `json:"zone"`
}
type RgsAppVar struct {
AppID int `json:"app_id"`
Retry bool `json:"retry"` // 重发之前的任务,此项存在时,无需传入参数
Vars any `json:"vars"`
}
// 游戏云配置信息
type RgsConfig struct {
CPU int `json:"cpu"`
Memory int `json:"memory"`
NetOut int `json:"net_out"`
NetIn int `json:"net_in"`
BaseDisk int `json:"base_disk"`
DataDisk int `json:"data_disk"`
Allocation int `json:"allocation"`
Database int `json:"database"`
Backup int `json:"backup"`
}
// 创建游戏云响应
type CreateRgsResponse struct {
Code int `json:"code"`
Data RgsCreateData `json:"data"`
}
// RgsCreateData 创建游戏云返回的完整实例数据
type RgsCreateData struct {
RgsRecord
Node RgsNode `json:"Node"` // 节点信息
Plan RgsPlan `json:"Plan"`
EggTypeID int `json:"EggTypeId"`
EggType any `json:"EggType"`
PteroUserName string `json:"PteroUserName"`
PteroUser any `json:"PteroUser"`
ServerID int `json:"ServerID"`
AllocationID int `json:"AllocationID"`
ServerUUID string `json:"ServerUUID"`
DaemonUUID string `json:"DaemonUUID"`
GameInfo any `json:"GameInfo"`
}
type RgsNode struct {
UUID string `json:"UUID"`
AuthKey string `json:"AuthKey"`
Region string `json:"Region"`
IPRegion string `json:"IpRegion"`
Machine string `json:"Machine"`
Product string `json:"Product"`
Subtype string `json:"Subtype"`
ChineseName string `json:"ChineseName"`
PhysicalNode string `json:"PhysicalNode"`
Config string `json:"Config"`
Stock any `json:"Stock"`
StatusData string `json:"StatusData"`
ShowMonitorData string `json:"ShowMonitorData"`
UpdateTime string `json:"UpdateTime"`
GitRepositoryName string `json:"GitRepositoryName"`
CertifyRequired bool `json:"CertifyRequired"`
IsDisableBackup bool `json:"IsDisableBackup"`
IsHidden bool `json:"IsHidden"`
NodeName string `json:"NodeName"`
}
type RgsPlan struct {
ID int `json:"id"`
Region string `json:"region"`
Subtype string `json:"subtype"`
PlanName string `json:"plan_name"`
Machine string `json:"machine"`
ChargeType string `json:"charge_type"`
Chinese string `json:"chinese"`
IsFree bool `json:"is_free"`
PointRenewPrice any `json:"point_renew_price"`
IsSelling bool `json:"is_selling"`
StockDiscount int `json:"stock_discount"`
EipStockDiscount int `json:"eip_stock_discount"`
IPPrices any `json:"ip_prices"`
IPSelling any `json:"ip_selling"`
CPUPrice int `json:"cpu_price"`
MemoryPrice int `json:"memory_price"`
NetInPrice int `json:"net_in_price"`
NetOutPrice int `json:"net_out_price"`
BaseDiskPrice int `json:"base_disk_price"`
DataDiskPrice int `json:"data_disk_price"`
Config []RgsPlanConfig `json:"config"` // 这里不知道为什么要返还一堆套餐列表
AutoRestock int `json:"auto_restock"`
AvailableStock int `json:"available_stock"`
CPUPointDefault int `json:"cpu_point_default"`
CPUPointConsume int `json:"cpu_point_consume"`
CPUPointPrice float64 `json:"cpu_point_price"`
CPUBase float64 `json:"cpu_base"`
CPUMax int `json:"cpu_max"`
EipPrice int `json:"eip_price"`
DefencePrice int `json:"defence_price"`
AllocationPrice int `json:"allocation_price"`
DatabasePrice int `json:"database_price"`
BackupPrice int `json:"backup_price"`
DailyModeSupport bool `json:"daily_mode_support"`
DailyPriceScale int `json:"daily_price_scale"`
}
type RgsPlanConfig struct {
CPU int `json:"cpu"`
Memory int `json:"memory"`
NetIn int `json:"net_in,omitempty"`
CPUMax int `json:"cpu_max,omitempty"`
CPUMin int `json:"cpu_min,omitempty"`
NetOut int `json:"net_out"`
BaseDisk int `json:"base_disk,omitempty"`
DataDisk int `json:"data_disk,omitempty"`
BasePrice int `json:"base_price"`
MemoryMax int `json:"memory_max"`
MemoryMin int `json:"memory_min"`
NetInMax int `json:"net_in_max,omitempty"`
NetInMin int `json:"net_in_min,omitempty"`
NetOutMax int `json:"net_out_max,omitempty"`
NetOutMin int `json:"net_out_min"`
BaseDiskMax int `json:"base_disk_max,omitempty"`
BaseDiskMin int `json:"base_disk_min,omitempty"`
DataDiskMax int `json:"data_disk_max,omitempty"`
DataDiskMin int `json:"data_disk_min,omitempty"`
}
// 创建游戏云
func (s *RgsService) CreateRgs(req *CreateRgsRequest) (*CreateRgsResponse, error) {
path := "/product/rgs"
var resp CreateRgsResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
+42
View File
@@ -0,0 +1,42 @@
package rgs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/apis/rcs"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 创建并绑定弹性IP到游戏云
//
// id: 游戏云 ID
func (s *RgsService) CreateAndBindElasticIpToRgs(id int, req *rcs.CreateAndBindIpToRcsRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/eip", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 更换游戏云IP
//
// id: 游戏云 ID
func (s *RgsService) ChangeRgsIP(id int, req *rcs.ChangeRcsIPRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/eip/change", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 放弃游戏云IP
//
// id: 游戏云ID
func (s *RgsService) DisCardRgsIP(id int, req rcs.DisCardRcsIPRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/eip/discard", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
+66
View File
@@ -0,0 +1,66 @@
package rgs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/apis/rcs"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
type GetRgsFirewallRulesRequest struct {
Options common.StandQueryParameters `json:"options"`
}
type GetRgsFirewallRulesResponse struct {
Code int `json:"code"`
Data rcs.RcsFirewallRuleList `json:"data"`
}
// 获取游戏云防火墙规则列表
//
// id: 游戏云 ID
func (s *RgsService) GetRgsFirewallRules(id int, req *GetRgsFirewallRulesRequest) (*GetRgsFirewallRulesResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/firewall/rule", id)
var resp GetRgsFirewallRulesResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
// 创建/设置游戏云防火墙规则
//
// id: 游戏云 ID
func (s *RgsService) SetRgsFirewallRule(id int, req *rcs.SetRcsFirewallRuleRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/firewall/rule", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 删除游戏云防火墙规则
//
// id: 游戏云 ID
func (s *RgsService) DeleteRgsFirewallRule(id, ruleID int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/firewall/rule/%d", id, ruleID)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_DELETE, path, nil, nil, &resp)
return &resp, err
}
// 移动游戏云防火墙规则优先级
//
// id: 游戏云 ID
func (s *RgsService) MobileRgsFirewallRulePriority(id, ruleID int, req rcs.MobileRcsFirewallRulePriorityRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/firewall/rule/%d/pos", id, ruleID)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PUT, path, nil, req, &resp)
return &resp, err
}
+46
View File
@@ -0,0 +1,46 @@
package rgs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 游戏云详情
// 由于响应实在过于庞大,我们只维护部分必要的响应,如有扩展需求,请在项目的data文件夹下寻找响应实例自行解码
type GetRgsDetailResponse struct {
Code int `json:"code"`
Data RgsDetailData `json:"data"`
}
type RgsDetailData struct {
Data RgsRecord `json:"Data"`
NatList []RgsNatItem `json:"NatList"` // 端口映射列表
EIPList any `json:"EIPList"`
ConfigPrice int `json:"ConfigPrice"`
RenewPointPrice RgsRenewPointPrice `json:"RenewPointPrice"` // 积分续费
}
type RgsNatItem struct {
ID int `json:"ID"`
PortIn int `json:"PortIn"`
PortOut int `json:"PortOut"`
PortType string `json:"PortType"`
Tag string `json:"Tag"`
}
type RgsRenewPointPrice struct {
Num7 int `json:"7"` // 积分续费七天
Num31 int `json:"31"` // 积分续费31天
}
// 获取游戏云详情
//
// id: 游戏云 ID
func (s *RgsService) GetRgsDetail(id int) (*GetRgsDetailResponse, error) {
path := fmt.Sprintf("/product/rgs/%d", id)
var resp GetRgsDetailResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
+126
View File
@@ -0,0 +1,126 @@
package rgs
import (
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
type GetRgsListRequest struct {
Options common.StandQueryParameters `json:"options"`
}
type GetRgsListResponse struct {
Code int `json:"code"`
Data RgsListData `json:"data"`
}
type RgsListData struct {
TotalRecords int `json:"TotalRecords"`
Records []RgsRecord `json:"Records"`
}
// 游戏云记录信息
// 由于响应实在过于庞大,我们只维护部分必要的响应,如有扩展需求,请在项目的data文件夹下寻找响应实例自行解码
type RgsRecord struct {
ExpDate int `json:"ExpDate"`
ExpireNotice int `json:"ExpireNotice"`
AutoRenew bool `json:"AutoRenew"`
UnsubscribeAble bool `json:"UnsubscribeAble"`
Try bool `json:"Try"`
ID int `json:"ID"`
UID int `json:"UID"`
PlanID int `json:"PlanID"`
CreateDate int `json:"CreateDate"`
Status string `json:"Status"`
StopReason string `json:"StopReason"`
RewardPointsToBeCollect int `json:"RewardPointsToBeCollect"` // 待领取的积分
Tag string `json:"Tag"`
OsID int `json:"OsID"`
OsName string `json:"OsName"`
HostName string `json:"HostName"`
DefaultPass string `json:"DefaultPass"`
MainIPv4 string `json:"MainIPv4"`
IntIPv4 string `json:"IntIPv4"`
UsageData RgsUsageData `json:"UsageData"`
Zone string `json:"Zone"`
NatPublicIP string `json:"NatPublicIP"`
NatPublicDomain string `json:"NatPublicDomain"`
NATSpareDomain string `json:"NATSpareDomain"`
NetIn int `json:"NetIn"`
NetOut int `json:"NetOut"`
NowNetIn int `json:"NowNetIn"`
NowNetOut int `json:"NowNetOut"`
NetMode string `json:"NetMode"`
BridgeSyncing bool `json:"BridgeSyncing"`
VnetID int `json:"VnetID"`
UpdateTime int `json:"UpdateTime"`
FwSyncTime int `json:"FwSyncTime"`
FwMode string `json:"FwMode"`
AbCPULimit int `json:"AbCpuLimit"`
AbNetLimit int `json:"AbNetLimit"`
AbWhiteReason string `json:"AbWhiteReason"`
OsInfo RgsOsInfo `json:"OsInfo"`
CPU int `json:"CPU"`
Memory int `json:"Memory"`
BaseDisk int `json:"BaseDisk"`
DataDisk int `json:"DataDisk"`
InitedDate int `json:"InitedDate"`
Allocation int `json:"Allocation"`
Database int `json:"Database"`
Backup int `json:"Backup"`
CPULimitMode bool `json:"CpuLimitMode"`
CPULimitStatus bool `json:"CpuLimitStatus"`
CPUPoint int `json:"CpuPoint"`
DailyMode bool `json:"DailyMode"` // 是否日付模式
RBSKeepLast int `json:"RBSKeepLast"`
RBSAutoBackup string `json:"RBSAutoBackup"`
RBSLastAutoBackupDate int `json:"RBSLastAutoBackupDate"`
McsmUserName string `json:"McsmUserName"`
McsmUser McsmUser `json:"McsmUser"`
}
type RgsUsageData struct {
CPU int `json:"CPU"`
Mem int `json:"Mem"`
MemUsage int `json:"MemUsage"`
DiskRead int `json:"DiskRead"`
DiskWrite int `json:"DiskWrite"`
Disk int `json:"Disk"`
NetOut int `json:"NetOut"`
NetIn int `json:"NetIn"`
UpdateTime int `json:"UpdateTime"`
}
type RgsOsInfo struct {
ID int `json:"id"`
Region string `json:"region"`
Subtype string `json:"subtype"`
Machine string `json:"machine"`
Name string `json:"name"`
Version string `json:"version"`
SyncStatus string `json:"sync_status"`
OsType string `json:"os_type"`
ChineseName string `json:"chinese_name"`
Icon string `json:"icon"`
IsWithBbr bool `json:"is_with_bbr"`
IsEol bool `json:"is_eol"`
IsAvailable bool `json:"is_available"`
Order int `json:"order"`
LatestFilename string `json:"latest_filename"`
NoVMAgent bool `json:"no_vm_agent"`
}
// 获取游戏云列表
//
// options: 查询参数 可以用 common.StandQueryParameters 获取
func (s *RgsService) GetRgsList(req *GetRgsListRequest) (*GetRgsListResponse, error) {
path := "/product/rgs"
var resp GetRgsListResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
+164
View File
@@ -0,0 +1,164 @@
package rgs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/apis/rcs"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 通用模式切换请求
type RgsSwitchModeRequest struct {
Mode bool `json:"mode"`
}
// 游戏云CPU充电请求
type ChargeRgsCPURequest struct {
Mode string `json:"mode"` // 支付方式(money/point)
Money int `json:"money"` // 消耗用户余额(支付方式为point时0)
Points int `json:"points"` // 消耗用户积分(支付方式为money时0)
}
// 游戏云更换egg(游戏类型)请求
type ChangeRgsEggRequest struct {
EggTypeID int `json:"egg_type_id"` // 蛋ID
SaveDirs []string `json:"save_dirs"` // 要保留的目录
}
// 释放游戏云
//
// id: 游戏云ID
func (s *RgsService) FreeRgs(id int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/free", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
// 游戏云重启操作
//
// id: RGS ID
func (s *RgsService) RebootRgs(id int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/reboot", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
// 游戏云重置密码
//
// id: 游戏云ID
//
// newPass: 新密码,留空则自动生成
func (s *RgsService) ResetRgsPassword(id int, newPass string) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/reset-password", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, rcs.ResetRcsPasswordRequest{Password: newPass}, &resp)
return &resp, err
}
// 游戏云开机
//
// id: 游戏云ID
func (s *RgsService) StartRgs(id int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/start", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
// 游戏云关机
//
// id: 游戏云ID
func (s *RgsService) StopRgs(id int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/stop", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
// 设置游戏云标签
//
// id: 游戏云ID
//
// tag: 标签
func (s *RgsService) SetRgsTag(id int, tag string) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/tag", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, rcs.SetRcsTagRequest{TagName: tag}, &resp)
return &resp, err
}
// 游戏云限制模式(是否用余额结算)切换
//
// id: 游戏云 ID
//
// useMoney: 是否用余额结算CPU电量
func (s *RgsService) SwitchRgsBalanceMode(id int, useMoney bool) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/cpu-limit-mode", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, RgsSwitchModeRequest{Mode: useMoney}, &resp)
return &resp, err
}
// 游戏云日付模式开关
//
// id: 游戏云 ID
//
// dailyMode: true: 开启日付模式,false: 关闭日付模式
func (s *RgsService) SwitchRgsDailyMode(id int, dailyMode bool) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/daily-mode", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, RgsSwitchModeRequest{Mode: dailyMode}, &resp)
return &resp, err
}
// 游戏云CPU充电
//
// id: 游戏云 ID
func (s *RgsService) ChargeRgsCPU(id int, req *ChargeRgsCPURequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/cpu-charge", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 游戏云升级
//
// id: 游戏云ID
//
// plan: 升级到的套餐ID
//
// coupon: 优惠券ID,默认为0
func (s *RgsService) UpgradeRgs(id, plan, coupon int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/upgrade", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, rcs.UpgradeRcsRequest{DestPlan: plan, WithCouponID: coupon}, &resp)
return &resp, err
}
// 游戏云更换egg(游戏类型)
//
// 此操作需要二步验证
//
// eggTypeID: 游戏类型ID
//
// saveDirs: 要保留的目录
func (s *RgsService) ChangeRgsEgg(id int, eggTypeID int, saveDirs []string) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/change-egg", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, ChangeRgsEggRequest{EggTypeID: eggTypeID, SaveDirs: saveDirs}, &resp)
return &resp, err
}
+53
View File
@@ -0,0 +1,53 @@
package rgs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// MCSM面板用户
type McsmUser struct {
Name string `json:"name"`
Password string `json:"password"`
UserID int `json:"user_id,omitempty"`
PanelUUID string `json:"panel_uuid,omitempty"`
}
// 创建MCSM面板用户
//
// name: 用户名
//
// password: 密码
func (s *RgsService) CreateMcsmUser(name, password string) (*common.BasicOperationResponse, error) {
path := "/product/rgs/mcsm/panel_user"
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, McsmUser{Name: name, Password: password}, &resp)
return &resp, err
}
// 编辑MCSM面板用户
//
// name: 用户名
//
// password: 密码
func (s *RgsService) EditMcsmUser(name, password string) (*common.BasicOperationResponse, error) {
path := "/product/rgs/mcsm/panel_user"
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PATCH, path, nil, McsmUser{Name: name, Password: password}, &resp)
return &resp, err
}
// 删除MCSM面板用户
//
// name: 用户名
func (s *RgsService) DeleteMcsmUser(name string) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/mcsm/panel_user/%s", name)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_DELETE, path, nil, nil, &resp)
return &resp, err
}
+38
View File
@@ -0,0 +1,38 @@
package rgs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/apis/rcs"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
type GetRgsMonitorDataRequest struct {
StartDate int `json:"start_date"` // 开始时间(时间戳)
EndDate int `json:"end_date"` // 结束时间(时间戳)
}
type GetRgsMonitorDataResponse struct {
Code int `json:"code"`
Data rcs.RcsMonitorData `json:"data"`
}
// 获取游戏云监控数据
//
// id: 游戏云ID
//
// startDate: 开始时间
//
// endDate: 结束时间
func (s *RgsService) GetRgsMonitorData(id int, req *GetRgsMonitorDataRequest) (*GetRgsMonitorDataResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/monitor", id)
var resp GetRgsMonitorDataResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
+20
View File
@@ -0,0 +1,20 @@
package rgs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/apis/rcs"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 添加游戏云NAT端口映射
//
// id: 游戏云 ID
func (s *RgsService) AddRgsNatPortMapping(id int, req *rcs.AddRcsNatPortMappingRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/nat", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
+111
View File
@@ -0,0 +1,111 @@
package rgs
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/apis/rcs"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
type GetRgsRenewPriceRequest struct {
ProductID int `json:"product_id"`
Duration int `json:"duration"`
WithCouponID int `json:"with_coupon_id"`
}
type GetRgsRenewPriceResponse struct {
Code int `json:"code"`
Data rcs.RcsRenewPrice `json:"data"`
}
type GetRgsUpgradePriceRequest struct {
ProductID int `json:"product_id"`
Duration int `json:"duration"`
WithCouponID int `json:"with_coupon_id"`
Config RgsConfig `json:"config"`
}
// 游戏云升级价格
type GetRgsUpgradePriceResponse struct {
Code int `json:"code"`
Data RgsUpgradePriceData `json:"data"`
}
type RgsUpgradePriceData struct {
Detail RgsUpgradePriceDetail `json:"detail"`
Price int `json:"price"`
}
type RgsUpgradePriceDetail struct {
Price int `json:"price"`
AgentPrice int `json:"agent_price"`
StockPrice int `json:"stock_price"`
DefaultPrice int `json:"default_price"`
CouponValue int `json:"coupon_value"`
SaleReward int `json:"sale_reward"`
AgentReward int `json:"agent_reward"`
AgentID int `json:"agent_id"`
IgnoreAgent bool `json:"ignore_agent"`
PerScene RgsUpgradePerScene `json:"per_scene"`
}
type RgsUpgradePerScene struct {
Upgrade int `json:"upgrade"`
}
// 获取游戏云续费价格
//
// id: RGS ID, duration: 续费时长(月), coupon: 优惠券ID
func (s *RgsService) GetRgsRenewPrice(req *GetRgsRenewPriceRequest) (*GetRgsRenewPriceResponse, error) {
path := "/product/rgs/price"
var resp GetRgsRenewPriceResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
querys["scene"] = "renew"
querys["is_old"] = "true"
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
// 游戏云续费
//
// id: 游戏云ID
func (s *RgsService) RenewRgs(id int, req rcs.RenewRcsRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/renew", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 游戏云自动续费选项
//
// id: 游戏云ID
func (s *RgsService) EnableRgsAutoRenew(id int, req rcs.EnableRcsAutoRenewRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/rgs/%d/renew/option", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 获取游戏云升级价格
//
// id: RGS ID, duration: 续费时长(月), coupon: 优惠券ID
func (s *RgsService) GetRgsUpgradePrice(req *GetRgsUpgradePriceRequest) (*GetRgsUpgradePriceResponse, error) {
path := "/product/rgs/price"
var resp GetRgsUpgradePriceResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
querys["scene"] = "upgrade"
querys["is_old"] = "true"
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
+40
View File
@@ -0,0 +1,40 @@
package rgs
import (
"fmt"
"net/url"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 游戏云连接VNC
//
// id: 游戏云ID
//
// consoleType: 控制台类型,可选值: novnc,xtermjs
func (s *RgsService) GetRgsVnc(id int, consoleType string) (*common.VncConnectionInfo, error) {
path := fmt.Sprintf("/product/rgs/%d/vnc", id)
var resp common.VncConnectionInfo
querys := map[string]string{"console_type": consoleType}
err := s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
// 获取游戏云对应的PVE地址
//
// id: 游戏云ID
func (s *RgsService) GetRgsPveAddress(id int) (string, error) {
v, err := s.GetRgsVnc(id, "novnc")
if err != nil {
return "", err
}
parsedURL, err := url.Parse(v.Data.RequestURL)
if err != nil {
return "", err
}
return parsedURL.Hostname(), nil
}
+213
View File
@@ -0,0 +1,213 @@
package ros
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 创建对象存储桶请求
type CreateRosBucketRequest struct {
BucketName string `json:"bucket_name"` // 存储桶名称
InstanceID int `json:"instance_id"` // 实例ID
}
// 创建对象存储桶响应
type CreateRosBucketResponse struct {
Code int `json:"code"`
Data RosBucket `json:"data"`
}
// 获取对象存储桶列表请求
type GetRosBucketListRequest struct {
Options common.StandQueryParameters `json:"options"`
}
// 获取对象存储桶列表响应
type GetRosBucketListResponse struct {
Code int `json:"code"`
Data RosBucketList `json:"data"`
}
// 对象存储桶列表
type RosBucketList struct {
TotalRecords int `json:"TotalRecords"`
Records []RosBucket `json:"Records"`
}
// 获取对象存储桶详情响应
type GetRosBucketDetailResponse struct {
Code int `json:"code"`
Data RosBucketDetail `json:"data"`
}
// 对象存储桶详情
type RosBucketDetail struct {
Data RosBucket `json:"Data"`
}
// 修改存储桶Proxy设置请求
// 一个请求只能设置一项设置,要设置的设置项需要放在 Setting 中,只需要写需要修改的设置项,其他不填
type ModifyRosBucketProxySettingsRequest struct {
DomainList []string `json:"domain_list,omitempty"` // 域名列表
GzipSettings RosGzipSettings `json:"gzip_settings,omitempty"`
IPRestrictSettings RosIPRestrictSettings `json:"ip_restrict_settings,omitempty"`
RefererRestrictSettings RosRefererRestrictSettings `json:"referer_restrict_settings,omitempty"`
Setting string `json:"setting"` // 必选项,要设置的选项(domain/ssl/waf/gzip/ip_restrict/referer_restrict)
SslSettings RosSslSettings `json:"ssl_settings,omitempty"`
WafSettings RosWafSettings `json:"waf_settings,omitempty"`
}
// Gzip设置
type RosGzipSettings struct {
CompressLevel int `json:"compress_level,omitempty"` // 压缩等级(1-5,默认为2)
FileTypes []string `json:"file_types,omitempty"` // 文件MIME类型,默认["*"]
IsEnable bool `json:"is_enable,omitempty"` // 是否启用GZIP压缩,默认启用
}
// IP访问限制设置
type RosIPRestrictSettings struct {
Blacklist []string `json:"blacklist,omitempty"` // 黑名单IP或CIDR范围列表,和白名单列表只能二选一不能共存
IsEnable bool `json:"is_enable,omitempty"` // 是否启用IP访问限制
Whitelist []string `json:"whitelist,omitempty"` // 白名单IP或CIDR范围列表,和黑名单列表只能二选一不能共存
}
// Referer防盗链设置
type RosRefererRestrictSettings struct {
Blacklist []string `json:"blacklist,omitempty"` // 黑名单域名列表,和白名单列表只能二选一不能共存
BypassMissing bool `json:"bypass_missing,omitempty"` // 是否允许Referer请求头不存在或者格式有误
IsEnable bool `json:"is_enable,omitempty"` // 是否启用Referer防盗链
Whitelist []string `json:"whitelist,omitempty"` // 白名单域名列表,和黑名单列表只能二选一不能共存
}
// SSL设置,SSL证书会自动匹配
type RosSslSettings struct {
IsEnable bool `json:"is_enable,omitempty"` // 是否启用SSL
IsForce bool `json:"is_force,omitempty"` // 是否强制使用SSL
}
// WAF防火墙设置
type RosWafSettings struct {
BlockTime int `json:"block_time,omitempty"` // 未通过JS验证时的封禁时间,秒
GlobalJsCheck bool `json:"global_js_check,omitempty"` // 是否启用全局JS检查,只有超过阈值才会生效
GlobalQPS int `json:"global_qps,omitempty"` // 全局访问速率限制,超过会被拒绝
IsEnable bool `json:"is_enable,omitempty"` // 是否启用WAF防火墙
PerIPJsCheck bool `json:"per_ip_js_check,omitempty"` // 是否启用单IP JS检查,只有超过阈值才会生效
PerIPQPS int `json:"per_ip_qps,omitempty"` // 单个IP访问速率限制,超过会被拒绝
}
// 获取对象存储桶列表
//
// ⚠️注意这个接口是拿不到AK和SK的,响应里面的AK和SK都是空的
func (s *RosService) GetRosBucketList(req *GetRosBucketListRequest) (*GetRosBucketListResponse, error) {
path := "/product/ros/bucket/"
var resp GetRosBucketListResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
// 创建对象存储桶
//
// req: 创建参数(bucketName 存储桶名 >= 3 字符 <= 63 字符)
func (s *RosService) CreateRosBucket(req CreateRosBucketRequest) (*CreateRosBucketResponse, error) {
path := "/product/ros/bucket"
var resp CreateRosBucketResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 获取对象存储桶详情
//
// bucketID: 存储桶ID
func (s *RosService) GetRosBucketDetail(bucketID int) (*GetRosBucketDetailResponse, error) {
path := fmt.Sprintf("/product/ros/bucket/%d", bucketID)
var resp GetRosBucketDetailResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
// 删除对象存储桶
//
// bucketID: 存储桶ID
func (s *RosService) DeleteRosBucket(bucketID int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/ros/bucket/%d", bucketID)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_DELETE, path, nil, nil, &resp)
return &resp, err
}
// 获取对象存储桶监控数据
//
// bucketID: 存储桶ID
//
// req: 开始时间/结束时间(timestamp)
func (s *RosService) GetRosBucketMonitorData(bucketID int, req *GetRosMonitorDataRequest) (*GetRosMonitorDataResponse, error) {
path := fmt.Sprintf("/product/ros/bucket/%d/monitor", bucketID)
var resp GetRosMonitorDataResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
// 修改存储桶Proxy设置
//
// bucketID: 存储桶ID
func (s *RosService) ModifyRosBucketProxySettings(bucketID int, req *ModifyRosBucketProxySettingsRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/ros/bucket/%d/proxy", bucketID)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PATCH, path, nil, req, &resp)
return &resp, err
}
// 对象存储桶重新生成密钥
//
// bucketID: 存储桶ID
func (s *RosService) ReGenerateRosBucketKeys(bucketID int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/ros/bucket/%d/regenerate-keys", bucketID)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
// 开关对象存储桶匿名访问
//
// bucketID: 存储桶ID
func (s *RosService) SetRosBucketPublicAccess(bucketID int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/ros/bucket/%d/toggle-public-access", bucketID)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
// 按实例获取对象存储桶列表响应
type GetRosBucketListByInstanceResponse struct {
Code int `json:"code"`
Data RosBucketList `json:"data"`
}
// 按实例获取对象存储桶列表
//
// instanceID: 实例ID
func (s *RosService) GetRosBucketListByInstance(instanceID int) (*GetRosBucketListByInstanceResponse, error) {
path := fmt.Sprintf("/product/ros/bucket/%d", instanceID)
var resp GetRosBucketListByInstanceResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
+11
View File
@@ -0,0 +1,11 @@
package ros
import "github.com/XingfenD/rainyun_api_go_sdk/apis"
type RosService struct {
client *apis.RyClient
}
func NewRosService(c *apis.RyClient) *RosService {
return &RosService{client: c}
}
+224
View File
@@ -0,0 +1,224 @@
package ros
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 创建对象存储实例请求
type CreateRosInstanceRequest struct {
Duration int `json:"duration"` // 购买时长(月)
PlanID int `json:"plan_id"` // 套餐ID
WithCouponID int `json:"with_coupon_id"` // 优惠券ID
}
// 创建对象存储实例响应
type CreateRosInstanceResponse struct {
Code int `json:"code"`
Data RosInstance `json:"data"`
}
// 获取对象存储实例列表请求
type GetRosInstanceListRequest struct {
Options common.StandQueryParameters `json:"options"`
}
// 获取对象存储实例列表响应
type GetRosInstanceListResponse struct {
Code int `json:"code"`
Data RosInstanceList `json:"data"`
}
// 对象存储实例列表
type RosInstanceList struct {
TotalRecords int `json:"TotalRecords"`
Records []RosInstance `json:"Records"`
}
// 获取对象存储实例详情响应
type GetRosInstanceDetailResponse struct {
Code int `json:"code"`
Data RosInstanceDetail `json:"data"`
}
// 对象存储实例详情
type RosInstanceDetail struct {
Data RosInstance `json:"Data"`
RenewPointPrice RosRenewPointPrice `json:"RenewPointPrice"` // 积分续费
}
// 对象存储积分续费价格
type RosRenewPointPrice struct {
Num7 int `json:"7"` // 积分续费七天
Num31 int `json:"31"` // 积分续费一个月
}
// ROS实例续费请求
type RenewRosInstanceRequest struct {
Duration int `json:"duration"` // 续费时长(月)
WithCouponID int `json:"with_coupon_id"` // 优惠券ID
}
// ROS实例自动续费选项
type RosInstanceAutoRenewOption struct {
AutoRenewOption bool `json:"auto_renew_option"`
}
// ROS实例缩放请求
type ScaleRosInstanceRequest struct {
DestPlan int `json:"dest_plan"` // 目标套餐ID
WithCouponID int `json:"with_coupon_id"` // 优惠券ID
}
// 设置对象存储实例标签请求
type SetRosInstanceTagRequest struct {
TagName string `json:"tag_name"`
}
// 开关对象存储实例的弹性计费选项请求
type ToggleRosInstanceExtraAccountingRequest struct {
IsEnable bool `json:"is_enable"`
}
// 创建对象存储实例
//
// req: 创建参数
func (s *RosService) CreateRosInstance(req CreateRosInstanceRequest) (*CreateRosInstanceResponse, error) {
path := "/product/ros/instance"
var resp CreateRosInstanceResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 获取对象存储实例详情
//
// instanceID: 实例ID
func (s *RosService) GetRosInstanceDetail(instanceID int) (*GetRosInstanceDetailResponse, error) {
path := fmt.Sprintf("/product/ros/instance/%d", instanceID)
var resp GetRosInstanceDetailResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
// 获取对象存储实例列表
//
// ⚠️注意这个接口是拿不到AK和SK的,响应里面的AK和SK都是空的
func (s *RosService) GetRosInstanceList(req *GetRosInstanceListRequest) (*GetRosInstanceListResponse, error) {
path := "/product/ros/instance/"
var resp GetRosInstanceListResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
// 获取对象存储实例监控数据
//
// instanceID: 实例ID
//
// req: 开始时间/结束时间(timestamp)
func (s *RosService) GetRosInstanceMonitorData(instanceID int, req *GetRosMonitorDataRequest) (*GetRosMonitorDataResponse, error) {
path := fmt.Sprintf("/product/ros/instance/%d/monitor", instanceID)
var resp GetRosMonitorDataResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
// 对象存储实例续费
//
// instanceID: 实例ID
//
// req: 续费参数
func (s *RosService) RenewRosInstance(instanceID int, req RenewRosInstanceRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/ros/instance/%d/renew", instanceID)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 对象存储实例自动续费选项
//
// instanceID: 实例ID
//
// isOpen: 是否开启自动续费
func (s *RosService) SetRosInstanceAutoRenewOption(instanceID int, isOpen bool) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/ros/instance/%d/renew/option", instanceID)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, RosInstanceAutoRenewOption{AutoRenewOption: isOpen}, &resp)
return &resp, err
}
// ROS实例缩放
//
// instanceID: 实例ID
//
// req: 缩放参数
func (s *RosService) ScaleRosInstance(instanceID int, req ScaleRosInstanceRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/ros/instance/%d/scale", instanceID)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 设置对象存储实例标签
//
// instanceID: 实例ID
//
// tag: 标签
func (s *RosService) SetRosInstanceTags(instanceID int, tag string) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/ros/instance/%d/tag", instanceID)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PATCH, path, nil, SetRosInstanceTagRequest{TagName: tag}, &resp)
return &resp, err
}
// 开关对象存储实例的弹性计费选项
//
// instanceID: 实例ID
//
// isEnable: 是否开启
func (s *RosService) ToggleRosInstanceExtraAccounting(instanceID int, isEnable bool) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/ros/instance/%d/toggle-extra-accounting", instanceID)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PATCH, path, nil, ToggleRosInstanceExtraAccountingRequest{IsEnable: isEnable}, &resp)
return &resp, err
}
// 对象存储实例重新生成密钥
//
// instanceID: 实例ID
func (s *RosService) ReGenerateRosInstanceKeys(instanceID int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/ros/instance/%d/regenerate-keys", instanceID)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
// 开关对象存储实例匿名访问
//
// instanceID: 实例ID
func (s *RosService) SetRosInstancePublicAccess(instanceID int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/ros/instance/%d/toggle-public-access", instanceID)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, nil, &resp)
return &resp, err
}
+141
View File
@@ -0,0 +1,141 @@
package ros
// RosNode 节点信息
type RosNode struct {
UUID string `json:"UUID"`
AuthKey string `json:"AuthKey"`
Region string `json:"Region"`
IPRegion string `json:"IpRegion"`
Machine string `json:"Machine"`
Product string `json:"Product"`
Subtype string `json:"Subtype"`
ChineseName string `json:"ChineseName"`
PhysicalNode string `json:"PhysicalNode"`
Config string `json:"Config"`
Stock any `json:"Stock"`
StatusData string `json:"StatusData"`
ShowMonitorData string `json:"ShowMonitorData"`
UpdateTime string `json:"UpdateTime"`
GitRepositoryName string `json:"GitRepositoryName"`
CertifyRequired bool `json:"CertifyRequired"`
IsDisableBackup bool `json:"IsDisableBackup"`
IsHidden bool `json:"IsHidden"`
NodeName string `json:"NodeName"`
}
// RosPlan 套餐信息
type RosPlan struct {
ID int `json:"id"`
Region string `json:"region"`
Subtype string `json:"subtype"`
PlanName string `json:"plan_name"`
Machine string `json:"machine"`
ChargeType string `json:"charge_type"`
Chinese string `json:"chinese"`
IsFree bool `json:"is_free"`
PointRenewPrice any `json:"point_renew_price"`
IsSelling bool `json:"is_selling"`
Price int `json:"price"`
StorageSize int `json:"storage_size"`
Bandwidth int `json:"bandwidth"`
ExtraTransferPrice float64 `json:"extra_transfer_price"`
ExtraStoragePrice float64 `json:"extra_storage_price"`
}
// RosUsageData 实例使用数据
type RosUsageData struct {
MetricsUsageTotalBytes int `json:"metrics_usage_total_bytes"` // 存储使用量
MetricsReceivedBytes int `json:"metrics_received_bytes"` // 接收字节数
MetricsSentBytes int `json:"metrics_sent_bytes"` // 发送字节数
MetricsRequests int `json:"metrics_requests"` // 请求数
SpeedReceivedBytes int `json:"speed_received_bytes"` // 接收字节速度
SpeedSentBytes int `json:"speed_sent_bytes"` // 发送字节速度
SpeedRequests int `json:"speed_requests"` // 请求速度
UpdateTime int `json:"UpdateTime"` // 更新时间
}
// RosInstance 对象存储实例信息
type RosInstance struct {
ID int `json:"ID"`
UID int `json:"UID"`
PlanID int `json:"PlanID"`
CreateDate int `json:"CreateDate"` // 创建时间
NodeUUID string `json:"NodeUUID"` // 节点UUID
Node RosNode `json:"Node"` // 节点信息
Status string `json:"Status"`
StopReason string `json:"StopReason"`
RewardPointsToBeCollect int `json:"RewardPointsToBeCollect"` // 待领取积分奖励
Tag string `json:"Tag"`
Plan RosPlan `json:"Plan"`
AccessKey string `json:"access_key"` // ⚠️列表接口拿不到AK,响应里面的AK是空的
SecretKey string `json:"secret_key"` // ⚠️列表接口拿不到SK,响应里面的SK是空的
IsPublicAccess bool `json:"is_public_access"` // 是否允许公共访问
IsEnableExtraAccounting bool `json:"is_enable_extra_accounting"` // 是否启用额外计费
LastResetDate int `json:"last_reset_date"` // 最后重置时间
NextResetDate int `json:"next_reset_date"` // 下次重置时间
ExpDate int `json:"ExpDate"` // 到期时间
ExpireNotice int `json:"ExpireNotice"`
AutoRenew bool `json:"AutoRenew"` // 是否自动续费
UnsubscribeAble bool `json:"UnsubscribeAble"`
Try bool `json:"Try"` // 是否试用
PublicAPIURL string `json:"public_api_url"`
Buckets any `json:"buckets"`
ExtraPayTime int `json:"extra_pay_time"`
UsageData RosUsageData `json:"UsageData"`
Restrictions string `json:"restrictions"`
PublicAccessRestricted bool `json:"public_access_restricted"`
}
// RosBucket 对象存储桶信息
type RosBucket struct {
ID int `json:"id"` // 存储桶ID
Name string `json:"name"` // 存储桶名称
UID int `json:"uid"` // 用户ID
CreateDate int `json:"create_date"`
AccessKey string `json:"access_key"` // ⚠️列表接口拿不到AK,响应里面的AK是空的
SecretKey string `json:"secret_key"` // ⚠️列表接口拿不到SK,响应里面的SK是空的
IsPublicAccess bool `json:"is_public_access"` // 是否公开
InstanceID int `json:"instance_id"` // 实例ID
Instance RosInstance `json:"Instance"`
StopReason string `json:"stop_reason"`
DomainList any `json:"DomainList"`
SslIsEnable bool `json:"ssl_is_enable"`
SSLCertList any `json:"SSLCertList"`
SslAutoRedirect bool `json:"ssl_auto_redirect"`
WafIsEnable bool `json:"waf_is_enable"`
WafGlobalQPS int `json:"waf_global_qps"`
WafPerIPQPS int `json:"waf_per_ip_qps"`
WafBlockTime int `json:"waf_block_time"`
WafGlobalJsCheck bool `json:"waf_global_js_check"`
WafPerIPJsCheck bool `json:"waf_per_ip_js_check"`
RefererRestrictIsEnable bool `json:"referer_restrict_is_enable"`
RefererRestrictWhitelist any `json:"RefererRestrictWhitelist"`
RefererRestrictBlacklist any `json:"RefererRestrictBlacklist"`
RefererRestrictBypassMissing bool `json:"referer_restrict_bypass_missing"`
IPRestrictIsEnable bool `json:"ip_restrict_is_enable"`
IPRestrictWhitelist any `json:"IPRestrictWhitelist"`
IPRestrictBlacklist any `json:"IPRestrictBlacklist"`
GzipIsEnable bool `json:"gzip_is_enable"`
GzipCompressLevel int `json:"gzip_compress_level"`
UsageData RosUsageData `json:"UsageData"`
ReadyDelete bool `json:"ready_delete"`
}
// 获取监控数据请求(桶和实例通用)
type GetRosMonitorDataRequest struct {
StartDate int `json:"start_date"` // 开始时间(timestamp)
EndDate int `json:"end_date"` // 结束时间(timestamp)
}
// 获取监控数据响应(桶和实例通用)
type GetRosMonitorDataResponse struct {
Code int `json:"code"`
Data RosMonitorData `json:"data"`
}
// RosMonitorData 对象存储监控数据(桶和实例通用)
type RosMonitorData struct {
Columns []string `json:"Columns"`
Values [][]any `json:"Values"`
}
+128
View File
@@ -0,0 +1,128 @@
package ssl
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// SSL证书
type SslCertificate struct {
Cert string `json:"cert"` // 证书
Key string `json:"key"` // 私钥
}
// SSL证书列表记录
type SslCertificateRecord struct {
ID int `json:"ID"`
UID int `json:"UID"`
Domain string `json:"Domain"` // 域名(逗号分割)
Issuer string `json:"Issuer"` // 品牌
StartDate int `json:"StartDate"` // 开始时间
ExpDate int `json:"ExpDate"` // 结束时间
UploadTime int `json:"UploadTime"` // 上传时间
NginxErr string `json:"NginxErr"` // ?
BaishanCertID int `json:"BaishanCertID"` // 白山云证书ID
BindDomains any `json:"BindDomains"` // 绑定的域名
}
// SSL证书列表数据
type SslCertificateListData struct {
TotalRecords int `json:"TotalRecords"`
Records []SslCertificateRecord `json:"Records"`
}
type GetSslCertificateListResponse struct {
Code int `json:"code"`
Data SslCertificateListData `json:"data"`
}
type GetSslCertificateListRequest struct {
Options common.StandQueryParameters `json:"options"`
}
// 获取SSL证书列表
func (s *SslService) GetSSLCertificateList(req *GetSslCertificateListRequest) (*GetSslCertificateListResponse, error) {
path := "/product/sslcenter/"
var resp GetSslCertificateListResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
// 上传SSL证书
//
// cert: 证书
//
// key: 私钥
func (s *SslService) UploadSSLCertificate(cert string, key string) (*common.BasicOperationResponse, error) {
path := "/product/sslcenter/"
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, SslCertificate{
Cert: cert,
Key: key,
}, &resp)
return &resp, err
}
// SSL证书详情数据
type SslDetailData struct {
Cert string `json:"Cert"` // 证书
Key string `json:"Key"` // 私钥
DomainName string `json:"DomainName"` // 域名(逗号分割)
Issuer string `json:"Issuer"` // 品牌
StartDate int `json:"StartDate"` // 开始时间
ExpDate int `json:"ExpDate"` // 结束时间
RemainDays int `json:"RemainDays"` // 剩余天数
}
type GetSslDetailResponse struct {
Code int `json:"code"`
Data SslDetailData `json:"data"`
}
// 获取SSL证书详情
//
// id: SSL证书ID
func (s *SslService) GetSslDetail(id int) (*GetSslDetailResponse, error) {
path := fmt.Sprintf("/product/sslcenter/%d", id)
var resp GetSslDetailResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
// 替换SSL证书
//
// id: SSL证书ID
//
// cert: 证书
//
// key: 私钥
func (s *SslService) ReplaceSsl(id int, cert, key string) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/sslcenter/%d", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PUT, path, nil, SslCertificate{
Cert: cert,
Key: key,
}, &resp)
return &resp, err
}
// 删除SSL证书
//
// id: SSL证书ID
func (s *SslService) DeleteSsl(id int) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/product/sslcenter/%d", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_DELETE, path, nil, nil, &resp)
return &resp, err
}
+11
View File
@@ -0,0 +1,11 @@
package ssl
import "github.com/XingfenD/rainyun_api_go_sdk/apis"
type SslService struct {
client *apis.RyClient
}
func NewSslService(c *apis.RyClient) *SslService {
return &SslService{client: c}
}
+11
View File
@@ -0,0 +1,11 @@
package user
import "github.com/XingfenD/rainyun_api_go_sdk/apis"
type UserService struct {
client *apis.RyClient
}
func NewUserService(c *apis.RyClient) *UserService {
return &UserService{client: c}
}
+40
View File
@@ -0,0 +1,40 @@
package user
import (
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// Request2FARequest 请求二次验证
type Request2FARequest struct {
Type string `json:"type"`
}
// 请求二次验证
//
// verificationMethod: 验证方式(sms/totp/email)
func (s *UserService) Request2FA(verificationMethod string) (*common.BasicOperationResponse, error) {
path := "/user/mfa/request"
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, Request2FARequest{Type: verificationMethod}, &resp)
return &resp, err
}
// Verify2FAResultRequest 验证二次验证结果
type Verify2FAResultRequest struct {
AuthCode int `json:"auth_code"`
}
// 验证二次验证结果
//
// authCode: 验证码
func (s *UserService) Verify2FAResult(authCode int) (*common.BasicOperationResponse, error) {
path := "/user/mfa/verify"
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, Verify2FAResultRequest{AuthCode: authCode}, &resp)
return &resp, err
}
+186
View File
@@ -0,0 +1,186 @@
package user
import (
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
type GetUserRewardProductsResponse struct {
Code int `json:"code"`
Data UserRewardProductsData `json:"data"`
}
// UserRewardProductsData 用户可用积分兑换的产品
type UserRewardProductsData struct {
Rcs []any `json:"rcs"`
Rvh []any `json:"rvh"`
Rgs []any `json:"rgs"`
Ros []any `json:"ros"`
Rbm []any `json:"rbm"`
}
// 获取可兑换积分产品列表.
func (s *UserService) GetUserRewardProducts() (*GetUserRewardProductsResponse, error) {
path := "/user/reward/products"
var resp GetUserRewardProductsResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
// 发布优惠券给下级用户
type PublishCouponsToLowerLevelUsersRequest struct {
BaseLimit int `json:"base_limit"` // 满减条件(满多少才能用)
Color string `json:"color"` // 颜色: waring: 黄,danger: 红,success: 绿...
Count int `json:"count"` // 发放数量
ExpDate int `json:"exp_date"` // 过期时间(timestamp)
FriendlyName string `json:"friendly_name"` // 优惠券标题
Type string `json:"type"` // 类型: discount:折扣, normal: 直减
UID int `json:"uid"` // 要发放到用户ID(如:114514),为空时则返回兑换码
UsableDuration string `json:"usable_duration"` // unknown
UsableProduct string `json:"usable_product"` // 可用产品(默认全部),","分隔: renew,create,upgrade
UsableScenes string `json:"usable_scenes"` // 适用操作(默认全部),","分隔: rvh,rcs,rgs,ros,rbm
Value int `json:"value"` // 直减(元)/折扣(折), 折扣时:1~9:一~九折;11~99:一一~九九折
}
// 发布优惠券给下级用户
func (s *UserService) PublishCouponsToLowerLevelUsers(req *PublishCouponsToLowerLevelUsersRequest) (*common.BasicOperationResponse, error) {
path := "/user/vip/coupon"
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 发送优惠券到积分商城
type PostCouponsToPointsMallRequest struct {
AvailableDays int `json:"available_days"` // 可用天数
BaseLimit int `json:"base_limit"` // 满减条件(满多少才能用)
BuyLimit int `json:"buy_limit"` // 领取次数限制
Color string `json:"color"` // 颜色: waring: 黄, danger: 红, success: 绿, info: 蓝
Count int `json:"count"` // 发放数量
EndDate int `json:"end_date"` // 截止日期
FirstSend bool `json:"first_send"` // 绑定微信后立即自动领取(设置后不可手动领取并且不会显示)
FriendlyName string `json:"friendly_name"` // 优惠券名称
Name string `json:"name"` // 标识名称
Order int `json:"order"` // 排序,越大越靠前
Points int `json:"points"` // 领取积分
Type string `json:"type"` // 类型: discount:折扣, normal: 直减
UsableDuration string `json:"usable_duration"` // unknown
UsableProduct string `json:"usable_product"` // 可用产品(默认全部),","分隔: renew,create,upgrade
UsableScenes string `json:"usable_scenes"` // 适用操作(默认全部),","分隔: rvh,rcs,rgs,ros,rbm
Value int `json:"value"` // 直减(元)/折扣(折), 折扣时:1~9:一~九折;11~99:一一~九九折
}
// 发布优惠券到积分商城(供下级领取)
func (s *UserService) PostCouponsToPointsMall(req *PostCouponsToPointsMallRequest) (*common.BasicOperationResponse, error) {
path := "/user/vip/coupon"
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
type GetPointsMallItemsResponse struct {
Code int `json:"code"`
Data []PointsMallItem `json:"data"`
}
// PointsMallItem 积分商城物品
type PointsMallItem struct {
ID int `json:"id"`
Name string `json:"name"`
Points int `json:"points"`
Type string `json:"type"`
AvailableStock int `json:"available_stock"`
FriendlyName string `json:"friendly_name"`
ItemData PointsMallItemData `json:"item_data"`
BuyLimit int `json:"buy_limit"`
SenderID int `json:"sender_id"`
FirstSend bool `json:"first_send"`
ByInvite bool `json:"by_invite"`
Color string `json:"color"`
Order int `json:"order"`
PublicTime int `json:"public_time"`
EndDate int `json:"end_date"`
AutoRefresh int `json:"auto_refresh"`
RefreshLimit int `json:"refresh_limit"`
MoneyRequired int `json:"money_required"`
}
// PointsMallItemData 积分商城物品数据
type PointsMallItemData struct {
Color string `json:"color,omitempty"`
FriendlyName string `json:"friendly_name,omitempty"`
UsableScenes string `json:"usable_scenes,omitempty"`
AvailableDays int `json:"available_days,omitempty"`
UsableProduct string `json:"usable_product,omitempty"`
BaseLimit int `json:"base_limit,omitempty"`
PublicPoint int `json:"public_point,omitempty"`
Type string `json:"type,omitempty"`
UsableDuration string `json:"usable_duration,omitempty"`
UsablePlanID int `json:"usable_plan_id,omitempty"`
Value any `json:"value,omitempty"`
ProductType string `json:"product_type,omitempty"`
ProductSubtype string `json:"product_subtype,omitempty"`
DurationSeconds int `json:"duration_seconds,omitempty"`
ProductConfig PointsMallProductConfig `json:"product_config,omitempty"`
Desc string `json:"desc,omitempty"`
ImgURL string `json:"img_url,omitempty"`
DescURL string `json:"desc_url,omitempty"`
}
// PointsMallProductConfig 积分商城物品的产品配置
type PointsMallProductConfig struct {
OsID int `json:"os_id"`
PlanID int `json:"plan_id"`
Subtype string `json:"subtype"`
Duration int `json:"duration"`
PayMode string `json:"pay_mode"`
PanelUser string `json:"panel_user"`
EggTypeID int `json:"egg_type_id"`
WithCoupon int `json:"with_coupon"`
CPULimitMode bool `json:"cpu_limit_mode"`
Config PointsMallItemConfig `json:"config"`
}
// PointsMallItemConfig 积分商城物品配置
type PointsMallItemConfig struct {
CPU int `json:"cpu"`
Backup int `json:"backup"`
Memory int `json:"memory"`
NetIn int `json:"net_in"`
NetOut int `json:"net_out"`
Database int `json:"database"`
BaseDisk int `json:"base_disk"`
DataDisk int `json:"data_disk"`
Allocation int `json:"allocation"`
}
// 获取积分商城商品列表
func (s *UserService) GetPointsMallItems() (*GetPointsMallItemsResponse, error) {
path := "/user/reward/items"
var resp GetPointsMallItemsResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
// 兑换积分物品
type RedeemPointsForItemRequest struct {
ItemID int `json:"item_id"`
}
// 兑换积分物品
func (s *UserService) RedeemPointsForItem(id int) (*common.BasicOperationResponse, error) {
path := "/user/reward/items"
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, RedeemPointsForItemRequest{ItemID: id}, &resp)
return &resp, err
}
+123
View File
@@ -0,0 +1,123 @@
package user
import (
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
type GetUserInfoResponse struct {
Code int `json:"code"`
Data UserInfo `json:"data"`
}
// UserInfo 用户信息
type UserInfo struct {
ID int `json:"ID"`
Name string `json:"Name"`
Email string `json:"Email"`
Phone string `json:"Phone"`
Money float64 `json:"Money"`
RegisterTime int `json:"RegisterTime"`
QQOpenID string `json:"QQOpenID"`
QQ any `json:"QQ"`
WechatOpenID string `json:"WechatOpenID"`
CardCode any `json:"CardCode"`
IconURL string `json:"IconUrl"`
Points int `json:"Points"`
MoneyFromPoint int `json:"MoneyFromPoint"`
Inviter int `json:"Inviter"`
APIKey string `json:"APIKey"`
LastIP string `json:"LastIP"`
BanReason string `json:"BanReason"`
UnsubscribeCount int `json:"UnsubscribeCount"`
AlipayAccount string `json:"AlipayAccount"`
AlipayName string `json:"AlipayName"`
LastLogin string `json:"LastLogin"`
LastLoginArea string `json:"LastLoginArea"`
LoginCount int `json:"LoginCount"`
DLWallet int `json:"DLWallet"`
DLLevel int `json:"DLLevel"`
AdminGroup string `json:"AdminGroup"`
TOTPSecret string `json:"TOTPSecret"`
IsLoginEnableTFA bool `json:"IsLoginEnableTFA"`
IsAllowPointUse int `json:"IsAllowPointUse"`
ShareCode string `json:"ShareCode"`
VipLevel int `json:"VipLevel"`
IsAgent bool `json:"IsAgent"`
Valid bool `json:"Valid"`
Source string `json:"Source"`
ConsumeMonthly int `json:"ConsumeMonthly"`
ConsumeAll int `json:"ConsumeAll"`
ConsumeQuarter int `json:"ConsumeQuarter"`
ResellDaily int `json:"ResellDaily"`
ResellMonthly int `json:"ResellMonthly"`
ResellBeforeMonth float64 `json:"ResellBeforeMonth"`
ResellQuarter float64 `json:"ResellQuarter"`
ResellAll float64 `json:"ResellAll"`
StockDaily int `json:"StockDaily"`
StockMonthly int `json:"StockMonthly"`
StockQuarter float64 `json:"StockQuarter"`
StockAll float64 `json:"StockAll"`
SecondStockQuarter int `json:"SecondStockQuarter"`
SecondStockAll int `json:"SecondStockAll"`
SubUserMonthly int `json:"SubUserMonthly"`
SubUserAll int `json:"SubUserAll"`
ResellPointsMonthly int `json:"ResellPointsMonthly"`
ResellPointsAll int `json:"ResellPointsAll"`
Vip UserVipInfo `json:"VIP"`
Certify int `json:"Certify"`
LockPoints int `json:"LockPoints"`
CertifyStatus string `json:"CertifyStatus"`
CertifyType string `json:"CertifyType"`
CertifyAuditNote string `json:"CertifyAuditNote"`
}
// UserVipInfo 用户 VIP 等级信息
type UserVipInfo struct {
Title string `json:"Title"`
SaleRequire int `json:"SaleRequire"`
ResellRequire int `json:"ResellRequire"`
CertifyRequired bool `json:"CertifyRequired"`
SaleProfit float64 `json:"SaleProfit"`
ResellProfit float64 `json:"ResellProfit"`
SecondResellProfit float64 `json:"SecondResellProfit"`
CanSendCoupons bool `json:"CanSendCoupons"`
CanCustomCode bool `json:"CanCustomCode"`
CanSendMsg bool `json:"CanSendMsg"`
CanTryUsual bool `json:"CanTryUsual"`
FreeDomainCount int `json:"FreeDomainCount"`
FreeSSLCount int `json:"FreeSSLCount"`
CanBeAgent bool `json:"CanBeAgent"`
AgentTitle string `json:"AgentTitle"`
StockRequire int `json:"StockRequire"`
SecondStockRequire int `json:"SecondStockRequire"`
StockDiscount float64 `json:"StockDiscount"`
SecondStockProfit float64 `json:"SecondStockProfit"`
}
// 获取用户信息.
func (s *UserService) GetUserInfo() (*GetUserInfoResponse, error) {
path := "/user/"
var resp GetUserInfoResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
// RefreshApikeyRequest 刷新 API 密钥请求
type RefreshApikeyRequest struct {
Option string `json:"option"`
}
// 刷新 api 密钥.
//
// ⚠️不要轻易使用此方法
func (s *UserService) RefreshApikey() (*common.BasicOperationResponse, error) {
path := "/user/"
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PATCH, path, nil, RefreshApikeyRequest{Option: "apikey"}, &resp)
return &resp, err
}
+11
View File
@@ -0,0 +1,11 @@
package workorder
import "github.com/XingfenD/rainyun_api_go_sdk/apis"
type WorkorderService struct {
client *apis.RyClient
}
func NewWorkorderService(c *apis.RyClient) *WorkorderService {
return &WorkorderService{client: c}
}
+152
View File
@@ -0,0 +1,152 @@
package workorder
import "github.com/XingfenD/rainyun_api_go_sdk/apis/common"
// 获取工单列表请求
type GetWorkOrderListRequest struct {
Options common.StandQueryParameters `json:"options"`
}
// 获取工单列表响应
type GetWorkOrderListResponse struct {
Code int `json:"code"`
Data WorkorderListData `json:"data"`
}
// 工单列表数据
type WorkorderListData struct {
TotalRecords int `json:"TotalRecords"`
Records []WorkorderRecord `json:"Records"`
}
// 工单
type WorkorderRecord struct {
ID int `json:"ID"` // 工单ID
UID int `json:"UID"` // 用户ID
ExtUserInfo string `json:"ExtUserInfo"`
UserName string `json:"UserName"` // 用户名
UserEmail string `json:"UserEmail"`
UserVip string `json:"UserVip"` // 用户vip等级
UserIcon string `json:"UserIcon"` // 用户头像
Title string `json:"Title"` // 工单标题
Type string `json:"Type"` // 工单类型
RelatedProductType string `json:"RelatedProductType"` // 关联产品类型
RelatedProductID int `json:"RelatedProductID"` // 关联产品id
IsUrgent int `json:"IsUrgent"` // 是否为紧急工单
Status string `json:"Status"` // 状态(finished/answered/waiting)
Time int `json:"Time"` // 工单创建时间
LastTime int `json:"LastTime"`
WaitBeginTime int `json:"WaitBeginTime"`
AssistID int `json:"AssistID"` // 客服id
AuthStatus string `json:"AuthStatus"`
AuthTime int `json:"AuthTime"`
AuthID int `json:"AuthID"`
}
// 工单回复
type WorkorderDiscuss struct {
ID int `json:"ID"`
IsAssist bool `json:"IsAssist"`
UID int `json:"UID"`
UserName string `json:"UserName"`
UserEmail string `json:"UserEmail"`
UserVip string `json:"UserVip"`
UserIcon string `json:"UserIcon"`
Content string `json:"Content"`
Time int `json:"Time"`
WaitTime int `json:"WaitTime"`
LastEditedTime int `json:"LastEditedTime"`
IsScored bool `json:"IsScored"`
}
// 工单详情数据
type WorkorderDetailData struct {
WorkorderRecord
Content string `json:"Content"`
Discuss []WorkorderDiscuss `json:"Discuss"`
}
// 获取工单详情响应
type GetWorkOrderDetailResponse struct {
Code int `json:"code"`
Data WorkorderDetailData `json:"data"`
}
// 创建工单
type CreateWorkerorderRequest struct {
Content string `json:"content"`
IsAuthed bool `json:"is_authed"` // 是否需要授权(可选)
IsUrgent int `json:"is_urgent"` // 是否为紧急工单
RelatedProductID int `json:"related_product_id"` // 关联产品类型(可选)
RelatedProductType string `json:"related_product_type"` // 关联产品id(可选)
Title string `json:"title"`
Type string `json:"type"` // 工单类型
}
// 创建工单数据
type CreateWorkorderData struct {
WorkorderRecord
Content string `json:"Content"`
}
// 创建工单响应
type CreateWorkerorderResponse struct {
Code int `json:"code"`
Data CreateWorkorderData `json:"data"`
}
// 产品授权请求
type ProductAuthRequest struct {
ProductID int `json:"product_id"` // 产品ID
ProductType string `json:"product_type"` // 产品类型(rvh/rcs/rgs/rbm/ros)
}
// 回复工单请求
type ReplyWorkerorderRequest struct {
Content string `json:"content"` // 回复内容
}
// 工单打分
type ScoreWorkerorderRequest struct {
Score int `json:"score"` // 分数(1-5)
Reason string `json:"reason"` // (可选)
IsSolved bool `json:"is_solved"` // 是否解决(可选)
DiscussID int `json:"discuss_id"` // 回复ID(可选)
Aid int `json:"aid"` // 客服id(可选)
}
// 工单打分详情数据
type ScoreWorkorderData struct {
UID int `json:"uid"`
Aid int `json:"aid"`
OrderID int `json:"order_id"`
DiscussID int `json:"discuss_id"`
Score int `json:"score"`
Reason string `json:"reason"`
IsSolved bool `json:"is_solved"`
DiscussTime int `json:"DiscussTime"`
ScoreTime int `json:"score_time"`
}
// 获取工单打分响应
type GetScoreWorkorderResponse struct {
Code int `json:"code"`
Data ScoreWorkorderData `json:"data"`
}
// 工单状态数据
type WorkorderStatusData struct {
LastTime int `json:"LastTime"`
Status string `json:"Status"`
}
// 获取工单状态响应
type GetWorkorderStatusResponse struct {
Code int `json:"code"`
Data WorkorderStatusData `json:"data"`
}
// 设置工单状态请求
type SetWorkorderStatusRequest struct {
Status string `json:"status"`
}
+43
View File
@@ -0,0 +1,43 @@
package workorder
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 工单打分
//
// id: 工单ID
func (s *WorkorderService) ScoreWorkorder(id int, req *ScoreWorkerorderRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/workorder/%d/score", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 编辑工单打分
//
// id: 工单ID
func (s *WorkorderService) EditScoreWorkorder(id int, req *ScoreWorkerorderRequest) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/workorder/%d/score", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PATCH, path, nil, req, &resp)
return &resp, err
}
// 获取工单打分
//
// id: 工单ID
//
// discussID: 客服回复ID
func (s *WorkorderService) GetScoreWorkorder(id int, discussID int) (*GetScoreWorkorderResponse, error) {
path := fmt.Sprintf("/workorder/%d/score/%d", id, discussID)
var resp GetScoreWorkorderResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
+110
View File
@@ -0,0 +1,110 @@
package workorder
import (
"fmt"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/constant"
)
// 获取工单列表
//
// req.Options 为分页查询参数, 可用 common.StandQueryParameters 构造
func (s *WorkorderService) GetWorkOrderList(req *GetWorkOrderListRequest) (*GetWorkOrderListResponse, error) {
path := "/workorder/"
var resp GetWorkOrderListResponse
querys, err := common.MarshalQueryParams(req)
if err != nil {
return nil, err
}
err = s.client.Do(constant.HTTPMethod_GET, path, querys, nil, &resp)
return &resp, err
}
// 获取工单详情
//
// id: 工单ID
func (s *WorkorderService) GetWorkOrderDetail(id int) (*GetWorkOrderDetailResponse, error) {
path := fmt.Sprintf("/workorder/%d", id)
var resp GetWorkOrderDetailResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
// 创建工单
func (s *WorkorderService) CreateWorkOrder(req *CreateWorkerorderRequest) (*CreateWorkerorderResponse, error) {
path := "/workorder/"
var resp CreateWorkerorderResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, req, &resp)
return &resp, err
}
// 产品授权
//
// id:工单ID
//
// productID:产品ID
//
// productType:产品类型(rvh/rcs/rgs/rbm/ros)
func (s *WorkorderService) ProductAuth(id int, productID int, productType string) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/workorder/%d/auth", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, ProductAuthRequest{ProductID: productID, ProductType: productType}, &resp)
return &resp, err
}
// 回复工单
//
// id: 工单ID
//
// content: 回复内容
func (s *WorkorderService) ReplyWorkorder(id int, content string) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/workorder/%d/reply_order", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_POST, path, nil, ReplyWorkerorderRequest{Content: content}, &resp)
return &resp, err
}
// 编辑回复工单
//
// id: 工单ID
//
// replyID: 回复ID
//
// content: 编辑后的内容
func (s *WorkorderService) EditWorkorderReply(id int, replyID int, content string) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/workorder/%d/reply_order/%d", id, replyID)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PATCH, path, nil, ReplyWorkerorderRequest{Content: content}, &resp)
return &resp, err
}
// 获取工单状态
//
// id: 工单ID
func (s *WorkorderService) GetWorkorderStatus(id int) (*GetWorkorderStatusResponse, error) {
path := fmt.Sprintf("/workorder/%d/status", id)
var resp GetWorkorderStatusResponse
err := s.client.Do(constant.HTTPMethod_GET, path, nil, nil, &resp)
return &resp, err
}
// 设置工单状态
//
// id: 工单ID
//
// status: 目标状态
func (s *WorkorderService) SetWorkorderStatus(id int, status string) (*common.BasicOperationResponse, error) {
path := fmt.Sprintf("/workorder/%d/status", id)
var resp common.BasicOperationResponse
err := s.client.Do(constant.HTTPMethod_PATCH, path, nil, SetWorkorderStatusRequest{Status: status}, &resp)
return &resp, err
}
+50
View File
@@ -0,0 +1,50 @@
package billing
import (
"strconv"
"time"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/apis/expense"
"github.com/XingfenD/rainyun_api_go_sdk/cmd/ry/internal/model"
"github.com/XingfenD/rainyun_api_go_sdk/cmd/ry/internal/output"
"github.com/XingfenD/rainyun_api_go_sdk/sdk"
"github.com/spf13/cobra"
)
func Cmd(rySDK **sdk.RainyunSDK, out **output.Printer) *cobra.Command {
billingCmd := &cobra.Command{
Use: "billing",
Short: "Billing and orders",
}
ordersCmd := &cobra.Command{
Use: "orders",
Short: "List orders",
RunE: func(cmd *cobra.Command, args []string) error {
resp, err := (*rySDK).GetOrdersList(&expense.GetOrdersListRequest{
Options: common.StandQueryParameters{Page: 1, PerPage: 50},
})
if err != nil {
return err
}
orders := make([]model.Order, len(resp.Data.Records))
for i, r := range resp.Data.Records {
t, _ := time.Parse("2006-01-02 15:04:05", r.CreateDate)
orders[i] = model.Order{
ID: strconv.Itoa(r.ID),
Product: r.ProductName,
Amount: r.Amount,
Status: r.Status,
Created: t,
}
}
return (*out).Print(orders)
},
}
billingCmd.AddCommand(ordersCmd)
return billingCmd
}
+100
View File
@@ -0,0 +1,100 @@
package configcmd
import (
"fmt"
"strings"
"github.com/XingfenD/rainyun_api_go_sdk/cmd/ry/internal/config"
"github.com/spf13/cobra"
)
func Cmd(cfg **config.Config, cfgPath string) *cobra.Command {
configCmd := &cobra.Command{
Use: "config",
Short: "Manage ry configuration",
Annotations: map[string]string{"skipSDK": "true"},
}
configShowCmd := &cobra.Command{
Use: "show",
Short: "Show current configuration",
Annotations: map[string]string{"skipSDK": "true"},
RunE: func(cmd *cobra.Command, args []string) error {
c := *cfg
fmt.Printf("Config file: %s\n", cfgPath)
masked := c.APIKey
if len(masked) > 4 {
masked = masked[:2] + strings.Repeat("*", len(masked)-4) + masked[len(masked)-2:]
}
fmt.Printf("API key: %s\n", masked)
fmt.Printf("Output: %s\n", c.Output)
return nil
},
}
configSetCmd := &cobra.Command{
Use: "set <key> [value]",
Short: "Set a config value",
Args: cobra.RangeArgs(1, 2),
Annotations: map[string]string{"skipSDK": "true"},
RunE: func(cmd *cobra.Command, args []string) error {
key := args[0]
var value string
if len(args) == 2 {
value = args[1]
} else {
// Interactive mode — prompt for the value.
if key == "apikey" {
v, err := config.ReadSecret("Enter API key: ")
if err != nil {
return fmt.Errorf("read API key: %w", err)
}
value = v
} else {
v, err := config.ReadLine("Enter " + key + ": ")
if err != nil {
return fmt.Errorf("read %s: %w", key, err)
}
value = v
}
}
c := *cfg
switch key {
case "apikey":
c.APIKey = value
case "output":
c.Output = value
default:
return fmt.Errorf("unknown config key: %s (supported: apikey, output)", key)
}
if err := config.Save(cfgPath, c); err != nil {
return fmt.Errorf("save config: %w", err)
}
if key == "apikey" {
fmt.Printf("Set %s = %s\n", key, "(hidden)")
} else {
fmt.Printf("Set %s = %s\n", key, value)
}
return nil
},
}
configPathCmd := &cobra.Command{
Use: "path",
Short: "Print config file path",
Annotations: map[string]string{"skipSDK": "true"},
RunE: func(cmd *cobra.Command, args []string) error {
fmt.Println(cfgPath)
return nil
},
}
configCmd.AddCommand(configShowCmd)
configCmd.AddCommand(configSetCmd)
configCmd.AddCommand(configPathCmd)
return configCmd
}
+137
View File
@@ -0,0 +1,137 @@
package domain
import (
"fmt"
"strconv"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/apis/domain"
"github.com/XingfenD/rainyun_api_go_sdk/cmd/ry/internal/model"
"github.com/XingfenD/rainyun_api_go_sdk/cmd/ry/internal/output"
"github.com/XingfenD/rainyun_api_go_sdk/sdk"
"github.com/spf13/cobra"
)
func Cmd(rySDK **sdk.RainyunSDK, out **output.Printer) *cobra.Command {
domainCmd := &cobra.Command{
Use: "domain",
Short: "Manage domains",
}
domainListCmd := &cobra.Command{
Use: "list",
Short: "List domains",
RunE: func(cmd *cobra.Command, args []string) error {
resp, err := (*rySDK).GetDomainList(&domain.GetDomainListRequest{
Options: common.StandQueryParameters{Page: 1, PerPage: 50},
})
if err != nil {
return err
}
domains := make([]model.Domain, len(resp.Data.Records))
for i, r := range resp.Data.Records {
domains[i] = model.Domain{
ID: strconv.Itoa(r.ID),
Name: r.DomainName,
}
}
return (*out).Print(domains)
},
}
dnsCmd := &cobra.Command{
Use: "dns",
Short: "Manage DNS records",
}
dnsListCmd := &cobra.Command{
Use: "list <domain-id>",
Short: "List DNS records",
RunE: func(cmd *cobra.Command, args []string) error {
id, err := strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("invalid domain id: %s", args[0])
}
resp, err := (*rySDK).GetDomainDNSRecordList(id)
if err != nil {
return err
}
records := make([]model.DNSRecord, len(resp.Data))
for i, r := range resp.Data {
records[i] = model.DNSRecord{
ID: strconv.Itoa(r.ID),
Type: r.RecordType,
Name: r.Host,
Value: r.Value,
TTL: r.TTL,
}
}
return (*out).Print(records)
},
}
dnsAddCmd := &cobra.Command{
Use: "add <domain-id>",
Short: "Add a DNS record",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
id, err := strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("invalid domain id: %s", args[0])
}
recType, _ := cmd.Flags().GetString("type")
host, _ := cmd.Flags().GetString("host")
value, _ := cmd.Flags().GetString("value")
ttl, _ := cmd.Flags().GetInt("ttl")
req := &domain.AddDomainDNSRecordRequest{
Type: recType,
Host: host,
Value: value,
TTL: ttl,
Line: "DEFAULT",
Level: 10,
}
if _, err := (*rySDK).AddDomainDNSRecord(id, req); err != nil {
return err
}
fmt.Printf("DNS record added for domain %s\n", args[0])
return nil
},
}
dnsDeleteCmd := &cobra.Command{
Use: "delete <domain-id> <record-id>",
Short: "Delete a DNS record",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
domainID, err := strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("invalid domain id: %s", args[0])
}
recordID, err := strconv.Atoi(args[1])
if err != nil {
return fmt.Errorf("invalid record id: %s", args[1])
}
if _, err := (*rySDK).DeleteDomainDNSRecord(domainID, recordID); err != nil {
return err
}
fmt.Printf("DNS record %s deleted for domain %s\n", args[1], args[0])
return nil
},
}
dnsAddCmd.Flags().String("type", "A", "Record type (A, AAAA, CNAME, TXT, MX, SRV)")
dnsAddCmd.Flags().String("host", "@", "Record host name")
dnsAddCmd.Flags().String("value", "", "Record value")
dnsAddCmd.Flags().Int("ttl", 600, "TTL in seconds")
dnsAddCmd.MarkFlagRequired("value")
dnsCmd.AddCommand(dnsListCmd)
dnsCmd.AddCommand(dnsAddCmd)
dnsCmd.AddCommand(dnsDeleteCmd)
domainCmd.AddCommand(domainListCmd)
domainCmd.AddCommand(dnsCmd)
return domainCmd
}
+205
View File
@@ -0,0 +1,205 @@
package server
import (
"fmt"
"strconv"
"time"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/apis/rcs"
"github.com/XingfenD/rainyun_api_go_sdk/cmd/ry/internal/model"
"github.com/XingfenD/rainyun_api_go_sdk/cmd/ry/internal/output"
"github.com/XingfenD/rainyun_api_go_sdk/sdk"
"github.com/spf13/cobra"
)
func Cmd(rySDK **sdk.RainyunSDK, out **output.Printer, raw *bool) *cobra.Command {
serverCmd := &cobra.Command{
Use: "server",
Short: "Manage cloud servers",
}
serverListCmd := &cobra.Command{
Use: "list",
Short: "List servers",
RunE: func(cmd *cobra.Command, args []string) error {
resp, err := (*rySDK).GetRcsList(&rcs.GetRcsListRequest{
Options: common.StandQueryParameters{Page: 1, PerPage: 50},
})
if err != nil {
return err
}
servers := make([]model.Server, len(resp.Data.Records))
for i, r := range resp.Data.Records {
servers[i] = toServer(r)
}
if *raw {
return (*out).Print(resp)
}
return (*out).Print(servers)
},
}
serverGetCmd := &cobra.Command{
Use: "get <id>",
Short: "Get server details",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
id, err := strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("invalid server id: %s", args[0])
}
resp, err := (*rySDK).GetRcsDetail(id)
if err != nil {
return err
}
s := toServer(resp.Data.Data)
if *raw {
return (*out).Print(resp)
}
return (*out).Print(s)
},
}
serverStartCmd := &cobra.Command{
Use: "start <id>",
Short: "Start a server",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
id, err := strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("invalid server id: %s", args[0])
}
if _, err := (*rySDK).StartRcs(id); err != nil {
return err
}
fmt.Printf("Server %s started\n", args[0])
return nil
},
}
serverStopCmd := &cobra.Command{
Use: "stop <id>",
Short: "Stop a server",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
id, err := strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("invalid server id: %s", args[0])
}
if _, err := (*rySDK).StopRcs(id); err != nil {
return err
}
fmt.Printf("Server %s stopped\n", args[0])
return nil
},
}
serverRebootCmd := &cobra.Command{
Use: "reboot <id>",
Short: "Reboot a server",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
id, err := strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("invalid server id: %s", args[0])
}
if _, err := (*rySDK).RebootRcs(id); err != nil {
return err
}
fmt.Printf("Server %s rebooted\n", args[0])
return nil
},
}
serverReinstallCmd := &cobra.Command{
Use: "reinstall <id>",
Short: "Reinstall server OS",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
id, err := strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("invalid server id: %s", args[0])
}
osID, _ := cmd.Flags().GetInt("os-id")
if osID == 0 {
return fmt.Errorf("--os-id flag is required (e.g. --os-id 123)")
}
if _, err := (*rySDK).ReinstallRcs(id, &rcs.ReinstallRcsRequest{OsID: osID}); err != nil {
return err
}
fmt.Printf("Server %s reinstalling with os-id %d\n", args[0], osID)
return nil
},
}
serverResetPasswordCmd := &cobra.Command{
Use: "reset-password <id>",
Short: "Reset server password",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
id, err := strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("invalid server id: %s", args[0])
}
if _, err := (*rySDK).ResetRcsPassword(id, ""); err != nil {
return err
}
fmt.Printf("Password reset for server %s\n", args[0])
return nil
},
}
serverVNCCmd := &cobra.Command{
Use: "vnc <id>",
Short: "Get VNC connection URL",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
id, err := strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("invalid server id: %s", args[0])
}
v, err := (*rySDK).GetRcsVnc(id, "novnc")
if err != nil {
return err
}
url, uerr := common.GetVncConnectURL(v)
if uerr != nil || url == "" {
fmt.Println(v.Data.VNCProxyURL)
} else {
fmt.Println(url)
}
return nil
},
}
serverReinstallCmd.Flags().Int("os-id", 0, "OS template ID (required)")
serverReinstallCmd.MarkFlagRequired("os-id")
serverCmd.AddCommand(serverListCmd)
serverCmd.AddCommand(serverGetCmd)
serverCmd.AddCommand(serverStartCmd)
serverCmd.AddCommand(serverStopCmd)
serverCmd.AddCommand(serverRebootCmd)
serverCmd.AddCommand(serverReinstallCmd)
serverCmd.AddCommand(serverResetPasswordCmd)
serverCmd.AddCommand(serverVNCCmd)
return serverCmd
}
func toServer(r rcs.RcsRecord) model.Server {
return model.Server{
ID: strconv.Itoa(r.ID),
Name: r.HostName,
Status: r.Status,
IP: r.MainIPv4,
CPU: r.CPU,
Memory: r.Memory,
Disk: r.Disk,
OS: r.OsName,
Region: r.Zone,
ExpireAt: time.Unix(int64(r.ExpDate), 0),
}
}
+99
View File
@@ -0,0 +1,99 @@
package storage
import (
"fmt"
"strconv"
"github.com/XingfenD/rainyun_api_go_sdk/apis/common"
"github.com/XingfenD/rainyun_api_go_sdk/apis/ros"
"github.com/XingfenD/rainyun_api_go_sdk/cmd/ry/internal/model"
"github.com/XingfenD/rainyun_api_go_sdk/cmd/ry/internal/output"
"github.com/XingfenD/rainyun_api_go_sdk/sdk"
"github.com/spf13/cobra"
)
func Cmd(rySDK **sdk.RainyunSDK, out **output.Printer) *cobra.Command {
storageCmd := &cobra.Command{
Use: "storage",
Short: "Manage object storage",
}
storageListCmd := &cobra.Command{
Use: "list",
Short: "List storage instances",
RunE: func(cmd *cobra.Command, args []string) error {
resp, err := (*rySDK).GetRosInstanceList(&ros.GetRosInstanceListRequest{
Options: common.StandQueryParameters{Page: 1, PerPage: 50},
})
if err != nil {
return err
}
instances := make([]model.StorageInstance, len(resp.Data.Records))
for i, r := range resp.Data.Records {
instances[i] = model.StorageInstance{
ID: strconv.Itoa(r.ID),
Name: r.Tag,
Status: r.Status,
}
}
return (*out).Print(instances)
},
}
bucketCmd := &cobra.Command{
Use: "bucket",
Short: "Manage buckets",
}
bucketListCmd := &cobra.Command{
Use: "list <instance-id>",
Short: "List buckets",
RunE: func(cmd *cobra.Command, args []string) error {
instanceID, err := strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("invalid instance id: %s", args[0])
}
resp, err := (*rySDK).GetRosBucketListByInstance(instanceID)
if err != nil {
return err
}
buckets := make([]model.Bucket, len(resp.Data.Records))
for i, b := range resp.Data.Records {
buckets[i] = model.Bucket{
ID: strconv.Itoa(b.ID),
Name: b.Name,
}
}
return (*out).Print(buckets)
},
}
bucketCreateCmd := &cobra.Command{
Use: "create <instance-id> <name>",
Short: "Create a bucket",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
instanceID, err := strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("invalid instance id: %s", args[0])
}
name := args[1]
if _, err := (*rySDK).CreateRosBucket(ros.CreateRosBucketRequest{
BucketName: name,
InstanceID: instanceID,
}); err != nil {
return err
}
fmt.Printf("Bucket %q created\n", name)
return nil
},
}
bucketCmd.AddCommand(bucketListCmd)
bucketCmd.AddCommand(bucketCreateCmd)
storageCmd.AddCommand(storageListCmd)
storageCmd.AddCommand(bucketCmd)
return storageCmd
}
+53
View File
@@ -0,0 +1,53 @@
package config
import (
"os"
"path/filepath"
"github.com/BurntSushi/toml"
)
type Config struct {
APIKey string `toml:"api_key,omitempty"`
Output string `toml:"output"`
}
func Load(path string) (*Config, error) {
cfg := &Config{Output: "table"}
data, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
return cfg, nil
}
return nil, err
}
if err := toml.Unmarshal(data, cfg); err != nil {
return nil, err
}
if cfg.Output == "" {
cfg.Output = "table"
}
return cfg, nil
}
func Save(path string, cfg *Config) error {
dir := filepath.Dir(path)
if err := os.MkdirAll(dir, 0700); err != nil {
return err
}
f, err := os.Create(path)
if err != nil {
return err
}
defer f.Close()
enc := toml.NewEncoder(f)
return enc.Encode(cfg)
}
func DefaultPath() string {
home, err := os.UserHomeDir()
if err != nil {
return "config.toml"
}
return filepath.Join(home, ".config", "ry", "config.toml")
}
+91
View File
@@ -0,0 +1,91 @@
package config
import (
"os"
"path/filepath"
"testing"
)
func TestLoadTOML(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "config.toml")
content := `
api_key = "sk-test123"
output = "json"
`
if err := os.WriteFile(path, []byte(content), 0600); err != nil {
t.Fatal(err)
}
cfg, err := Load(path)
if err != nil {
t.Fatalf("Load() error: %v", err)
}
if cfg.APIKey != "sk-test123" {
t.Errorf("APIKey = %q, want %q", cfg.APIKey, "sk-test123")
}
if cfg.Output != "json" {
t.Errorf("Output = %q, want %q", cfg.Output, "json")
}
}
func TestLoadDefaults(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "empty.toml")
if err := os.WriteFile(path, []byte(""), 0600); err != nil {
t.Fatal(err)
}
cfg, err := Load(path)
if err != nil {
t.Fatalf("Load() error: %v", err)
}
if cfg.Output != "table" {
t.Errorf("default Output = %q, want %q", cfg.Output, "table")
}
}
func TestLoadMissingFile(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "missing.toml")
cfg, err := Load(path)
if err != nil {
t.Fatalf("Load() missing file error: %v", err)
}
if cfg.Output != "table" {
t.Errorf("default Output = %q, want %q", cfg.Output, "table")
}
}
func TestSave(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "out.toml")
cfg := &Config{APIKey: "secret", Output: "json"}
if err := Save(path, cfg); err != nil {
t.Fatalf("Save() error: %v", err)
}
loaded, err := Load(path)
if err != nil {
t.Fatalf("re-Load() error: %v", err)
}
if loaded.APIKey != "secret" {
t.Errorf("roundtrip APIKey = %q", loaded.APIKey)
}
if loaded.Output != "json" {
t.Errorf("roundtrip Output = %q", loaded.Output)
}
}
func TestDefaultPath(t *testing.T) {
path := DefaultPath()
if path == "" {
t.Error("DefaultPath() returned empty")
}
}
func TestEnsureDir(t *testing.T) {
dir := filepath.Join(t.TempDir(), "sub", "dir")
path := filepath.Join(dir, "config.toml")
cfg := &Config{Output: "table"}
if err := Save(path, cfg); err != nil {
t.Fatalf("Save() to deep dir error: %v", err)
}
}
+43
View File
@@ -0,0 +1,43 @@
package config
import (
"bufio"
"fmt"
"os"
"golang.org/x/term"
)
// ReadSecret prompts the user with msg and reads a line from stdin.
// When stdin is a terminal, echo is disabled so the typed value stays
// invisible. When stdin is piped (non-TTY) it falls back to a normal
// read so scripting still works.
func ReadSecret(msg string) (string, error) {
fmt.Fprint(os.Stderr, msg)
var value string
if term.IsTerminal(int(os.Stdin.Fd())) {
b, err := term.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
return "", err
}
value = string(b)
} else {
sc := bufio.NewScanner(os.Stdin)
if !sc.Scan() {
return "", sc.Err()
}
value = sc.Text()
}
fmt.Fprintln(os.Stderr)
return value, nil
}
// ReadLine prompts the user with msg and reads a normal (echo-enabled) line.
func ReadLine(msg string) (string, error) {
fmt.Fprint(os.Stderr, msg)
sc := bufio.NewScanner(os.Stdin)
if !sc.Scan() {
return "", sc.Err()
}
return sc.Text(), nil
}
+11
View File
@@ -0,0 +1,11 @@
package model
import "time"
type Order struct {
ID string `json:"id" table:"ID"`
Product string `json:"product" table:"PRODUCT"`
Amount float64 `json:"amount" table:"AMOUNT"`
Status string `json:"status" table:"STATUS"`
Created time.Time `json:"created" table:"CREATED"`
}
+14
View File
@@ -0,0 +1,14 @@
package model
type Domain struct {
ID string `json:"id" table:"ID"`
Name string `json:"name" table:"DOMAIN"`
}
type DNSRecord struct {
ID string `json:"id" table:"ID"`
Type string `json:"type" table:"TYPE"`
Name string `json:"name" table:"NAME"`
Value string `json:"value" table:"VALUE"`
TTL int `json:"ttl" table:"TTL"`
}
+16
View File
@@ -0,0 +1,16 @@
package model
import "time"
type Server struct {
ID string `json:"id" table:"ID"`
Name string `json:"name" table:"NAME"`
Status string `json:"status" table:"STATUS"`
IP string `json:"ip" table:"IP"`
CPU int `json:"cpu" table:"CPU"`
Memory int `json:"memory" table:"MEM"`
Disk int `json:"disk" table:"DISK"`
OS string `json:"os" table:"OS"`
Region string `json:"region" table:"REGION"`
ExpireAt time.Time `json:"expires" table:"EXPIRES"`
}
+12
View File
@@ -0,0 +1,12 @@
package model
type StorageInstance struct {
ID string `json:"id" table:"ID"`
Name string `json:"name" table:"NAME"`
Status string `json:"status" table:"STATUS"`
}
type Bucket struct {
ID string `json:"id" table:"ID"`
Name string `json:"name" table:"NAME"`
}
+12
View File
@@ -0,0 +1,12 @@
package output
import (
"encoding/json"
"io"
)
func printJSON(w io.Writer, data any) error {
enc := json.NewEncoder(w)
enc.SetIndent("", " ")
return enc.Encode(data)
}
+41
View File
@@ -0,0 +1,41 @@
package output
import (
"encoding/json"
"fmt"
"io"
)
type Printer struct {
format string
writer io.Writer
}
func New(format string, w io.Writer) *Printer {
return &Printer{format: format, writer: w}
}
func (p *Printer) Print(data any) error {
switch p.format {
case "table":
return printTable(p.writer, data)
case "json":
return printJSON(p.writer, data)
case "yaml":
return printYAML(p.writer, data)
case "raw":
b, err := json.Marshal(data)
if err != nil {
return err
}
_, err = fmt.Fprintln(p.writer, string(b))
return err
default:
return fmt.Errorf("unknown output format: %s", p.format)
}
}
func (p *Printer) PrintRaw(raw []byte) error {
_, err := fmt.Fprintln(p.writer, string(raw))
return err
}
+109
View File
@@ -0,0 +1,109 @@
package output
import (
"bytes"
"encoding/json"
"strings"
"testing"
)
type testItem struct {
ID string `json:"id" table:"ID"`
Name string `json:"name" table:"NAME"`
Age int `json:"age" table:"AGE"`
}
func TestTableFormat(t *testing.T) {
items := []testItem{
{ID: "1", Name: "Alice", Age: 30},
{ID: "2", Name: "Bob", Age: 25},
}
var buf bytes.Buffer
printer := New("table", &buf)
if err := printer.Print(items); err != nil {
t.Fatalf("Print table error: %v", err)
}
out := buf.String()
if !strings.Contains(out, "ID") || !strings.Contains(out, "Alice") {
t.Errorf("table output missing headers or data:\n%s", out)
}
}
func TestJSONFormat(t *testing.T) {
items := []testItem{{ID: "1", Name: "Alice", Age: 30}}
var buf bytes.Buffer
printer := New("json", &buf)
if err := printer.Print(items); err != nil {
t.Fatalf("Print json error: %v", err)
}
var parsed []testItem
if err := json.Unmarshal(buf.Bytes(), &parsed); err != nil {
t.Fatalf("invalid JSON output: %v", err)
}
if len(parsed) != 1 || parsed[0].ID != "1" {
t.Errorf("JSON content mismatch: %+v", parsed)
}
}
func TestYAMLFormat(t *testing.T) {
items := []testItem{{ID: "1", Name: "Alice", Age: 30}}
var buf bytes.Buffer
printer := New("yaml", &buf)
if err := printer.Print(items); err != nil {
t.Fatalf("Print yaml error: %v", err)
}
out := buf.String()
if !strings.Contains(out, "id:") || !strings.Contains(out, "Alice") {
t.Errorf("yaml output missing data:\n%s", out)
}
}
func TestRawFormat(t *testing.T) {
raw := []byte(`{"raw":"data"}`)
var buf bytes.Buffer
printer := New("raw", &buf)
if err := printer.PrintRaw(raw); err != nil {
t.Fatalf("PrintRaw error: %v", err)
}
if buf.String() != `{"raw":"data"}`+"\n" {
t.Errorf("raw output = %q", buf.String())
}
}
// 新增:Print 在 raw 格式下应输出 JSON
func TestRawPrintFormat(t *testing.T) {
items := []testItem{{ID: "1", Name: "Alice", Age: 30}}
var buf bytes.Buffer
printer := New("raw", &buf)
if err := printer.Print(items); err != nil {
t.Fatalf("Print raw error: %v", err)
}
var parsed []testItem
if err := json.Unmarshal(buf.Bytes(), &parsed); err != nil {
t.Fatalf("raw Print produced invalid JSON: %v\nbuf=%s", err, buf.String())
}
if len(parsed) != 1 || parsed[0].ID != "1" {
t.Errorf("raw Print content mismatch: %+v", parsed)
}
}
func TestSingleItem(t *testing.T) {
item := testItem{ID: "1", Name: "Solo", Age: 99}
var buf bytes.Buffer
printer := New("json", &buf)
if err := printer.Print(item); err != nil {
t.Fatalf("Print single item error: %v", err)
}
if !strings.Contains(buf.String(), "Solo") {
t.Errorf("single item output missing data:\n%s", buf.String())
}
}
func TestUnknownFormat(t *testing.T) {
var buf bytes.Buffer
printer := New("unknown", &buf)
err := printer.Print([]testItem{})
if err == nil {
t.Error("expected error for unknown format")
}
}
+115
View File
@@ -0,0 +1,115 @@
package output
import (
"fmt"
"io"
"reflect"
"strings"
)
func printTable(w io.Writer, data any) error {
v := reflect.ValueOf(data)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() == reflect.Slice {
return printTableSlice(w, v)
}
return printTableSingle(w, v)
}
func printTableSlice(w io.Writer, v reflect.Value) error {
if v.Len() == 0 {
fmt.Fprintln(w, "(empty)")
return nil
}
elemType := v.Index(0).Type()
if elemType.Kind() == reflect.Ptr {
elemType = elemType.Elem()
}
headers, cols := extractTableTags(elemType)
if len(headers) == 0 {
return fmt.Errorf("no table tags found on type %s", elemType.Name())
}
rows := make([][]string, v.Len())
for i := 0; i < v.Len(); i++ {
rows[i] = extractRow(v.Index(i), cols)
}
widths := make([]int, len(headers))
for i, h := range headers {
widths[i] = len(h)
}
for _, row := range rows {
for i, cell := range row {
if len(cell) > widths[i] {
widths[i] = len(cell)
}
}
}
sep := " "
renderRow(w, headers, widths, sep)
separator := make([]string, len(headers))
for i, ww := range widths {
separator[i] = strings.Repeat("-", ww)
}
renderRow(w, separator, widths, sep)
for _, row := range rows {
renderRow(w, row, widths, sep)
}
return nil
}
func renderRow(w io.Writer, cells []string, widths []int, sep string) {
parts := make([]string, len(cells))
for i, cell := range cells {
parts[i] = fmt.Sprintf("%-*s", widths[i], cell)
}
fmt.Fprintln(w, strings.Join(parts, sep))
}
func printTableSingle(w io.Writer, v reflect.Value) error {
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
t := v.Type()
for i := 0; i < t.NumField(); i++ {
tag := t.Field(i).Tag.Get("table")
if tag == "" {
continue
}
val := fmt.Sprintf("%v", v.Field(i).Interface())
fmt.Fprintf(w, "%-10s %s\n", tag+":", val)
}
return nil
}
func extractTableTags(t reflect.Type) ([]string, []int) {
var headers []string
var cols []int
for i := 0; i < t.NumField(); i++ {
tag := t.Field(i).Tag.Get("table")
if tag == "" {
continue
}
headers = append(headers, strings.ToUpper(tag))
cols = append(cols, i)
}
return headers, cols
}
func extractRow(v reflect.Value, cols []int) []string {
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
row := make([]string, len(cols))
for i, idx := range cols {
row[i] = fmt.Sprintf("%v", v.Field(idx).Interface())
}
return row
}
+13
View File
@@ -0,0 +1,13 @@
package output
import (
"io"
"gopkg.in/yaml.v3"
)
func printYAML(w io.Writer, data any) error {
enc := yaml.NewEncoder(w)
enc.SetIndent(2)
return enc.Encode(data)
}
+13
View File
@@ -0,0 +1,13 @@
package main
import (
"fmt"
"os"
)
func main() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
+112
View File
@@ -0,0 +1,112 @@
package main
import (
"fmt"
"os"
"github.com/XingfenD/rainyun_api_go_sdk/cmd/ry/commands/billing"
"github.com/XingfenD/rainyun_api_go_sdk/cmd/ry/commands/configcmd"
"github.com/XingfenD/rainyun_api_go_sdk/cmd/ry/commands/domain"
"github.com/XingfenD/rainyun_api_go_sdk/cmd/ry/commands/server"
"github.com/XingfenD/rainyun_api_go_sdk/cmd/ry/commands/storage"
"github.com/XingfenD/rainyun_api_go_sdk/cmd/ry/internal/config"
"github.com/XingfenD/rainyun_api_go_sdk/cmd/ry/internal/output"
"github.com/XingfenD/rainyun_api_go_sdk/sdk"
"github.com/spf13/cobra"
)
var (
cfg *config.Config
cfgPath string
rySDK *sdk.RainyunSDK
out *output.Printer
flagAPIKey string
flagOutput string
flagRaw bool
flagVerbose bool
)
var rootCmd = &cobra.Command{
Use: "ry",
Short: "Rainyun CLI — manage cloud resources from your terminal",
Long: `ry is a CLI that lets you manage Rainyun cloud resources from your terminal.
Use "ry [command] --help" for more information about a command.`,
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Help()
},
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
var err error
cfg, err = config.Load(cfgPath)
if err != nil {
return fmt.Errorf("load config: %w", err)
}
if cmd.Annotations != nil && cmd.Annotations["skipSDK"] == "true" {
return nil
}
apiKey := cfg.APIKey
if flagAPIKey != "" {
apiKey = flagAPIKey
}
if env := os.Getenv("RY_APIKEY"); env != "" {
apiKey = env
}
if apiKey == "" {
return fmt.Errorf("no api key configured — run 'ry config set apikey <key>'")
}
rySDK = sdk.New(apiKey)
outputFormat := cfg.Output
if flagOutput != "" {
outputFormat = flagOutput
}
if flagRaw {
outputFormat = "raw"
}
out = output.New(outputFormat, os.Stdout)
if flagVerbose {
fmt.Fprintf(os.Stderr, "[debug] config: %s\n", cfgPath)
fmt.Fprintf(os.Stderr, "[debug] output: %s\n", outputFormat)
}
return nil
},
}
func init() {
rootCmd.SilenceErrors = true
rootCmd.SilenceUsage = true
cfgPath = config.DefaultPath()
rootCmd.PersistentFlags().StringVar(&flagAPIKey, "apikey", "", "Rainyun API key")
rootCmd.PersistentFlags().StringVarP(&flagOutput, "output", "o", "", "Output format: table, json, yaml, raw")
rootCmd.PersistentFlags().BoolVar(&flagRaw, "raw", false, "Output raw API response")
rootCmd.PersistentFlags().BoolVarP(&flagVerbose, "verbose", "v", false, "Enable verbose output")
completionCmd := &cobra.Command{
Use: "completion [bash|zsh|fish]",
Short: "Generate shell completion script",
Annotations: map[string]string{"skipSDK": "true"},
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
switch args[0] {
case "bash":
return rootCmd.GenBashCompletion(os.Stdout)
case "zsh":
return rootCmd.GenZshCompletion(os.Stdout)
case "fish":
return rootCmd.GenFishCompletion(os.Stdout, true)
default:
return fmt.Errorf("unsupported shell: %s", args[0])
}
},
}
rootCmd.AddCommand(completionCmd)
rootCmd.AddCommand(configcmd.Cmd(&cfg, cfgPath))
rootCmd.AddCommand(server.Cmd(&rySDK, &out, &flagRaw))
rootCmd.AddCommand(storage.Cmd(&rySDK, &out))
rootCmd.AddCommand(domain.Cmd(&rySDK, &out))
rootCmd.AddCommand(billing.Cmd(&rySDK, &out))
}
+1
View File
@@ -7,4 +7,5 @@ const (
HTTPMethod_POST HTTPMethod = "POST" HTTPMethod_POST HTTPMethod = "POST"
HTTPMethod_DELETE HTTPMethod = "DELETE" HTTPMethod_DELETE HTTPMethod = "DELETE"
HTTPMethod_PUT HTTPMethod = "PUT" HTTPMethod_PUT HTTPMethod = "PUT"
HTTPMethod_PATCH HTTPMethod = "PATCH"
) )
+44
View File
@@ -6,6 +6,50 @@ All notable changes to this template should be documented in this file.
The format loosely follows Keep a Changelog and can be adapted to the team's habits. The format loosely follows Keep a Changelog and can be adapted to the team's habits.
本文档参考了 Keep a Changelog 的思路,也可以根据团队习惯调整。 本文档参考了 Keep a Changelog 的思路,也可以根据团队习惯调整。
## [Unreleased] - 2026-08-13
### Added / 新增
- `config set <key>` 支持交互式输入:省略 value 时交互式提示,`apikey` 使用隐藏输入避免敏感信息暴露在终端/历史中。
- 新增 `Makefile`(build/test/vet/fmt/cover/tidy/clean/help)。
- 迁移 rainyun-cli 到仓库内 `cmd/ry/`:新增 `main.go`、`root.go`、`commands/{server,domain,storage,billing,configcmd}`、`internal/{config,model,output}`。
- CLI 直接调用 `sdk.New(apiKey)`,删除 CLI 自带 provider/HTTP 层。
- 配置简化为单一 `apikey` + `output`(table/json/yaml),落盘到 `~/.config/ry/config.toml`。
- 补齐 SDK 4 个缺口端点:`domain list`、`dns list`、`bucket-by-instance`、`expense orders`。
- 新增 `cmd/ry/internal/config` 与 `cmd/ry/internal/output` 测试(6/6 + 7/7)。
### Fixed / 修复
- 修复 `output --raw` 输出 bug:新增 raw case,原样透传 SDK Response。
### Changed / 变更
- 命令 ID 参数统一为 `int`,显示层 model ID 保持 `string`。
- `server reinstall` flag 从 `--os` 改为 `--os-id int`。
- `.gitignore` 新增 `bin/`、`coverage.out`、`coverage.html`。
- 新增 `golang.org/x/term` 依赖(交互式隐藏输入)。
## [0.2.0] - 2026-08-05
### Added / 新增
- 迁移剩余全部模块:domain(24)、product(8)、rbm(10)、rca(21)、rgs(38)、ros(19)、ssl(5)、user(10)、workorder(11),并补全 public 剩余 5 个接口。
- 全部响应结构体嵌套拆分命名复用;rgs 复用 rcs 的请求/响应类型。
- `sdk.New` 注册全部 11 个服务。
### Fixed / 修复
- 修正源 SDK 中的路径错误(`{id}` 占位符、缺少 `/`、`/product/rcs/` 误写为 rgs 路径等)与参数传递错误(`resp` vs `&resp`、漏传 body)。
## [0.1.0] - 2026-08-05
### Added / 新增
- 从 `rainyun-go-sdk` 迁移 RCS 全部 35 个接口(列表/详情/创建/备份/防火墙/监控/NAT/续费/升降级等),响应结构体嵌套已拆分复用(`RcsRecord`、`Node`、`Plan`、`OsInfo`、`UsageData` 等)。
- 新增 `apis/common` 基础类型:`BasicOperationResponse`、`VncConnectionInfo`。
- `constant` 新增 `HTTPMethod_PATCH`。
## [0.0.0] - 2026-08-02 ## [0.0.0] - 2026-08-02
### Notes / 说明 ### Notes / 说明
+11 -2
View File
@@ -2,13 +2,22 @@ module github.com/XingfenD/rainyun_api_go_sdk
go 1.24.1 go 1.24.1
require (
github.com/BurntSushi/toml v1.6.0
github.com/bytedance/sonic v1.15.2
github.com/go-resty/resty/v2 v2.17.2
github.com/spf13/cobra v1.10.2
golang.org/x/term v0.34.0
gopkg.in/yaml.v3 v3.0.1
)
require ( require (
github.com/bytedance/gopkg v0.1.3 // indirect github.com/bytedance/gopkg v0.1.3 // indirect
github.com/bytedance/sonic v1.15.2 // indirect
github.com/bytedance/sonic/loader v0.5.1 // indirect github.com/bytedance/sonic/loader v0.5.1 // indirect
github.com/cloudwego/base64x v0.1.6 // indirect github.com/cloudwego/base64x v0.1.6 // indirect
github.com/go-resty/resty/v2 v2.17.2 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.9 // indirect github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/spf13/pflag v1.0.9 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
golang.org/x/net v0.43.0 // indirect golang.org/x/net v0.43.0 // indirect
+21 -2
View File
@@ -1,3 +1,5 @@
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M= github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM= github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
github.com/bytedance/sonic v1.15.2 h1:90H+rcF/FwLXwfB1cudOLq/je83n683Utf4Cbp0xHCo= github.com/bytedance/sonic v1.15.2 h1:90H+rcF/FwLXwfB1cudOLq/je83n683Utf4Cbp0xHCo=
@@ -6,13 +8,23 @@ github.com/bytedance/sonic/loader v0.5.1 h1:Ygpfa9zwRCCKSlrp5bBP/b/Xzc3VxsAW+5NI
github.com/bytedance/sonic/loader v0.5.1/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo= github.com/bytedance/sonic/loader v0.5.1/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-resty/resty/v2 v2.17.2 h1:FQW5oHYcIlkCNrMD2lloGScxcHJ0gkjshV3qcQAyHQk= github.com/go-resty/resty/v2 v2.17.2 h1:FQW5oHYcIlkCNrMD2lloGScxcHJ0gkjshV3qcQAyHQk=
github.com/go-resty/resty/v2 v2.17.2/go.mod h1:kCKZ3wWmwJaNc7S29BRtUhJwy7iqmn+2mLtQrOyQlVA= github.com/go-resty/resty/v2 v2.17.2/go.mod h1:kCKZ3wWmwJaNc7S29BRtUhJwy7iqmn+2mLtQrOyQlVA=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -20,16 +32,23 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

Some files were not shown because too many files have changed in this diff Show More