-
Notifications
You must be signed in to change notification settings - Fork 5
/
client.go
170 lines (139 loc) · 4.13 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
package virgilhttp
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"time"
"crypto/tls"
"github.com/valyala/fasthttp"
"gopkg.in/virgil.v4/errors"
"gopkg.in/virgil.v4/transport"
"gopkg.in/virgil.v4/transport/endpoints"
)
// TransportClientDoer set a doer to Http Transport client
func TransportClientDoer(client Doer) func(t *TransportClient) {
return func(t *TransportClient) {
t.client = client
}
}
// NewTransportClient create a new instance of HTTP Transport protocol for Virgil Client
// You can send nil for second paramter and by defaolt will be used http.Client
func NewTransportClient(serviceURL string, roServiceURL string, identityServiceURL string, vraServiceURL string, opts ...func(t *TransportClient)) *TransportClient {
t := &TransportClient{
cardServiceURL: strings.TrimRight(serviceURL, "/"),
roCardServiceURL: strings.TrimRight(roServiceURL, "/"),
identityServiceURL: strings.TrimRight(identityServiceURL, "/"),
vraServiceURL: strings.TrimRight(vraServiceURL, "/"),
client: &fasthttp.Client{
MaxIdleConnDuration: 24 * time.Hour,
TLSConfig: &tls.Config{
ClientSessionCache: tls.NewLRUClientSessionCache(0),
},
},
}
for _, option := range opts {
option(t)
}
return t
}
// Doer is a simple interface for wrap request
type Doer interface {
Do(*fasthttp.Request, *fasthttp.Response) error
}
// TransportClient is implementation for virgil client transport protocol
type TransportClient struct {
cardServiceURL string
roCardServiceURL string
identityServiceURL string
vraServiceURL string
client Doer
token string
}
func (c *TransportClient) Call(endpoint endpoints.Endpoint, payload interface{}, returnObj interface{}, params ...interface{}) error {
var ep *HTTPEndpoint
if e, ok := HTTPEndpoints[endpoint]; !ok {
return errors.Errorf("endpoint %d is not supported", endpoint)
} else {
ep = e
}
url, err := c.ToServiceURL(ep.ServiceType)
if err != nil {
return err
}
if len(params) != ep.Params {
return errors.Errorf("expected %d params but got %d", ep.Params, len(params))
}
urlParams := make([]interface{}, 1)
urlParams[0] = url
urlParams = append(urlParams, params...)
url = fmt.Sprintf(ep.URL, urlParams...)
res, err := c.getBody(c.do(ep.Method, url, payload))
if err != nil {
return err
}
err = json.Unmarshal(res, &returnObj)
if err != nil {
return errors.Wrap(err, "Cannot unmarshal response body")
}
return nil
}
func (c *TransportClient) ToServiceURL(serviceType ServiceType) (string, error) {
switch serviceType {
case Cardservice:
return c.cardServiceURL, nil
case ROCardService:
return c.roCardServiceURL, nil
case IdentityService:
return c.identityServiceURL, nil
case VRAService:
return c.vraServiceURL, nil
default:
return "", errors.Errorf("service %d not supported", serviceType)
}
}
func (c *TransportClient) SetToken(token string) {
c.token = token
}
type responseError struct {
Code int `json:"code"`
}
func (c *TransportClient) getBody(resp *fasthttp.Response, err error) ([]byte, error) {
if resp == nil {
return nil, errors.New("nil response")
}
if err != nil {
return nil, errors.Wrap(err, "")
}
body := resp.Body()
if resp.Header.StatusCode() == http.StatusNotFound {
return nil, errors.Wrap(transport.ErrNotFound, "")
}
if resp.Header.StatusCode() != http.StatusOK {
verr := &responseError{}
err = json.Unmarshal(body, verr)
if err != nil {
return nil, errors.Wrap(transport.ErrByTransportCode(resp.Header.StatusCode(), string(body)), "")
}
return nil, errors.Wrap(transport.GetErrByCode(resp.Header.StatusCode(), verr.Code), "")
}
return body, nil
}
func (c *TransportClient) do(method, url string, model interface{}) (*fasthttp.Response, error) {
var req fasthttp.Request
req.Header.SetMethod(method)
req.Header.SetRequestURI(url)
if model != nil {
reqBody, err := json.Marshal(model)
if err != nil {
return nil, errors.Wrap(err, "Cannot marshal model")
}
req.SetBody(reqBody)
}
if len(c.token) > 0 {
req.Header.Set("Authorization", fmt.Sprintf("VIRGIL %s", c.token))
}
var resp fasthttp.Response
err := c.client.Do(&req, &resp)
return &resp, err
}