Files
WddSuperAgent/agent-wdd/cloudflare/CloudflareAPI.go

166 lines
4.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package cloudflare
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"sync"
"time"
"agent-wdd/log"
)
const (
// CloudflareAPIBaseURL is the base URL for Cloudflare API
CloudflareAPIBaseURL = "https://api.cloudflare.com/client/v4"
// DefaultTimeout is the default timeout for HTTP requests
DefaultTimeout = 5 * time.Second
)
// CloudflareClient represents a client for interacting with Cloudflare API
type CloudflareClient struct {
apiToken string
baseURL string
client *http.Client
userAgent string
dnsNameToIDMap map[string]string // 域名到ID的映射
}
var (
instance *CloudflareClient
once sync.Once
)
// Response is the general response structure from Cloudflare API
type Response struct {
Result interface{} `json:"result"`
ResultInfo *ResultInfo `json:"result_info,omitempty"`
Success bool `json:"success"`
Errors []Error `json:"errors"`
Messages []interface{} `json:"messages"`
}
// ResultInfo contains pagination information
type ResultInfo struct {
Page int `json:"page"`
PerPage int `json:"per_page"`
TotalPages int `json:"total_pages"`
Count int `json:"count"`
TotalCount int `json:"total_count"`
}
// Error represents an error returned by the Cloudflare API
type Error struct {
Code int `json:"code"`
Message string `json:"message"`
ErrorChain []Error `json:"error_chain,omitempty"`
}
// NewClient creates a new instance of CloudflareClient with the given API token
func NewClient(apiToken string) *CloudflareClient {
log.Debug("Creating new Cloudflare client")
return &CloudflareClient{
apiToken: apiToken,
baseURL: CloudflareAPIBaseURL,
client: &http.Client{Timeout: DefaultTimeout},
userAgent: "WddSuperAgent/1.0",
}
}
// GetInstance returns the singleton instance of CloudflareClient
func GetInstance(apiToken string) *CloudflareClient {
if instance == nil {
once.Do(func() {
instance = NewClient(apiToken)
log.Info("Cloudflare client singleton instance created")
})
}
return instance
}
// SetAPIToken updates the API token used for authentication
func (c *CloudflareClient) SetAPIToken(apiToken string) {
c.apiToken = apiToken
log.Info("Cloudflare API token updated")
}
// SetTimeout updates the HTTP client timeout
func (c *CloudflareClient) SetTimeout(timeout time.Duration) {
c.client.Timeout = timeout
log.Info("Cloudflare client timeout updated to %v", timeout)
}
// doRequest performs an HTTP request with the given method, URL, and body
func (c *CloudflareClient) doRequest(method, url string, body interface{}) (*Response, error) {
log.Debug("Performing %s request to %s", method, url)
var reqBody io.Reader
if body != nil {
jsonBody, err := json.Marshal(body)
if err != nil {
log.Error("Failed to marshal request body: %v", err)
return nil, fmt.Errorf("failed to marshal request body: %w", err)
}
reqBody = bytes.NewBuffer(jsonBody)
}
req, err := http.NewRequest(method, url, reqBody)
if err != nil {
log.Error("Failed to create HTTP request: %v", err)
return nil, fmt.Errorf("failed to create HTTP request: %w", err)
}
// Set headers
req.Header.Set("Authorization", "Bearer "+c.apiToken)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", c.userAgent)
// Perform request
resp, err := c.client.Do(req)
if err != nil {
log.Error("Failed to execute HTTP request: %v", err)
return nil, fmt.Errorf("failed to execute HTTP request: %w", err)
}
defer resp.Body.Close()
// Read response body
respBody, err := io.ReadAll(resp.Body)
if err != nil {
log.Error("Failed to read response body: %v", err)
return nil, fmt.Errorf("failed to read response body: %w", err)
}
// Parse response
var cfResp Response
if err := json.Unmarshal(respBody, &cfResp); err != nil {
log.Error("Failed to unmarshal response: %v", err)
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
// Check for API errors
if !cfResp.Success {
errorMsg := "Cloudflare API error"
if len(cfResp.Errors) > 0 {
errorMsg = fmt.Sprintf("%s: %s (code: %d)", errorMsg, cfResp.Errors[0].Message, cfResp.Errors[0].Code)
}
log.Error(errorMsg)
return &cfResp, fmt.Errorf(errorMsg)
}
log.Debug("Request completed successfully")
return &cfResp, nil
}
// GetDNSNameToIDMap 获取域名到ID的映射
func (c *CloudflareClient) GetDNSNameToIDMap(zoneID string) map[string]string {
// 如果dnsNameToIDMap为空则获取所有域名到ID的映射
if c.dnsNameToIDMap == nil {
c.ListDNSRecords(zoneID, nil)
}
return c.dnsNameToIDMap
}