Skip to content

Commit 8a1ae77

Browse files
Artem TitovArtem Titov
authored andcommitted
Merge remote-tracking branch 'origin/main' into dev/storage
1 parent aa19956 commit 8a1ae77

File tree

11 files changed

+235
-152
lines changed

11 files changed

+235
-152
lines changed

common/connectors/storageconn/connector.go

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package storageconn
22

33
import (
4-
"bytes"
54
"encoding/json"
65
"fmt"
76
"io"
87
"mime"
8+
"net/http"
99
"os"
1010
"path/filepath"
1111
"testing_system/common/config"
@@ -25,9 +25,6 @@ func NewConnector(connection *config.Connection) *Connector {
2525

2626
func (s *Connector) Download(request *Request) *FileResponse {
2727
response := NewFileResponse(*request)
28-
if request.StorageFilename == "" {
29-
response.Error = fmt.Errorf("storage filename not specified")
30-
}
3128

3229
if err := os.MkdirAll(request.BaseFolder, 0775); err != nil {
3330
response.Error = fmt.Errorf("failed to create base folder: %v", err)
@@ -47,18 +44,23 @@ func (s *Connector) Download(request *Request) *FileResponse {
4744
"request": string(requestJSON),
4845
})
4946

50-
resp, err := r.Get(path)
47+
resp, err := r.SetDoNotParseResponse(true).Execute("GET", path)
5148
if err != nil {
5249
response.Error = fmt.Errorf("failed to send request: %v", err)
5350
return response
5451
}
52+
defer resp.RawBody().Close()
5553

56-
if resp.IsError() {
57-
response.Error = fmt.Errorf("get request failed with status: %v", resp.Status())
54+
if resp.StatusCode() >= 400 {
55+
if resp.StatusCode() == http.StatusNotFound {
56+
response.Error = ErrStorageFileNotFound
57+
} else {
58+
response.Error = fmt.Errorf("get request failed with status: %v", resp.Status())
59+
}
5860
return response
5961
}
6062

61-
filename := ""
63+
var filename string
6264
if request.DownloadFilename != nil && *request.DownloadFilename != "" {
6365
filename = *request.DownloadFilename
6466
} else {
@@ -85,24 +87,20 @@ func (s *Connector) Download(request *Request) *FileResponse {
8587
}
8688
defer file.Close()
8789

88-
_, err = io.Copy(file, bytes.NewReader(resp.Body()))
90+
written, err := io.Copy(file, resp.RawBody())
8991
if err != nil {
9092
response.Error = fmt.Errorf("failed to write to file: %v", err)
9193
return response
9294
}
9395

9496
response.Filename = filename
9597
response.BaseFolder = request.BaseFolder
96-
response.Size = uint64(len(resp.Body()))
98+
response.Size = uint64(written)
9799
return response
98100
}
99101

100102
func (s *Connector) Upload(request *Request) *Response {
101103
response := &Response{R: *request}
102-
if request.StorageFilename == "" {
103-
response.Error = fmt.Errorf("storage filename not specified")
104-
return response
105-
}
106104

107105
if request.File == nil {
108106
response.Error = fmt.Errorf("file for upload is not specified")
@@ -121,6 +119,8 @@ func (s *Connector) Upload(request *Request) *Response {
121119
r.SetFormData(map[string]string{
122120
"request": string(requestJSON),
123121
})
122+
123+
// request.StorageFilename can be empty
124124
r.SetFileReader("file", request.StorageFilename, request.File)
125125

126126
resp, err := r.Post(path)
@@ -139,10 +139,6 @@ func (s *Connector) Upload(request *Request) *Response {
139139

140140
func (s *Connector) Delete(request *Request) *Response {
141141
response := &Response{R: *request}
142-
if request.StorageFilename == "" {
143-
response.Error = fmt.Errorf("storage filename not specified")
144-
return response
145-
}
146142

147143
path := "/storage/remove"
148144
r := s.connection.R()
@@ -153,7 +149,7 @@ func (s *Connector) Delete(request *Request) *Response {
153149
return response
154150
}
155151

156-
r.SetQueryParams(map[string]string{
152+
r.SetFormData(map[string]string{
157153
"request": string(requestJSON),
158154
})
159155

@@ -170,4 +166,3 @@ func (s *Connector) Delete(request *Request) *Response {
170166

171167
return response
172168
}
173-
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package storageconn
2+
3+
import "errors"
4+
5+
var ErrStorageFileNotFound = errors.New("file not found in storage")

common/connectors/storageconn/structs.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ type Request struct {
3434
// For uploads, File should be specified
3535
File io.Reader `json:"-"`
3636

37-
// StorageFilename should be always specified
37+
// If StorageFilename is not specified, Storage tries to get the filename automatically
3838
StorageFilename string `json:"storageFilename"`
3939
}
4040

common/constants/resource/resource_type.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const (
1717
CheckerOutput
1818
Interactor
1919
// Will be increased
20+
// Don't forget to add a new type to storage/filesystem/resource_info.go
2021
)
2122

2223
type DataType int

main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func main() {
3434
if ts.Config.Storage != nil {
3535
err := storage.SetupStorage(ts)
3636
if err != nil {
37-
logger.Panic(err.Error())
37+
logger.Panic("Can not setup storage, error: %v", err.Error())
3838
}
3939
} else {
4040
logger.Info("storage is not configured, skipping storage component")

storage/filesystem/filesystem.go

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"mime/multipart"
66
"os"
77
"path/filepath"
8-
"strings"
8+
"strconv"
99
"testing_system/common/config"
1010
"testing_system/lib/logger"
1111

@@ -21,25 +21,24 @@ func NewFilesystem(storageConfig *config.StorageConfig) IFilesystem {
2121
return &Filesystem{Basepath: storageConfig.StoragePath, BlockSize: storageConfig.BlockSize}
2222
}
2323

24-
func (filesystem *Filesystem) generatePathFromID(prefix string, id string) string {
25-
var parts []string
26-
parts = append(parts, prefix)
24+
func (filesystem *Filesystem) generatePathFromID(id string) string {
25+
parts := []string{}
2726
for i := 0; i < len(id); i += int(filesystem.BlockSize) {
2827
end := min(i+int(filesystem.BlockSize), len(id))
2928
parts = append(parts, id[i:end])
3029
}
3130
return filepath.Join(parts...)
3231
}
3332

34-
func (filesystem *Filesystem) SaveFile(c *gin.Context, prefix string, id string, filename string, file *multipart.FileHeader) error {
35-
fullPath, err := filesystem.GetFilePath(prefix, id, filename)
33+
func (filesystem *Filesystem) SaveFile(c *gin.Context, resourceInfo *ResourceInfo, file *multipart.FileHeader) error {
34+
fullPath, err := filesystem.BuildFilePath(resourceInfo)
3635
if err != nil {
3736
return err
3837
}
3938

40-
fullDirPath := filepath.Dir(fullPath)
41-
if err := os.MkdirAll(fullDirPath, 0755); err != nil {
42-
return fmt.Errorf("failed to create directory: %w", err)
39+
dir := filepath.Dir(fullPath)
40+
if err := os.MkdirAll(dir, 0755); err != nil {
41+
return fmt.Errorf("failed to create directory %s: %w", dir, err)
4342
}
4443

4544
if _, err := os.Stat(fullPath); err == nil {
@@ -49,8 +48,8 @@ func (filesystem *Filesystem) SaveFile(c *gin.Context, prefix string, id string,
4948
return c.SaveUploadedFile(file, fullPath)
5049
}
5150

52-
func (filesystem *Filesystem) RemoveFile(prefix string, id string, filename string) error {
53-
fullPath, err := filesystem.GetFilePath(prefix, id, filename)
51+
func (filesystem *Filesystem) RemoveFile(resourceInfo *ResourceInfo) error {
52+
fullPath, err := filesystem.BuildFilePath(resourceInfo)
5453
if err != nil {
5554
return err
5655
}
@@ -60,16 +59,18 @@ func (filesystem *Filesystem) RemoveFile(prefix string, id string, filename stri
6059
}
6160

6261
dir := filepath.Dir(fullPath)
63-
basePath, _ := filepath.Abs(filesystem.Basepath)
6462

6563
for {
66-
absDir, _ := filepath.Abs(dir)
67-
if absDir == basePath || !strings.HasPrefix(absDir, basePath) {
64+
if dir == filesystem.Basepath {
6865
break
6966
}
7067

7168
entries, err := os.ReadDir(dir)
72-
if err != nil || len(entries) > 0 {
69+
70+
if err != nil {
71+
return fmt.Errorf("failed to read directory %s: %w", dir, err)
72+
}
73+
if len(entries) > 0 {
7374
break
7475
}
7576

@@ -82,28 +83,34 @@ func (filesystem *Filesystem) RemoveFile(prefix string, id string, filename stri
8283
return nil
8384
}
8485

85-
func (filesystem *Filesystem) GetFilePath(prefix, id, filename string) (string, error) {
86-
if prefix == "" || id == "" || filename == "" {
87-
return "", fmt.Errorf("prefix, id, and filename cannot be empty")
88-
}
89-
90-
cleanFilename := filepath.Base(filename)
91-
92-
subpath := filesystem.generatePathFromID(prefix, id)
93-
fullPath := filepath.Join(filesystem.Basepath, subpath, cleanFilename)
94-
95-
absBasepath, err := filepath.Abs(filesystem.Basepath)
86+
func (filesystem *Filesystem) GetFile(resourceInfo *ResourceInfo) (string, error) {
87+
fullPath, err := filesystem.BuildFilePath(resourceInfo)
9688
if err != nil {
9789
return "", err
9890
}
9991

100-
absFullPath, err := filepath.Abs(fullPath)
92+
_, err = os.Stat(fullPath)
93+
10194
if err != nil {
10295
return "", err
10396
}
10497

105-
if !strings.HasPrefix(absFullPath, absBasepath) {
106-
return "", fmt.Errorf("invalid path: basepath is not a prefix of fullpath")
98+
return fullPath, nil
99+
}
100+
101+
func (filesystem *Filesystem) BuildFilePath(resourceInfo *ResourceInfo) (string, error) {
102+
subpathID := filesystem.generatePathFromID(strconv.FormatUint(resourceInfo.ID, 10))
103+
fullPath := filepath.Join(filesystem.Basepath, resourceInfo.DataType.String(), subpathID, resourceInfo.Filepath)
104+
105+
if resourceInfo.EmptyStorageFilename {
106+
entries, err := os.ReadDir(fullPath)
107+
if err != nil {
108+
return "", fmt.Errorf("failed to read directory %s: %v", fullPath, err)
109+
}
110+
if len(entries) != 1 || entries[0].IsDir() {
111+
return "", fmt.Errorf("StorageFilename is not specified, but directory %s does not contain exactly one file", fullPath)
112+
}
113+
fullPath = filepath.Join(fullPath, entries[0].Name())
107114
}
108115

109116
return fullPath, nil

storage/filesystem/interface.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
)
88

99
type IFilesystem interface {
10-
SaveFile(c *gin.Context, prefix string, id string, filename string, file *multipart.FileHeader) error
11-
RemoveFile(prefix string, id string, filename string) error
12-
GetFilePath(prefix string, id string, filename string) (string, error)
10+
SaveFile(c *gin.Context, resourceInfo *ResourceInfo, file *multipart.FileHeader) error
11+
RemoveFile(resourceInfo *ResourceInfo) error
12+
GetFile(resourceInfo *ResourceInfo) (string, error)
1313
}

0 commit comments

Comments
 (0)