This repository has been archived by the owner on Sep 6, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 12
/
client.go
230 lines (199 loc) · 6.55 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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
package tat
import (
"bytes"
"crypto/tls"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
"time"
"github.com/facebookgo/httpcontrol"
)
// Client represents a Client configuration to connect to api
type Client struct {
username string
password string
basicAuthUsername string
basicAuthPassword string
url string
referer string
requestTimeout time.Duration
maxTries uint
sslInsecureSkipVerify bool
}
//Options is a struct to initialize a TAT client
type Options struct {
Username string
Password string
BasicAuthUsername string
BasicAuthPassword string
URL string
Referer string
RequestTimeout time.Duration
MaxTries uint
SSLInsecureSkipVerify bool
}
type httpClient interface {
Do(req *http.Request) (*http.Response, error)
}
// HTTPClient is HTTClient or testHTTPClient for tests
var HTTPClient httpClient
// DebugLogFunc is a function that logs the provided message with optional fmt.Sprintf-style arguments. By default, logs to the default log.Logger.
var DebugLogFunc = log.Printf //func(string, ...interface{})
// ErrorLogFunc is a function that logs the provided message with optional fmt.Sprintf-style arguments. By default, logs to the default log.Logger.
var ErrorLogFunc = log.Printf
// IsDebug display request / response in ErrorLogFunc if true
var IsDebug = false
//ErrClientNotInitiliazed is a predifined Error
var ErrClientNotInitiliazed = fmt.Errorf("Client is not initialized")
//NewClient initialize a TAT client
func NewClient(opts Options) (*Client, error) {
if opts.URL == "" {
return nil, fmt.Errorf("Invalid configuration, please check url of Tat Engine")
}
c := &Client{
url: opts.URL,
username: opts.Username,
password: opts.Password,
referer: "TAT-SDK-" + Version,
requestTimeout: time.Minute,
maxTries: 5,
sslInsecureSkipVerify: opts.SSLInsecureSkipVerify,
}
if opts.Referer != "" {
c.referer = opts.Referer
}
if opts.RequestTimeout != time.Duration(0) {
c.requestTimeout = opts.RequestTimeout
}
if opts.MaxTries != 0 {
c.maxTries = opts.MaxTries
}
// Set basic auth credentials only if the username AND the password options have been provided
if opts.BasicAuthUsername != "" && opts.BasicAuthPassword != "" {
c.basicAuthUsername = opts.BasicAuthUsername
c.basicAuthPassword = opts.BasicAuthPassword
}
return c, nil
}
func (c *Client) initHeaders(req *http.Request) error {
if c == nil {
return ErrClientNotInitiliazed
}
// If the client is configured with basic auth credentials, add them to the request
if c.basicAuthUsername != "" && c.basicAuthPassword != "" {
req.SetBasicAuth(c.basicAuthUsername, c.basicAuthPassword)
}
req.Header.Set(TatHeaderUsername, c.username)
req.Header.Set(TatHeaderPassword, c.password)
req.Header.Set(TatHeaderXTatRefererLower, c.referer)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Connection", "close")
return nil
}
// IsHTTPS returns true if url begins with https
func (c *Client) IsHTTPS() bool {
return strings.HasPrefix(c.url, "https")
}
func (c *Client) reqWant(method string, wantCode int, path string, jsonStr []byte) ([]byte, error) {
if c == nil {
return nil, ErrClientNotInitiliazed
}
requestPath := c.url + path
var req *http.Request
if jsonStr != nil {
req, _ = http.NewRequest(method, requestPath, bytes.NewReader(jsonStr))
} else {
req, _ = http.NewRequest(method, requestPath, nil)
}
c.initHeaders(req)
if HTTPClient == nil {
HTTPClient = &http.Client{
Transport: &httpcontrol.Transport{
RequestTimeout: c.requestTimeout,
MaxTries: c.maxTries,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: c.sslInsecureSkipVerify,
},
},
}
}
resp, err := HTTPClient.Do(req)
defer func() {
if resp != nil && resp.Body != nil {
resp.Body.Close()
}
}()
if resp == nil {
ErrorLogFunc("Invalid response from Tat. Please Check Tat Engine, err:%s", err)
return []byte{}, fmt.Errorf("Invalid response from Tat. Please Check Tat Engine, err:%s", err)
}
if resp.StatusCode != wantCode || IsDebug {
ErrorLogFunc("Request Username:%s Referer:%s Path:%s", c.username, c.referer, requestPath)
ErrorLogFunc("Request Body:%s", string(jsonStr))
ErrorLogFunc("Response Status:%s", resp.Status)
ErrorLogFunc("Response Headers:%s", resp.Header)
if resp.StatusCode != wantCode {
body, errc := ioutil.ReadAll(resp.Body)
if errc != nil {
ErrorLogFunc("Error with ioutil.ReadAll (with statusCode %d != wantCode %d) %s", resp.StatusCode, wantCode, errc)
return []byte{}, fmt.Errorf("Response code:%d (want:%d) err on readAll Body:%s", resp.StatusCode, wantCode, errc)
}
ErrorLogFunc("Response Body:%s", string(body))
return []byte{}, fmt.Errorf("Response code:%d (want:%d) with Body:%s", resp.StatusCode, wantCode, string(body))
}
}
DebugLogFunc("%s %s", method, requestPath)
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
ErrorLogFunc("Error with ioutil.ReadAll %s", err)
return nil, fmt.Errorf("Error with ioutil.ReadAll %s", err.Error())
}
if IsDebug {
ErrorLogFunc("Debug Response Body:%s", string(body))
}
return body, nil
}
func (c *Client) simpleGetAndGetBytes(url string) ([]byte, error) {
out, err := c.reqWant("GET", 200, url, nil)
if err != nil {
return nil, err
}
return out, nil
}
func (c *Client) simplePutAndGetBytes(url string, want int, v interface{}) ([]byte, error) {
return c.simpleReqAndGetBytes("PUT", url, want, v)
}
func (c *Client) simplePostAndGetBytes(url string, want int, v interface{}) ([]byte, error) {
return c.simpleReqAndGetBytes("POST", url, want, v)
}
func (c *Client) simpleDeleteAndGetBytes(url string, want int, v interface{}) ([]byte, error) {
return c.simpleReqAndGetBytes("DELETE", url, want, v)
}
func (c *Client) simpleReqAndGetBytes(method, url string, want int, v interface{}) ([]byte, error) {
var jsonStr []byte
var err error
if v != nil {
jsonStr, err = json.Marshal(v)
if err != nil {
ErrorLogFunc("Error while convert json:%s", err)
return nil, err
}
}
out, err := c.reqWant(method, want, url, jsonStr)
if err != nil {
return nil, err
}
return out, nil
}
// Sprint return the value in json as a string
func Sprint(v interface{}) ([]byte, error) {
jsonStr, err := json.Marshal(v)
if err != nil {
ErrorLogFunc("Error while convert response from tat:%s", err)
return []byte("Error while convert json struct from tat api"), err
}
return jsonStr, nil
}