This repository has been archived by the owner on Feb 7, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
client.go
executable file
·135 lines (113 loc) · 3.5 KB
/
client.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package dana
import (
"encoding/json"
"github.com/tidwall/gjson"
"io"
"io/ioutil"
"moul.io/http2curl"
"net/http"
"strings"
"time"
)
// Client struct
type Client struct {
BaseUrl string
Version string
ClientId string
ClientSecret string
PrivateKey []byte
PublicKey []byte
LogLevel int
Logger Logger
SignatureEnabled bool
}
// NewClient : this function will always be called when the library is in use
func NewClient() Client {
logOption := LogOption{
Format: "text",
Level: "info",
TimestampFormat: "2006-01-02T15:04:05-0700",
CallerToggle: false,
}
logger := *NewLogger(logOption)
return Client{
// LogLevel is the logging level used by the Dana library
// 0: No logging
// 1: Errors only
// 2: Errors + informational (default)
// 3: Errors + informational + debug
LogLevel: 2,
Logger: logger,
SignatureEnabled: true,
}
}
// ===================== HTTP CLIENT ================================================
var defHTTPTimeout = 15 * time.Second
var httpClient = &http.Client{Timeout: defHTTPTimeout}
// NewRequest : send new request
func (c *Client) NewRequest(method string, fullPath string, headers map[string]string, body io.Reader) (*http.Request, error) {
req, err := http.NewRequest(method, fullPath, body)
if err != nil {
c.Logger.Info("Request creation failed: %v ", err)
return nil, err
}
if headers != nil {
for k, vv := range headers {
req.Header.Set(k, vv)
}
}
return req, nil
}
// ExecuteRequest : execute request
func (c *Client) ExecuteRequest(req *http.Request, v interface{}) error {
c.Logger.Info("Start requesting: %v ", req.URL)
command, _ := http2curl.GetCurlCommand(req)
start := time.Now()
res, err := httpClient.Do(req)
if err != nil {
c.Logger.Error("Request failed. Error : %v , Curl Request : %v", err, command)
return err
}
defer res.Body.Close()
c.Logger.Info("Completed in %v", time.Since(start))
c.Logger.Info("Curl Request: %v ", command)
resBody, err := ioutil.ReadAll(res.Body)
if err != nil {
c.Logger.Error("Cannot read response body: %v ", err)
return err
}
c.Logger.Info("DANA HTTP status response : %d", res.StatusCode)
c.Logger.Info("DANA response body : %s", string(resBody))
if v != nil && res.StatusCode == 200 {
if err = json.Unmarshal(resBody, v); err != nil {
c.Logger.Error("Failed unmarshal body: %v ", err)
return err
}
// Dana endpoint V1 doesn't return signature in response, so we don't need to verify signature again
if strings.Contains(req.URL.String(), "/v1/") {
c.Logger.Info("Req URL Contains Dana endpoint V1")
return nil
}
if c.SignatureEnabled {
response := gjson.Get(string(resBody), "response")
signature := gjson.Get(string(resBody), "signature")
err = verifySignature(response.String(), signature.String(), c.PublicKey)
if err != nil {
c.Logger.Error("verifySignature failed: %v ", err)
return err
}
}
}
return nil
}
// Call the Dana API at specific `path` using the specified HTTP `method`. The result will be
// given to `v` if there is no error. If any error occurred, the return of this function is the error
// itself, otherwise nil.
func (c *Client) Call(method, path string, header map[string]string, body io.Reader, v interface{}) error {
req, err := c.NewRequest(method, path, header, body)
if err != nil {
return err
}
return c.ExecuteRequest(req, v)
}
// ===================== END HTTP CLIENT ================================================