154 lines
4.1 KiB
Go
154 lines
4.1 KiB
Go
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
|
|
}
|
|
|
|
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
|
|
}
|