-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathCreateUploadFile.go
executable file
·141 lines (128 loc) · 4.87 KB
/
CreateUploadFile.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
package logic
import (
"ch/kirari04/videocms/config"
"ch/kirari04/videocms/helpers"
"ch/kirari04/videocms/inits"
"ch/kirari04/videocms/models"
"errors"
"fmt"
"io"
"log"
"net/http"
"os"
"github.com/google/uuid"
"github.com/labstack/echo/v4"
)
/*
*/
func CreateUploadFile(sessionToken string, userId uint) (status int, response *models.Link, err error) {
// validate token
token, claims, err := helpers.VerifyDynamicJWT(sessionToken, &models.UploadSessionClaims{}, []byte(config.ENV.JwtUploadSecretKey))
if err != nil && claims != nil {
log.Printf("err: %v", err)
return http.StatusBadRequest, nil, errors.New("broken upload session token")
}
if !token.Valid {
return http.StatusBadRequest, nil, errors.New("invalid upload session token")
}
if (*claims).UserID != userId {
return http.StatusForbidden, nil, echo.ErrForbidden
}
//check if session still active
uploadSession := models.UploadSession{}
if res := inits.DB.
Where(&models.UploadSession{
UUID: (*claims).UUID,
UserID: userId,
}).First(&uploadSession); res.Error != nil {
return http.StatusNotFound, nil, errors.New("upload session not found")
}
//list all chuncks
uploadChuncks := []models.UploadChunck{}
if res := inits.DB.
Where(&models.UploadChunck{
UploadSessionID: uploadSession.ID,
}).
Order("`index` ASC").
Find(&uploadChuncks); res.Error != nil {
log.Printf("Failed to create find upload chuncks: %v", res.Error)
return http.StatusNotFound, nil, errors.New("upload chuncks not found")
}
if len(uploadChuncks) != uploadSession.ChunckCount {
return http.StatusBadRequest, nil, fmt.Errorf("missing Chuncks: uploaded %v, required %v", len(uploadChuncks), uploadSession.ChunckCount)
}
// delete any missing files or sessions inside database if anything failes or it successfully finishes
defer createUploadFileCleanup(&uploadSession)
// open finalFile (copy destination of the chuncks)
finalFilePath := fmt.Sprintf("%v/example.mkv", uploadSession.SessionFolder)
finalFile, err := os.OpenFile(finalFilePath, os.O_CREATE|os.O_WRONLY, 0766)
if err != nil {
log.Printf("Failed to create final file: %v", err)
return http.StatusInternalServerError, nil, echo.ErrInternalServerError
}
// copy uploaded chuncks into final file
var written int64
for _, uploadChunck := range uploadChuncks {
openedChunck, err := os.Open(uploadChunck.Path)
if err != nil {
log.Printf("Failed to read chunck %v: %v", uploadChunck.Path, err)
return http.StatusInternalServerError, nil, echo.ErrInternalServerError
}
n, err := io.Copy(finalFile, openedChunck)
if err != nil {
log.Printf("Failed to copy chunck %v: %v", uploadChunck.Path, err)
return http.StatusInternalServerError, nil, echo.ErrInternalServerError
}
written += n
if err := openedChunck.Close(); err != nil {
log.Printf("Failed to close chunck %v: %v", uploadChunck.Path, err)
return http.StatusInternalServerError, nil, echo.ErrInternalServerError
}
}
if err := finalFile.Close(); err != nil {
log.Printf("Failed to close final file: %v", err)
return http.StatusInternalServerError, nil, echo.ErrInternalServerError
}
// check file size
finalFilePathInfo, err := os.Stat(finalFilePath)
if err != nil {
log.Printf("Failed to read filestat of final file: %v", err)
return http.StatusInternalServerError, nil, echo.ErrInternalServerError
}
if finalFilePathInfo.Size() != uploadSession.Size {
return http.StatusConflict, nil, fmt.Errorf("the uploaded file size doesnt match with the uploaded file: server %v, client %v", finalFilePathInfo.Size(), uploadSession.Size)
}
// create file
fileId := uuid.NewString()
filePath := fmt.Sprintf("%s/%s.%s", config.ENV.FolderVideoUploadsPriv, fileId, "tmp")
if err := os.Rename(finalFilePath, filePath); err != nil {
log.Printf("Failed to copy final file to destination: %v", err)
return http.StatusInternalServerError, nil, echo.ErrInternalServerError
}
status, dbLink, cloned, err := CreateFile(&filePath, uploadSession.ParentFolderID, uploadSession.Name, fileId, uploadSession.Size, userId)
if err != nil {
os.Remove(filePath)
return status, nil, err
}
if cloned {
os.Remove(filePath)
}
return status, dbLink, nil
}
func createUploadFileCleanup(uploadSession *models.UploadSession) {
if err := os.RemoveAll(uploadSession.SessionFolder); err != nil {
log.Printf("[WARNING] createUploadFileCleanup -> remove session folder: %v\n", err)
}
if res := inits.DB.
Model(&models.UploadChunck{}).
Where(&models.UploadChunck{
UploadSessionID: uploadSession.ID,
}).
Delete(&models.UploadChunck{}); res.Error != nil {
log.Printf("[WARNING] createUploadFileCleanup -> remove upload chuncks from database (%d): %v\n", uploadSession.ID, res.Error)
}
if res := inits.DB.
Delete(&models.UploadSession{}, uploadSession.ID); res.Error != nil {
log.Printf("[WARNING] createUploadFileCleanup -> remove upload session from database (%d): %v\n", uploadSession.ID, res.Error)
}
}