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