-
Notifications
You must be signed in to change notification settings - Fork 716
Expand file tree
/
Copy pathchunk_model.go
More file actions
127 lines (109 loc) · 3.21 KB
/
chunk_model.go
File metadata and controls
127 lines (109 loc) · 3.21 KB
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
package model
import (
"crypto/md5"
"errors"
"fmt"
"net/http"
"os"
"path/filepath"
"github.com/gin-gonic/gin"
)
type ChunkFileRequest struct {
FileId string `json:"fileId"` // client create uuid
FileName string `json:"fileName"` // file name
FileIndex int `json:"fileIndex"` // file index
FileCount int `json:"fileCount"` // file slice size
FileKeys []string `json:"fileKeys"` // file slice all key md5 (accumulation file key if fileIndex == fileCount then merge after verification)
FileKey string `json:"fileKey"` // file now key to md5 - if server read the slice to md5 eq key not eq then fail
File []byte `json:"file"` // now file
}
func (cf *ChunkFileRequest) BindingForm(ctx *gin.Context) error {
if err := ctx.ShouldBind(cf); err != nil {
return err
}
return cf.md5()
}
func (cf *ChunkFileRequest) md5() error {
hash := fmt.Sprintf("%x", md5.Sum(cf.File))
if hash != cf.FileKey {
return errors.New("current file slice key error")
}
return nil
}
func (cf *ChunkFileRequest) SaveUploadedFile(tempPath, path string) (string, error) {
tempFolder := filepath.Join(tempPath, cf.FileId)
_, err := os.Stat(tempFolder)
if os.IsNotExist(err) {
err := os.MkdirAll(tempFolder, os.ModePerm)
if err != nil {
return "", err
}
}
out, err := os.Create(filepath.Join(tempFolder, cf.FileKey))
if err != nil {
return "", err
}
defer out.Close()
if _, err := out.Write(cf.File); err != nil {
return "", err
}
fmt.Println(cf.FileIndex, cf.FileCount)
if cf.FileIndex != cf.FileCount {
return "", nil
}
for _, fileKey := range cf.FileKeys {
tempFile := filepath.Join(tempFolder, fileKey)
if _, err := os.Stat(tempFile); err != nil {
return "", errors.New("file " + fileKey + " is emtpy")
}
}
base := filepath.Dir(path)
if _, err := os.Stat(base); err != nil {
if os.IsNotExist(err) {
err := os.MkdirAll(base, os.ModePerm)
if err != nil {
return "", err
}
}
}
file, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0664)
if err != nil {
return "", err
}
defer file.Close()
for _, fileKey := range cf.FileKeys {
tempFile := filepath.Join(tempFolder, fileKey)
bt, err := os.ReadFile(tempFile)
if err != nil {
return "", err
}
file.Write(bt)
}
return tempFolder, nil
}
// request method is json
// param: fileId
// param: fileName
// param: fileIndex the file slice index
// param: fileCount the file slice size
// param: fileKeys the file slice all file key md5 (accumulation file key if fileIndex == fileCount then merge after verification)
// param: fileKey now file slice key md5
// param: file now slice file
func ChunkUploadFile(ctx *gin.Context) {
var cf ChunkFileRequest
if err := cf.BindingForm(ctx); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"code": "400", "msg": "bad file param", "err": err.Error()})
return
}
tempFolder, err := cf.SaveUploadedFile("./temp", "./uploads/"+cf.FileName)
if err != nil {
ctx.JSON(http.StatusServiceUnavailable, gin.H{"code": "503", "msg": "bad save upload file", "err": err.Error()})
return
}
ctx.JSON(http.StatusOK, gin.H{"code": "200", "msg": "success"})
if tempFolder != "" {
defer func(tempFolder string) {
os.RemoveAll(tempFolder)
}(tempFolder)
}
}