refactor: re-implement cloudflare services with custom sdk, to lightweight package size

This commit is contained in:
Fu Diwei
2026-06-10 23:13:21 +08:00
parent 5a68915cf0
commit 12cb2bbced
9 changed files with 326 additions and 38 deletions
@@ -6,12 +6,10 @@ import (
"fmt"
"log/slog"
cf "github.com/cloudflare/cloudflare-go/v7"
cfcertificates "github.com/cloudflare/cloudflare-go/v7/custom_certificates"
cfhostnames "github.com/cloudflare/cloudflare-go/v7/custom_hostnames"
cfoption "github.com/cloudflare/cloudflare-go/v7/option"
"github.com/samber/lo"
"github.com/certimate-go/certimate/pkg/core"
cloudflaresdk "github.com/certimate-go/certimate/pkg/sdk3rd/cloudflare"
)
type (
@@ -36,7 +34,7 @@ type DeployerConfig struct {
type Deployer struct {
config *DeployerConfig
logger *slog.Logger
sdkClient *cfcertificates.CustomCertificateService
sdkClient *cloudflaresdk.Client
}
var _ Provider = (*Deployer)(nil)
@@ -74,29 +72,30 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep
if d.config.CertificateId == "" {
// 新建自定义证书
// REF: https://developers.cf.com/api/resources/custom_certificates/methods/create
customCertificateNewReq := cfcertificates.CustomCertificateNewParams{
ZoneID: cf.F(d.config.ZoneId),
Certificate: cf.F(certPEM),
PrivateKey: cf.F(privkeyPEM),
BundleMethod: cf.F(cfhostnames.BundleMethodUbiquitous),
Deploy: cf.F(cfcertificates.CustomCertificateNewParamsDeploy(cmp.Or(d.config.Environment, "production"))),
customCertificateCreateReq := &cloudflaresdk.CustomCertificateCreateRequest{
ZoneId: d.config.ZoneId,
Certificate: lo.ToPtr(certPEM),
PrivateKey: lo.ToPtr(privkeyPEM),
BundleMethod: lo.ToPtr("ubiquitous"),
Deploy: lo.ToPtr(cmp.Or(d.config.Environment, "production")),
}
customCertificateNewResp, err := d.sdkClient.New(ctx, customCertificateNewReq)
d.logger.Debug("sdk request 'CustomCertificates.New'", slog.Any("request", customCertificateNewReq), slog.Any("response", customCertificateNewResp))
customCertificateCreateResp, err := d.sdkClient.CustomCertificateCreateWithContext(ctx, customCertificateCreateReq)
d.logger.Debug("sdk request 'CustomCertificates.Create'", slog.Any("request", customCertificateCreateReq), slog.Any("response", customCertificateCreateResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'CustomCertificates.New': %w", err)
return nil, fmt.Errorf("failed to execute sdk request 'CustomCertificates.Create': %w", err)
}
} else {
// 编辑自定义证书
// REF: https://developers.cloudflare.com/api/resources/custom_certificates/methods/edit
customCertificateEditReq := cfcertificates.CustomCertificateEditParams{
ZoneID: cf.F(d.config.ZoneId),
Certificate: cf.F(certPEM),
PrivateKey: cf.F(privkeyPEM),
BundleMethod: cf.F(cfhostnames.BundleMethodUbiquitous),
Deploy: cf.F(cfcertificates.CustomCertificateEditParamsDeploy(cmp.Or(d.config.Environment, "production"))),
customCertificateEditReq := &cloudflaresdk.CustomCertificateEditRequest{
ZoneId: d.config.ZoneId,
CertificateId: d.config.CertificateId,
Certificate: lo.ToPtr(certPEM),
PrivateKey: lo.ToPtr(privkeyPEM),
BundleMethod: lo.ToPtr("ubiquitous"),
Deploy: lo.ToPtr(cmp.Or(d.config.Environment, "production")),
}
customCertificateEditResp, err := d.sdkClient.Edit(ctx, d.config.CertificateId, customCertificateEditReq)
customCertificateEditResp, err := d.sdkClient.CustomCertificateEditWithContext(ctx, customCertificateEditReq)
d.logger.Debug("sdk request 'CustomCertificates.Edit'", slog.Any("request", customCertificateEditReq), slog.Any("response", customCertificateEditResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'CustomCertificates.Edit': %w", err)
@@ -106,14 +105,13 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep
return &DeployResult{}, nil
}
func createSDKClient(apiToken string) (*cfcertificates.CustomCertificateService, error) {
if apiToken == "" {
return nil, fmt.Errorf("cloudflare: invalid api token")
func createSDKClient(apiToken string) (*cloudflaresdk.Client, error) {
client, err := cloudflaresdk.NewClient(
cloudflaresdk.WithApiToken(apiToken),
)
if err != nil {
return nil, err
}
opts := append(cf.DefaultClientOptions(), cfoption.WithAPIToken(apiToken))
srv := cfcertificates.NewCustomCertificateService(opts...)
return srv, nil
return client, err
}
@@ -2,11 +2,11 @@ package vod
import (
"encoding/json"
"errors"
"net/http"
"net/url"
"strconv"
"github.com/pkg/errors"
"github.com/volcengine/volc-sdk-golang/service/vod/models/request"
"github.com/volcengine/volc-sdk-golang/service/vod/models/response"
"google.golang.org/protobuf/encoding/protojson"
@@ -0,0 +1,48 @@
package cloudflare
import (
"context"
"fmt"
"net/http"
"net/url"
)
type CustomCertificateCreateRequest struct {
ZoneId string `json:"-"`
CustomCsrId *string `json:"custom_csr_id,omitempty"`
Certificate *string `json:"certificate,omitempty"`
PrivateKey *string `json:"private_key,omitempty"`
BundleMethod *string `json:"bundle_method,omitempty"`
Type *string `json:"type,omitempty"`
Deploy *string `json:"deploy,omitempty"`
Policy *string `json:"policy,omitempty"`
GeoRestrictions []*GeoRestriction `json:"geo_restrictions,omitempty"`
}
type CustomCertificateCreateResponse struct {
sdkResponseBase
Result *CustomCertificate `json:"result,omitempty"`
}
func (c *Client) CustomCertificateCreate(req *CustomCertificateCreateRequest) (*CustomCertificateCreateResponse, error) {
return c.CustomCertificateCreateWithContext(context.Background(), req)
}
func (c *Client) CustomCertificateCreateWithContext(ctx context.Context, req *CustomCertificateCreateRequest) (*CustomCertificateCreateResponse, error) {
path := fmt.Sprintf("/zones/%s/custom_certificates", url.PathEscape(req.ZoneId))
httpreq, err := c.newRequest(http.MethodPost, path)
if err != nil {
return nil, err
} else {
httpreq.SetBody(req)
httpreq.SetContext(ctx)
}
result := &CustomCertificateCreateResponse{}
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
return result, err
}
return result, nil
}
@@ -0,0 +1,48 @@
package cloudflare
import (
"context"
"fmt"
"net/http"
"net/url"
)
type CustomCertificateEditRequest struct {
ZoneId string `json:"-"`
CertificateId string `json:"-"`
CustomCsrId *string `json:"custom_csr_id,omitempty"`
Certificate *string `json:"certificate,omitempty"`
PrivateKey *string `json:"private_key,omitempty"`
BundleMethod *string `json:"bundle_method,omitempty"`
Deploy *string `json:"deploy,omitempty"`
Policy *string `json:"policy,omitempty"`
GeoRestrictions []*GeoRestriction `json:"geo_restrictions,omitempty"`
}
type CustomCertificateEditResponse struct {
sdkResponseBase
Result *CustomCertificate `json:"result,omitempty"`
}
func (c *Client) CustomCertificateEdit(req *CustomCertificateEditRequest) (*CustomCertificateEditResponse, error) {
return c.CustomCertificateEditWithContext(context.Background(), req)
}
func (c *Client) CustomCertificateEditWithContext(ctx context.Context, req *CustomCertificateEditRequest) (*CustomCertificateEditResponse, error) {
path := fmt.Sprintf("/zones/%s/custom_certificates/%s", url.PathEscape(req.ZoneId), url.PathEscape(req.CertificateId))
httpreq, err := c.newRequest(http.MethodPatch, path)
if err != nil {
return nil, err
} else {
httpreq.SetBody(req)
httpreq.SetContext(ctx)
}
result := &CustomCertificateEditResponse{}
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
return result, err
}
return result, nil
}
+104
View File
@@ -0,0 +1,104 @@
package cloudflare
import (
"crypto/tls"
"encoding/json"
"fmt"
"time"
"github.com/go-resty/resty/v2"
"github.com/certimate-go/certimate/internal/app"
)
type Client struct {
rc *resty.Client
}
func NewClient(optFns ...OptionsFunc) (*Client, error) {
opts := &Options{}
for _, fn := range optFns {
fn(opts)
}
if opts.ApiToken == "" {
return nil, fmt.Errorf("sdkerr: unset apiToken")
}
restyClient := resty.New().
SetBaseURL("https://api.cloudflare.com/client/v4").
SetHeader("Accept", "application/json").
SetHeader("Authorization", "Bearer "+opts.ApiToken).
SetHeader("Content-Type", "application/json").
SetHeader("User-Agent", app.AppUserAgent)
return &Client{rc: restyClient}, nil
}
func (c *Client) SetTimeout(timeout time.Duration) *Client {
c.rc.SetTimeout(timeout)
return c
}
func (c *Client) SetTLSConfig(config *tls.Config) *Client {
c.rc.SetTLSClientConfig(config)
return c
}
func (c *Client) newRequest(method string, path string) (*resty.Request, error) {
if method == "" {
return nil, fmt.Errorf("sdkerr: unset method")
}
if path == "" {
return nil, fmt.Errorf("sdkerr: unset path")
}
req := c.rc.R()
req.Method = method
req.URL = path
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.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())
} else {
if rErrors := res.GetErrors(); rErrors != nil {
return resp, fmt.Errorf("sdkerr: errors='%s'", rErrors.Error())
}
}
}
return resp, nil
}
+13
View File
@@ -0,0 +1,13 @@
package cloudflare
type Options struct {
ApiToken string
}
type OptionsFunc func(*Options)
func WithApiToken(apiToken string) OptionsFunc {
return func(o *Options) {
o.ApiToken = apiToken
}
}
+84
View File
@@ -0,0 +1,84 @@
package cloudflare
import (
"fmt"
"strings"
)
type sdkResponse interface {
GetErrors() error
GetSuccess() bool
}
type sdkResponseBase struct {
Errors APIErrors `json:"errors,omitempty"`
Messages []APIMessage `json:"messages,omitempty"`
Success bool `json:"success,omitempty"`
}
type APIMessage struct {
Code int `json:"code"`
Message string `json:"message"`
DocumentationURL string `json:"documentation_url"`
ErrorChain []APIErrorChain `json:"error_chain"`
Source *APISource `json:"source"`
}
type APIErrors []APIMessage
type APIErrorChain struct {
Code int `json:"code"`
Message string `json:"message"`
}
type APISource struct {
Pointer string `json:"pointer"`
}
func (e APIErrors) Error() string {
builder := &strings.Builder{}
for _, item := range e {
fmt.Fprintf(builder, "%d: %s", item.Code, item.Message)
for _, link := range item.ErrorChain {
fmt.Fprintf(builder, "; %d: %s", link.Code, link.Message)
}
}
return builder.String()
}
func (r *sdkResponseBase) GetErrors() error {
if len(r.Errors) > 0 {
return r.Errors
}
return nil
}
func (r *sdkResponseBase) GetSuccess() bool {
return r.Success
}
var _ sdkResponse = (*sdkResponseBase)(nil)
type GeoRestriction struct {
Label string `json:"label"`
}
type CustomCertificate struct {
ID string `json:"id"`
ZoneID string `json:"zone_id"`
BundleMethod string `json:"bundle_method"`
CustomCsrID string `json:"custom_csr_id"`
GeoRestrictions []GeoRestriction `json:"geo_restrictions"`
Hosts []string `json:"hosts"`
Issuer string `json:"issuer"`
PolicyRestrictions string `json:"policy_restrictions"`
Priority float64 `json:"priority"`
Signature string `json:"signature"`
Status string `json:"status"`
ExpiresOn string `json:"expires_on"`
UploadedOn string `json:"uploaded_on"`
ModifiedOn string `json:"modified_on"`
}