diff --git a/go.mod b/go.mod index 9425486db..493943ebb 100644 --- a/go.mod +++ b/go.mod @@ -77,7 +77,6 @@ require ( github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.3.112 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.3.111 github.com/ucloud/ucloud-sdk-go v0.22.77 - github.com/volcengine/ve-tos-golang-sdk/v2 v2.9.5 github.com/volcengine/volc-sdk-golang v1.0.250 github.com/volcengine/volcengine-go-sdk v1.2.35 github.com/wneessen/go-mail v0.7.3 diff --git a/go.sum b/go.sum index 63e091f37..8ec0529ce 100644 --- a/go.sum +++ b/go.sum @@ -849,7 +849,6 @@ github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -933,8 +932,6 @@ github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqri github.com/ucloud/ucloud-sdk-go v0.22.77 h1:5f54RZhVm4lgQ5RbKnzbk2Ck79XBn/cYRJbZ3zsNogQ= github.com/ucloud/ucloud-sdk-go v0.22.77/go.mod h1:dyLmFHmUfgb4RZKYQP9IArlvQ2pxzFthfhwxRzOEPIw= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= -github.com/volcengine/ve-tos-golang-sdk/v2 v2.9.5 h1:6f6C0aTlnPiCH+KRKknf8vxbqqn0aA0J9WhO5mArFfg= -github.com/volcengine/ve-tos-golang-sdk/v2 v2.9.5/go.mod h1:IrjK84IJJTuOZOTMv/P18Ydjy/x+ow7fF7q11jAxXLM= github.com/volcengine/volc-sdk-golang v1.0.23/go.mod h1:AfG/PZRUkHJ9inETvbjNifTDgut25Wbkm2QoYBTbvyU= github.com/volcengine/volc-sdk-golang v1.0.250 h1:2/RLIahTgZ57OkNgDV0FpAkvk/4QFMGIuVFTnU26GDs= github.com/volcengine/volc-sdk-golang v1.0.250/go.mod h1:zHJlaqiMbIB+0mcrsZPTwOb3FB7S/0MCfqlnO8R7hlM= @@ -1235,7 +1232,6 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/pkg/core/deployer/providers/byteplus-tos/byteplus_tos.go b/pkg/core/deployer/providers/byteplus-tos/byteplus_tos.go index 790170dba..77eca644d 100644 --- a/pkg/core/deployer/providers/byteplus-tos/byteplus_tos.go +++ b/pkg/core/deployer/providers/byteplus-tos/byteplus_tos.go @@ -4,11 +4,11 @@ import ( "context" "fmt" "log/slog" - - "github.com/volcengine/ve-tos-golang-sdk/v2/tos" + "net/url" "github.com/certimate-go/certimate/pkg/core" cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/byteplus-certcenter" + tossdk "github.com/certimate-go/certimate/pkg/sdk3rd/volcengine/tos" ) type ( @@ -34,7 +34,7 @@ type DeployerConfig struct { type Deployer struct { config *DeployerConfig logger *slog.Logger - sdkClient *tos.ClientV2 + sdkClient *tossdk.Client sdkCertmgr core.Certmgr } @@ -45,7 +45,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { return nil, fmt.Errorf("the configuration of the deployer provider is nil") } - client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey, config.Region) + client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey, config.Region, config.Bucket) if err != nil { return nil, fmt.Errorf("could not create client: %w", err) } @@ -96,16 +96,14 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep // 设置自定义域名 // REF: https://docs.byteplus.com/en/docs/tos/Putbucketcustomdomain - // REF: https://docs.byteplus.com/en/docs/tos/Manage-custom-domain-names-go-sdk - putBucketCustomDomainReq := &tos.PutBucketCustomDomainInput{ - Bucket: d.config.Bucket, - Rule: tos.CustomDomainRule{ + putBucketCustomDomainReq := &tossdk.PutBucketCustomDomainRequest{ + CustomDomainRule: &tossdk.PutBucketCustomDomainRequestCustomDomainRule{ Domain: d.config.Domain, - CertID: upres.CertId, + CertId: upres.CertId, }, } - putBucketCustomDomainResp, err := d.sdkClient.PutBucketCustomDomain(ctx, putBucketCustomDomainReq) - d.logger.Debug("sdk request 'tos.PutBucketCustomDomain'", slog.Any("request", putBucketCustomDomainReq), slog.Any("response", putBucketCustomDomainResp)) + putBucketCustomDomainResp, err := d.sdkClient.PutBucketCustomDomainWithContext(ctx, putBucketCustomDomainReq) + d.logger.Debug("sdk request 'tos.PutBucketCustomDomain'", slog.String("params.bucket", d.config.Bucket), slog.Any("request", putBucketCustomDomainReq), slog.Any("response", putBucketCustomDomainResp)) if err != nil { return nil, fmt.Errorf("failed to execute sdk request 'tos.PutBucketCustomDomain': %w", err) } @@ -113,13 +111,13 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep return &DeployResult{}, nil } -func createSDKClient(accessKeyId, secretAccessKey, region string) (*tos.ClientV2, error) { - endpoint := fmt.Sprintf("tos-%s.bytepluses.com", region) +func createSDKClient(accessKeyId, secretAccessKey, region, bucket string) (*tossdk.Client, error) { + endpoint := fmt.Sprintf("https://%s.tos-%s.bytepluses.com", url.PathEscape(bucket), url.PathEscape(region)) - client, err := tos.NewClientV2( - endpoint, - tos.WithRegion(region), - tos.WithCredentials(tos.NewStaticCredentials(accessKeyId, secretAccessKey)), + client, err := tossdk.NewClient(endpoint, + tossdk.WithAkSk(accessKeyId, secretAccessKey), + tossdk.WithRegion(region), + tossdk.WithBucket(bucket), ) if err != nil { return nil, err diff --git a/pkg/core/deployer/providers/volcengine-tos/volcengine_tos.go b/pkg/core/deployer/providers/volcengine-tos/volcengine_tos.go index 6b3a30a70..bcc432ed9 100644 --- a/pkg/core/deployer/providers/volcengine-tos/volcengine_tos.go +++ b/pkg/core/deployer/providers/volcengine-tos/volcengine_tos.go @@ -5,10 +5,9 @@ import ( "fmt" "log/slog" - "github.com/volcengine/ve-tos-golang-sdk/v2/tos" - "github.com/certimate-go/certimate/pkg/core" cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/volcengine-certcenter" + tossdk "github.com/certimate-go/certimate/pkg/sdk3rd/volcengine/tos" ) type ( @@ -34,7 +33,7 @@ type DeployerConfig struct { type Deployer struct { config *DeployerConfig logger *slog.Logger - sdkClient *tos.ClientV2 + sdkClient *tossdk.Client sdkCertmgr core.Certmgr } @@ -45,7 +44,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { return nil, fmt.Errorf("the configuration of the deployer provider is nil") } - client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey, config.Region) + client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey, config.Region, config.Bucket) if err != nil { return nil, fmt.Errorf("could not create client: %w", err) } @@ -96,15 +95,14 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep // 设置自定义域名 // REF: https://www.volcengine.com/docs/6349/764779 - putBucketCustomDomainReq := &tos.PutBucketCustomDomainInput{ - Bucket: d.config.Bucket, - Rule: tos.CustomDomainRule{ + putBucketCustomDomainReq := &tossdk.PutBucketCustomDomainRequest{ + CustomDomainRule: &tossdk.PutBucketCustomDomainRequestCustomDomainRule{ Domain: d.config.Domain, - CertID: upres.CertId, + CertId: upres.CertId, }, } - putBucketCustomDomainResp, err := d.sdkClient.PutBucketCustomDomain(ctx, putBucketCustomDomainReq) - d.logger.Debug("sdk request 'tos.PutBucketCustomDomain'", slog.Any("request", putBucketCustomDomainReq), slog.Any("response", putBucketCustomDomainResp)) + putBucketCustomDomainResp, err := d.sdkClient.PutBucketCustomDomainWithContext(ctx, putBucketCustomDomainReq) + d.logger.Debug("sdk request 'tos.PutBucketCustomDomain'", slog.String("params.bucket", d.config.Bucket), slog.Any("request", putBucketCustomDomainReq), slog.Any("response", putBucketCustomDomainResp)) if err != nil { return nil, fmt.Errorf("failed to execute sdk request 'tos.PutBucketCustomDomain': %w", err) } @@ -112,13 +110,11 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep return &DeployResult{}, nil } -func createSDKClient(accessKeyId, secretAccessKey, region string) (*tos.ClientV2, error) { - endpoint := fmt.Sprintf("tos-%s.volces.com", region) - - client, err := tos.NewClientV2( - endpoint, - tos.WithRegion(region), - tos.WithCredentials(tos.NewStaticCredentials(accessKeyId, secretAccessKey)), +func createSDKClient(accessKeyId, secretAccessKey, region, bucket string) (*tossdk.Client, error) { + client, err := tossdk.NewClient("", + tossdk.WithAkSk(accessKeyId, secretAccessKey), + tossdk.WithRegion(region), + tossdk.WithBucket(bucket), ) if err != nil { return nil, err diff --git a/pkg/sdk3rd/ctyun/openapi/client.go b/pkg/sdk3rd/ctyun/openapi/client.go index 8a80ea5ec..4dfa10100 100644 --- a/pkg/sdk3rd/ctyun/openapi/client.go +++ b/pkg/sdk3rd/ctyun/openapi/client.go @@ -8,6 +8,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "hash" "io" "net/http" "net/url" @@ -73,14 +74,13 @@ func NewClient(baseUrl string, optFns ...OptionsFunc) (*Client, error) { payloadHash := sha256.Sum256([]byte(payloadStr)) payloadHashHex := hex.EncodeToString(payloadHash[:]) - h := hmac.New(sha256.New, []byte(opts.SecretAccessKey)) + var h hash.Hash + h = hmac.New(sha256.New, []byte(opts.SecretAccessKey)) h.Write([]byte(eopDate)) kTime := h.Sum(nil) - h = hmac.New(sha256.New, kTime) h.Write([]byte(opts.AccessKeyId)) kAk := h.Sum(nil) - h = hmac.New(sha256.New, kAk) h.Write([]byte(now.Format("20060102"))) kDate := h.Sum(nil) diff --git a/pkg/sdk3rd/huaweicloud/obs/client.go b/pkg/sdk3rd/huaweicloud/obs/client.go index ffcb469d4..09a9b3bec 100644 --- a/pkg/sdk3rd/huaweicloud/obs/client.go +++ b/pkg/sdk3rd/huaweicloud/obs/client.go @@ -154,6 +154,7 @@ func (c *Client) newRequest(method string, path string, params any) (*resty.Requ payloadStr := "" contentType := "" if params != nil { + // 目前仅支持 XML 请求体,仅适用于非 S3 兼容接口 payloadb, err := xml.Marshal(params) if err != nil { return nil, err diff --git a/pkg/sdk3rd/qingcloud/dns/client.go b/pkg/sdk3rd/qingcloud/dns/client.go index eaab5af65..c4c60fb48 100644 --- a/pkg/sdk3rd/qingcloud/dns/client.go +++ b/pkg/sdk3rd/qingcloud/dns/client.go @@ -36,7 +36,6 @@ func NewClient(optFns ...OptionsFunc) (*Client, error) { SetBaseURL("http://api.routewize.com"). SetHeader("Accept", "application/json"). SetHeader("Content-Type", "application/json"). - SetHeader("Host", "api.routewize.com"). SetHeader("User-Agent", app.AppUserAgent). SetPreRequestHook(func(c *resty.Client, req *http.Request) error { // 签名机制: diff --git a/pkg/sdk3rd/volcengine/tos/api_put_bucket_customdomain.go b/pkg/sdk3rd/volcengine/tos/api_put_bucket_customdomain.go new file mode 100644 index 000000000..d0ccb465d --- /dev/null +++ b/pkg/sdk3rd/volcengine/tos/api_put_bucket_customdomain.go @@ -0,0 +1,40 @@ +package tos + +import ( + "context" + "net/http" +) + +type PutBucketCustomDomainRequest struct { + CustomDomainRule *PutBucketCustomDomainRequestCustomDomainRule `json:",omitempty"` +} + +type PutBucketCustomDomainRequestCustomDomainRule struct { + CertId string `json:",omitempty"` + Domain string `json:",omitempty"` + Protocol string `json:",omitempty"` +} + +type PutBucketCustomDomainResponse struct { + sdkResponseBase +} + +func (c *Client) PutBucketCustomDomain(req *PutBucketCustomDomainRequest) (*PutBucketCustomDomainResponse, error) { + return c.PutBucketCustomDomainWithContext(context.Background(), req) +} + +func (c *Client) PutBucketCustomDomainWithContext(ctx context.Context, req *PutBucketCustomDomainRequest) (*PutBucketCustomDomainResponse, error) { + httpreq, err := c.newRequest(http.MethodPut, "/?customdomain", req) + if err != nil { + return nil, err + } else { + httpreq.SetContext(ctx) + } + + result := &PutBucketCustomDomainResponse{} + if _, err := c.doRequestWithResult(httpreq, result); err != nil { + return result, err + } + + return result, nil +} diff --git a/pkg/sdk3rd/volcengine/tos/client.go b/pkg/sdk3rd/volcengine/tos/client.go new file mode 100644 index 000000000..699754367 --- /dev/null +++ b/pkg/sdk3rd/volcengine/tos/client.go @@ -0,0 +1,258 @@ +package tos + +import ( + "crypto/hmac" + "crypto/md5" + "crypto/sha256" + "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "hash" + "net/http" + "net/url" + "sort" + "strings" + "time" + + "github.com/go-resty/resty/v2" + + "github.com/certimate-go/certimate/internal/app" +) + +type Client struct { + rc *resty.Client +} + +func NewClient(endpoint string, optFns ...OptionsFunc) (*Client, error) { + opts := &Options{} + for _, fn := range optFns { + fn(opts) + } + + if opts.Region == "" { + return nil, fmt.Errorf("sdkerr: unset region") + } + if opts.AccessKeyId == "" { + return nil, fmt.Errorf("sdkerr: unset accessKeyId") + } + if opts.SecretAccessKey == "" { + return nil, fmt.Errorf("sdkerr: unset secretAccessKey") + } + + if endpoint == "" { + if opts.Region == "" { + endpoint = fmt.Sprintf("https://tos-%s.volces.com", url.PathEscape(opts.Region)) + } else { + endpoint = fmt.Sprintf("https://%s.tos-%s.volces.com", url.PathEscape(opts.Bucket), url.PathEscape(opts.Region)) + } + } else { + if baseUrl, err := url.Parse(endpoint); err != nil { + return nil, fmt.Errorf("sdkerr: invalid endpoint: %w", err) + } else if baseUrl.Scheme == "" { + endpoint = "https://" + endpoint + } + } + + restyClient := resty.New(). + SetBaseURL(endpoint). + SetHeader("User-Agent", app.AppUserAgent). + SetPreRequestHook(func(c *resty.Client, req *http.Request) error { + // API 签名机制: + // https://www.volcengine.com/docs/6349/74839 + // https://docs.byteplus.com/en/docs/tos/reference-signature-mechanism_1 + + method := strings.ToUpper(req.Method) + + nowUtc := time.Now().UTC() + headerDateStr := nowUtc.Format(http.TimeFormat) + requestDateStr := nowUtc.Format("20060102T150405Z") + credentialDateStr := nowUtc.Format("20060102") + + canonicalUrl := req.URL.Path + if canonicalUrl == "" { + canonicalUrl = "/" + } + + canonicalQueryStr := "" + if len(req.URL.Query()) > 0 { + query := req.URL.Query() + + keys := make([]string, 0, len(query)) + for key := range query { + keys = append(keys, key) + } + sort.Strings(keys) + + for i, key := range keys { + if i > 0 { + canonicalQueryStr += "&" + } + + value := query.Get(key) + canonicalQueryStr += fmt.Sprintf("%s=%s", url.QueryEscape(key), url.QueryEscape(value)) + } + } + + canonicalHeaders := "" + signedHeaders := "" + if len(req.Header) > 0 || req.Host != "" { + if req.Header.Get("Host") == "" { + req.Header.Set("Host", req.Host) + } + if req.Header.Get("X-TOS-Date") == "" { + req.Header.Set("X-TOS-Date", requestDateStr) + } + + keys := make([]string, 0, len(req.Header)) + for key := range req.Header { + key = strings.ToLower(key) + if strings.HasPrefix(key, "x-tos-") || key == "host" { + keys = append(keys, key) + } + if key == "content-type" && req.Header.Get("X-TOS-Content-SHA256") != "" { + keys = append(keys, key) + } + } + sort.Strings(keys) + + for i, key := range keys { + if i > 0 { + canonicalHeaders += "\n" + signedHeaders += ";" + } + + value := strings.TrimSpace(req.Header.Get(key)) + canonicalHeaders += fmt.Sprintf("%s:%s", key, value) + signedHeaders += key + } + + canonicalHeaders += "\n" + } + + payloadSha256Str := req.Header.Get("X-TOS-Content-SHA256") + if payloadSha256Str == "" { + payloadSha256 := sha256.Sum256([]byte{}) + payloadSha256Str = strings.ToLower(hex.EncodeToString(payloadSha256[:])) + } + + canonicalRequest := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s", method, canonicalUrl, canonicalQueryStr, canonicalHeaders, signedHeaders, payloadSha256Str) + canonicalRequestHash := sha256.Sum256([]byte(canonicalRequest)) + canonicalRequestHashHex := strings.ToLower(hex.EncodeToString(canonicalRequestHash[:])) + + const signAlgorithmHeader = "TOS4-HMAC-SHA256" + credentialScope := fmt.Sprintf("%s/%s/tos/request", credentialDateStr, opts.Region) + stringToSign := fmt.Sprintf("%s\n%s\n%s\n%s", signAlgorithmHeader, requestDateStr, credentialScope, canonicalRequestHashHex) + + var h hash.Hash + h = hmac.New(sha256.New, []byte(opts.SecretAccessKey)) + h.Write([]byte(credentialDateStr)) + kDate := h.Sum(nil) + h = hmac.New(sha256.New, kDate) + h.Write([]byte(opts.Region)) + kRegion := h.Sum(nil) + h = hmac.New(sha256.New, kRegion) + h.Write([]byte("tos")) + kService := h.Sum(nil) + h = hmac.New(sha256.New, kService) + h.Write([]byte("request")) + kSigning := h.Sum(nil) + + h = hmac.New(sha256.New, kSigning) + h.Write([]byte(stringToSign)) + signature := strings.ToLower(hex.EncodeToString(h.Sum(nil))) + + req.Header.Set("Authorization", fmt.Sprintf("%s Credential=%s/%s, SignedHeaders=%s, Signature=%s", signAlgorithmHeader, opts.AccessKeyId, credentialScope, signedHeaders, signature)) + req.Header.Set("Date", headerDateStr) + + return nil + }) + + return &Client{rc: restyClient}, nil +} + +func (c *Client) SetTimeout(timeout time.Duration) *Client { + c.rc.SetTimeout(timeout) + return c +} + +func (c *Client) newRequest(method string, path string, params any) (*resty.Request, error) { + if method == "" { + return nil, fmt.Errorf("sdkerr: unset method") + } + if path == "" { + return nil, fmt.Errorf("sdkerr: unset path") + } + + requestUrl, err := url.Parse(path) + if err != nil { + return nil, fmt.Errorf("sdkerr: invalid path: %w", err) + } else if requestUrl.IsAbs() { + return nil, fmt.Errorf("sdkerr: path should be relative") + } + + payloadStr := "" + contentType := "" + if params != nil { + // 目前仅支持 JSON 请求体,仅适用于非 S3 兼容接口 + payloadb, err := json.Marshal(params) + if err != nil { + return nil, err + } + + payloadStr = string(payloadb) + contentType = "application/json" + } + payloadMd5 := md5.Sum([]byte(payloadStr)) + payloadMd5Encoded := base64.StdEncoding.EncodeToString(payloadMd5[:]) + + req := c.rc.R() + req.Method = method + req.URL = requestUrl.Path + req.QueryParam = requestUrl.Query() + req.SetBody(payloadStr) + req.SetHeader("Content-MD5", payloadMd5Encoded) + req.SetHeader("Content-Type", contentType) + return req, nil +} + +func (c *Client) doRequest(req *resty.Request) (*resty.Response, error) { + if req == nil { + return nil, fmt.Errorf("sdkerr: nil request") + } + + // WARN: + // PLEASE DO NOT USE `req.SetBody` HERE! USE `newRequest` INSTEAD. + // PLEASE DO NOT USE `req.SetResult` or `req.SetError` HERE! USE `doRequestWithResult` INSTEAD. + + resp, err := req.Send() + if err != nil { + return resp, fmt.Errorf("sdkerr: failed to send request: %w", err) + } else if resp.IsError() { + return resp, fmt.Errorf("sdkerr: unexpected status code: %d (resp: %s)", resp.StatusCode(), resp.String()) + } + + return resp, nil +} + +func (c *Client) doRequestWithResult(req *resty.Request, res sdkResponse) (*resty.Response, error) { + if req == nil { + return nil, fmt.Errorf("sdkerr: nil request") + } + + resp, err := c.doRequest(req) + if err != nil { + if resp != nil { + json.Unmarshal(resp.Body(), &res) + } + return resp, err + } + + if len(resp.Body()) != 0 { + if err := json.Unmarshal(resp.Body(), &res); err != nil { + return resp, fmt.Errorf("sdkerr: failed to unmarshal response: %w (resp: %s)", err, resp.String()) + } + } + + return resp, nil +} diff --git a/pkg/sdk3rd/volcengine/tos/options.go b/pkg/sdk3rd/volcengine/tos/options.go new file mode 100644 index 000000000..cb78a312a --- /dev/null +++ b/pkg/sdk3rd/volcengine/tos/options.go @@ -0,0 +1,29 @@ +package tos + +type Options struct { + AccessKeyId string + SecretAccessKey string + Region string + Bucket string +} + +type OptionsFunc func(*Options) + +func WithAkSk(ak, sk string) OptionsFunc { + return func(o *Options) { + o.AccessKeyId = ak + o.SecretAccessKey = sk + } +} + +func WithRegion(region string) OptionsFunc { + return func(o *Options) { + o.Region = region + } +} + +func WithBucket(bucket string) OptionsFunc { + return func(o *Options) { + o.Bucket = bucket + } +} diff --git a/pkg/sdk3rd/volcengine/tos/types.go b/pkg/sdk3rd/volcengine/tos/types.go new file mode 100644 index 000000000..27e63e2c5 --- /dev/null +++ b/pkg/sdk3rd/volcengine/tos/types.go @@ -0,0 +1,7 @@ +package tos + +type sdkResponse interface{} + +type sdkResponseBase struct{} + +var _ sdkResponse = (*sdkResponseBase)(nil) diff --git a/pkg/sdk3rd/wangsu/openapi/client.go b/pkg/sdk3rd/wangsu/openapi/client.go index c68fca15f..3fa8ae4e1 100644 --- a/pkg/sdk3rd/wangsu/openapi/client.go +++ b/pkg/sdk3rd/wangsu/openapi/client.go @@ -40,7 +40,6 @@ func NewClient(optFns ...OptionsFunc) (*Client, error) { SetBaseURL("https://open.chinanetcenter.com"). SetHeader("Accept", "application/json"). SetHeader("Content-Type", "application/json"). - SetHeader("Host", "open.chinanetcenter.com"). SetHeader("User-Agent", app.AppUserAgent). SetPreRequestHook(func(c *resty.Client, req *http.Request) error { // API 签名机制: @@ -67,7 +66,7 @@ func NewClient(optFns ...OptionsFunc) (*Client, error) { canonicalHeaders := "" + "content-type:" + strings.TrimSpace(strings.ToLower(req.Header.Get("Content-Type"))) + "\n" + - "host:" + strings.TrimSpace(strings.ToLower(req.Header.Get("Host"))) + "\n" + "host:" + strings.TrimSpace(strings.ToLower(req.Host)) + "\n" signedHeaders := "content-type;host" payloadStr := "" @@ -106,11 +105,11 @@ func NewClient(optFns ...OptionsFunc) (*Client, error) { h.Write([]byte(stringToSign)) signature := strings.ToLower(hex.EncodeToString(h.Sum(nil))) - req.Header.Set("X-CNC-AccessKey", options.AccessKey) - req.Header.Set("X-CNC-Timestamp", timestampStr) - req.Header.Set("X-CNC-Auth-Method", "AKSK") req.Header.Set("Authorization", fmt.Sprintf("%s Credential=%s, SignedHeaders=%s, Signature=%s", signAlgorithmHeader, options.AccessKey, signedHeaders, signature)) req.Header.Set("Date", nowUtc.Format(http.TimeFormat)) + req.Header.Set("X-CNC-Auth-Method", "AKSK") + req.Header.Set("X-CNC-AccessKey", options.AccessKey) + req.Header.Set("X-CNC-Timestamp", timestampStr) return nil })