/
client.go
153 lines (121 loc) · 3.66 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
package upload
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"mime/multipart"
"net/http"
"time"
"github.com/kyma-project/kyma/components/application-registry/internal/apperrors"
"github.com/kyma-project/kyma/components/application-registry/internal/httpconsts"
log "github.com/sirupsen/logrus"
)
const (
PublicFileField = "public"
EndpointFormat = "%s/v1/upload"
uploadRequestTimeout = time.Duration(5 * time.Second)
)
type Response struct {
UploadedFiles []UploadedFile
Errors []ResponseError
}
type ResponseError struct {
Message string
FileName string
}
type UploadedFile struct {
FileName string
RemotePath string
Bucket string
Size int64
}
type Client interface {
Upload(fileName string, contents []byte) (UploadedFile, apperrors.AppError)
}
type uploadClient struct {
httpClient http.Client
uploadServiceUrl string
}
func NewClient(uploadServiceUrl string) Client {
return uploadClient{
uploadServiceUrl: uploadServiceUrl,
httpClient: http.Client{
Timeout: uploadRequestTimeout,
},
}
}
func (uc uploadClient) Upload(fileName string, contents []byte) (UploadedFile, apperrors.AppError) {
req, err := uc.prepareRequest(fileName, contents)
if err != nil {
return UploadedFile{}, err
}
httpRes, err := uc.executeRequest(req)
if err != nil {
return UploadedFile{}, err
}
uploadRes, err := uc.unmarshal(httpRes)
if err != nil {
return UploadedFile{}, err
}
return uc.extract(fileName, uploadRes)
}
func (uc uploadClient) prepareRequest(fileName string, contents []byte) (*http.Request, apperrors.AppError) {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
{
err := uc.prepareMultipartForm(body, writer, fileName, contents)
if err != nil {
return nil, err
}
}
url := fmt.Sprintf(EndpointFormat, uc.uploadServiceUrl)
req, err := http.NewRequest(http.MethodPost, url, body)
if err != nil {
return nil, apperrors.Internal("Failed to create request, %s.", err)
}
req.Header.Set(httpconsts.HeaderContentType, writer.FormDataContentType())
return req, nil
}
func (uc uploadClient) prepareMultipartForm(body *bytes.Buffer, writer *multipart.Writer, fileName string, contents []byte) apperrors.AppError {
defer writer.Close()
publicFilePart, err := writer.CreateFormFile(PublicFileField, fileName)
if err != nil {
return apperrors.Internal("Failed to create multipart content, %s.", err.Error())
}
_, err = publicFilePart.Write(contents)
if err != nil {
return apperrors.Internal("Failed to write file contents, %s.", err.Error())
}
return nil
}
func (uc uploadClient) executeRequest(r *http.Request) (*http.Response, apperrors.AppError) {
res, err := uc.httpClient.Do(r)
if err != nil {
log.Errorf("Failed to execute request, %s.", err.Error())
return nil, apperrors.Internal("Failed to execute request.")
}
return res, nil
}
func (uc uploadClient) unmarshal(r *http.Response) (Response, apperrors.AppError) {
b, err := ioutil.ReadAll(r.Body)
if err != nil {
return Response{}, apperrors.Internal("Failed to read request body, %s.", err)
}
defer r.Body.Close()
var uploadResponse Response
err = json.Unmarshal(b, &uploadResponse)
if err != nil {
return Response{}, apperrors.Internal("Failed to unmarshal body, %s", err)
}
return uploadResponse, nil
}
func (uc uploadClient) extract(fileName string, response Response) (UploadedFile, apperrors.AppError) {
if len(response.UploadedFiles) == 1 {
return response.UploadedFiles[0], nil
}
for _, e := range response.Errors {
log.Errorf("Failed to upload %s file with Upload Service, %s.", e.FileName, e.Message)
}
return UploadedFile{}, apperrors.Internal("Failed to extract %s file from response.", fileName)
}