client.go raw

   1  package internal
   2  
   3  import (
   4  	"context"
   5  	"encoding/json"
   6  	"errors"
   7  	"io"
   8  	"net/http"
   9  	"net/url"
  10  	"time"
  11  
  12  	"github.com/go-acme/lego/v4/providers/dns/internal/errutils"
  13  	querystring "github.com/google/go-querystring/query"
  14  )
  15  
  16  const statusSuccess = "success"
  17  
  18  const defaultBaseURL = "https://my.axelname.ru/rest/"
  19  
  20  // Client the Axelname API client.
  21  type Client struct {
  22  	nickname string
  23  	token    string
  24  
  25  	baseURL    *url.URL
  26  	HTTPClient *http.Client
  27  }
  28  
  29  // NewClient creates a new Client.
  30  func NewClient(nickname, token string) (*Client, error) {
  31  	if token == "" || nickname == "" {
  32  		return nil, errors.New("credentials missing")
  33  	}
  34  
  35  	baseURL, _ := url.Parse(defaultBaseURL)
  36  
  37  	return &Client{
  38  		nickname:   nickname,
  39  		token:      token,
  40  		baseURL:    baseURL,
  41  		HTTPClient: &http.Client{Timeout: 10 * time.Second},
  42  	}, nil
  43  }
  44  
  45  func (c *Client) ListRecords(ctx context.Context, domain string) ([]Record, error) {
  46  	endpoint := c.baseURL.JoinPath("dns_list")
  47  
  48  	query := endpoint.Query()
  49  	query.Set("domain", domain)
  50  
  51  	endpoint.RawQuery = query.Encode()
  52  
  53  	req, err := c.newRequest(ctx, endpoint)
  54  	if err != nil {
  55  		return nil, err
  56  	}
  57  
  58  	var results ListResponse
  59  
  60  	err = c.do(req, &results)
  61  	if err != nil {
  62  		return nil, err
  63  	}
  64  
  65  	if results.Result != statusSuccess {
  66  		return nil, &results.APIError
  67  	}
  68  
  69  	return results.List, nil
  70  }
  71  
  72  func (c *Client) DeleteRecord(ctx context.Context, domain string, record Record) error {
  73  	endpoint := c.baseURL.JoinPath("dns_delete")
  74  
  75  	values, err := querystring.Values(record)
  76  	if err != nil {
  77  		return err
  78  	}
  79  
  80  	values.Set("domain", domain)
  81  
  82  	endpoint.RawQuery = values.Encode()
  83  
  84  	req, err := c.newRequest(ctx, endpoint)
  85  	if err != nil {
  86  		return err
  87  	}
  88  
  89  	var results APIResponse
  90  
  91  	err = c.do(req, &results)
  92  	if err != nil {
  93  		return err
  94  	}
  95  
  96  	if results.Result != statusSuccess {
  97  		return &results.APIError
  98  	}
  99  
 100  	return nil
 101  }
 102  
 103  func (c *Client) AddRecord(ctx context.Context, domain string, record Record) error {
 104  	endpoint := c.baseURL.JoinPath("dns_add")
 105  
 106  	values, err := querystring.Values(record)
 107  	if err != nil {
 108  		return err
 109  	}
 110  
 111  	values.Set("domain", domain)
 112  
 113  	endpoint.RawQuery = values.Encode()
 114  
 115  	req, err := c.newRequest(ctx, endpoint)
 116  	if err != nil {
 117  		return err
 118  	}
 119  
 120  	var results APIResponse
 121  
 122  	err = c.do(req, &results)
 123  	if err != nil {
 124  		return err
 125  	}
 126  
 127  	if results.Result != statusSuccess {
 128  		return &results.APIError
 129  	}
 130  
 131  	return nil
 132  }
 133  
 134  func (c *Client) newRequest(ctx context.Context, endpoint *url.URL) (*http.Request, error) {
 135  	query := endpoint.Query()
 136  	query.Set("token", c.token)
 137  	query.Set("nichdl", c.nickname)
 138  
 139  	endpoint.RawQuery = query.Encode()
 140  
 141  	return http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
 142  }
 143  
 144  func (c *Client) do(req *http.Request, result any) error {
 145  	resp, err := c.HTTPClient.Do(req)
 146  	if err != nil {
 147  		return errutils.NewHTTPDoError(req, err)
 148  	}
 149  
 150  	defer func() { _ = resp.Body.Close() }()
 151  
 152  	if resp.StatusCode/100 != 2 {
 153  		return parseError(req, resp)
 154  	}
 155  
 156  	if result == nil {
 157  		return nil
 158  	}
 159  
 160  	raw, err := io.ReadAll(resp.Body)
 161  	if err != nil {
 162  		return errutils.NewReadResponseError(req, resp.StatusCode, err)
 163  	}
 164  
 165  	err = json.Unmarshal(raw, result)
 166  	if err != nil {
 167  		return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
 168  	}
 169  
 170  	return nil
 171  }
 172  
 173  func parseError(req *http.Request, resp *http.Response) error {
 174  	raw, _ := io.ReadAll(resp.Body)
 175  
 176  	var errAPI APIError
 177  
 178  	err := json.Unmarshal(raw, &errAPI)
 179  	if err != nil {
 180  		return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
 181  	}
 182  
 183  	return &errAPI
 184  }
 185