caller.go raw
1 package dns
2
3 import (
4 "bytes"
5 "context"
6 "encoding/json"
7 "fmt"
8 "io/ioutil"
9 "net/http"
10 "os"
11 "strconv"
12
13 "github.com/pkg/errors"
14 "github.com/volcengine/volc-sdk-golang/base"
15 )
16
17 func NewDefaultServiceInfo() *base.Client {
18 return base.NewClient(ServiceInfo, nil)
19 }
20
21 type VolcCaller struct {
22 Volc *base.Client
23 }
24
25 func NewVolcCaller() *VolcCaller {
26 instance := &VolcCaller{Volc: NewDefaultServiceInfo()}
27 instance.Volc.SetAccessKey(os.Getenv("VOLC_ACCESSKEY"))
28 instance.Volc.SetSecretKey(os.Getenv("VOLC_SECRETKEY"))
29 instance.Volc.SetHost(instance.Volc.ServiceInfo.Host)
30 instance.Volc.SetScheme(instance.Volc.ServiceInfo.Scheme)
31 instance.Volc.SetTimeout(instance.Volc.ServiceInfo.Timeout)
32
33 return instance
34 }
35
36 func (c *VolcCaller) Do(r *http.Request) (*http.Response, error) {
37 r.URL.Host = c.Volc.ServiceInfo.Host
38 r.URL.Scheme = c.Volc.ServiceInfo.Scheme
39 r.Host = c.Volc.ServiceInfo.Host
40
41 r.Header.Add("Content-Type", "application/json")
42 q := r.URL.Query()
43 q.Add("Version", ServiceVersion)
44 q.Add("X-Account-Id", xTopAccountID)
45 r.URL.RawQuery = q.Encode()
46
47 r = c.Volc.ServiceInfo.Credentials.Sign(r)
48
49 ctx, cancel := context.WithTimeout(r.Context(), c.Volc.ServiceInfo.Timeout)
50 defer cancel()
51 r = r.WithContext(ctx)
52
53 resp, err := c.Volc.Client.Do(r)
54 if err != nil {
55 return resp, errors.WithStack(err)
56 }
57
58 var payload TopResponse
59 err = json.NewDecoder(resp.Body).Decode(&payload)
60 resp.Body.Close()
61
62 newResp := &http.Response{}
63
64 if err != nil {
65 return newResp, errors.WithStack(err)
66 }
67
68 if payload.ResponseMetadata.Error.Code != "" {
69 return newResp, NewTOPError(&payload.ResponseMetadata)
70 }
71
72 if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
73 return newResp, errors.Wrap(errors.New("http error"), strconv.Itoa(resp.StatusCode))
74 }
75
76 str, err := json.Marshal(payload.Result)
77 if err != nil {
78 return newResp, errors.WithStack(err)
79 }
80
81 newResp = &http.Response{Body: ioutil.NopCloser(bytes.NewBuffer(str))}
82
83 return newResp, errors.WithStack(err)
84 }
85
86 type TOPError struct {
87 Code string `form:"Code" json:"Code"`
88 CodeN int64 `form:"CodeN" json:"CodeN"`
89 Message string `form:"Message" json:"Message"`
90 RequestID string `form:"RequestId" json:"RequestId"`
91 }
92
93 func NewTOPError(respMeta *TopRespMeta) *TOPError {
94 return &TOPError{
95 Code: respMeta.Error.Code,
96 CodeN: respMeta.Error.CodeN,
97 Message: respMeta.Error.Message,
98 RequestID: respMeta.RequestID,
99 }
100 }
101
102 func (err *TOPError) GetCode() int64 {
103 return err.CodeN
104 }
105
106 func (err *TOPError) Error() string {
107 return fmt.Sprintf(
108 "TOP DNS response failed with code %d: %s, %s, requestID: %s",
109 err.CodeN, err.Code, err.Message, err.RequestID,
110 )
111 }
112
113 type TopResponse struct {
114 ResponseMetadata TopRespMeta `form:"ResponseMetadata" json:"ResponseMetadata"`
115 Result json.RawMessage `form:"Result" json:"Result"`
116 }
117
118 type TopRespMeta struct {
119 Action string `form:"Action" json:"Action"`
120 Error TopRespError `form:"Error" json:"Error"`
121 Region string `form:"Region" json:"Region"`
122 RequestID string `form:"RequestId" json:"RequestId"`
123 Service string `form:"Service" json:"Service"`
124 Version string `form:"Version" json:"Version"`
125 }
126
127 type TopRespError struct {
128 Code string `form:"Code" json:"Code"`
129 CodeN int64 `form:"CodeN" json:"CodeN"`
130 Message string `form:"Message" json:"Message"`
131 }
132