Compare commits
3 Commits
4ab8c9f614
...
0bd48fa166
Author | SHA1 | Date | |
---|---|---|---|
|
0bd48fa166 | ||
|
87f2e08227 | ||
|
0230a6ce4e |
@ -98,6 +98,8 @@ func (c *UploadCommand) Execute(args []string) error {
|
|||||||
- Name : %s
|
- Name : %s
|
||||||
- Parts : %d
|
- Parts : %d
|
||||||
- SHA256 : %s
|
- SHA256 : %s
|
||||||
|
|
||||||
|
Committing...
|
||||||
`,
|
`,
|
||||||
uploadId,
|
uploadId,
|
||||||
completeRequest.Name,
|
completeRequest.Name,
|
||||||
|
@ -102,7 +102,7 @@ func (s *Service) CurrentSession(c *gin.Context) *Session {
|
|||||||
|
|
||||||
func (s *Service) SessionCleaner() {
|
func (s *Service) SessionCleaner() {
|
||||||
for range time.Tick(time.Minute) {
|
for range time.Tick(time.Minute) {
|
||||||
t := time.Now().UTC().Add(-3 * time.Hour).Truncate(time.Minute)
|
t := time.Now().UTC().Add(-30 * time.Minute).Truncate(time.Minute)
|
||||||
// s.LogOk.Printf("Session", "Cleaning old session < %s", t)
|
// s.LogOk.Printf("Session", "Cleaning old session < %s", t)
|
||||||
if err := s.DB.Where("updated_at < ?", t).Delete(&Session{}).Error; err != nil {
|
if err := s.DB.Where("updated_at < ?", t).Delete(&Session{}).Error; err != nil {
|
||||||
s.LogErr.Printf("Session", "Cleaning failed: %s", err)
|
s.LogErr.Printf("Session", "Cleaning failed: %s", err)
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@ -19,10 +20,11 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrUploadNotExists = errors.New("upload id doesn't exists")
|
ErrUploadNotExists = errors.New("upload id does not exists")
|
||||||
ErrUploadPartTooLarge = fmt.Errorf("upload part too large (> %d B)", MaxUploadPartSize)
|
ErrUploadPartTooLarge = fmt.Errorf("upload part too large (> %d B)", MaxUploadPartSize)
|
||||||
ErrUploadPartWrongSha256 = errors.New("upload part wrong sha256")
|
ErrUploadPartWrongSha256 = errors.New("upload part sha256 does not match")
|
||||||
ErrFileAlreadExists = errors.New("file already exists")
|
ErrFileAlreadExists = errors.New("file already exists")
|
||||||
|
ErrUploadPartsCombineWrongSha256 = errors.New("upload parts combined sha256 does not match")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Model
|
// Model
|
||||||
@ -71,6 +73,36 @@ type UploadCompleteRequest struct {
|
|||||||
Parts uint `json:"parts" binding:"required"`
|
Parts uint `json:"parts" binding:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UploadCompleteFileOptions struct {
|
||||||
|
Ext string
|
||||||
|
IsTemp bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UploadCompleteRequest) Paths() []string {
|
||||||
|
return []string{u.Sha256[0:1], u.Sha256[1:2]}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UploadCompleteRequest) File(options *UploadCompleteFileOptions) []string {
|
||||||
|
filename := []string{}
|
||||||
|
if options == nil {
|
||||||
|
options = &UploadCompleteFileOptions{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.IsTemp {
|
||||||
|
filename = append(filename, "._tmp_")
|
||||||
|
}
|
||||||
|
filename = append(filename, u.Sha256)
|
||||||
|
if len(options.Ext) > 0 {
|
||||||
|
filename = append(filename, ".", options.Ext)
|
||||||
|
}
|
||||||
|
|
||||||
|
return []string{
|
||||||
|
u.Sha256[0:1],
|
||||||
|
u.Sha256[1:2],
|
||||||
|
strings.Join(filename, ""),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) UploadPart(c *gin.Context) {
|
func (s *Service) UploadPart(c *gin.Context) {
|
||||||
var (
|
var (
|
||||||
upload Upload
|
upload Upload
|
||||||
@ -156,13 +188,52 @@ func (s *Service) UploadComplete(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := s.StorageUpload.Stat(uploadCompleteRequest.Sha256[0:1], uploadCompleteRequest.Sha256[1:2], uploadCompleteRequest.Sha256)
|
if f, err := s.StorageUpload.Stat(uploadCompleteRequest.File(nil)...); err == nil && f.Mode().IsRegular() {
|
||||||
fmt.Println(err)
|
|
||||||
if err == nil && f.Mode().IsRegular() {
|
|
||||||
c.AbortWithError(http.StatusConflict, ErrFileAlreadExists)
|
c.AbortWithError(http.StatusConflict, ErrFileAlreadExists)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := s.StorageUpload.Create(uploadCompleteRequest.Paths()...); err != nil {
|
||||||
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Create(s.StorageUpload.Join(uploadCompleteRequest.File(&UploadCompleteFileOptions{IsTemp: true})...))
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fsha := sha256.New()
|
||||||
|
ft := io.MultiWriter(f, fsha)
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
for part := uint(1); part <= uploadCompleteRequest.Parts; part++ {
|
||||||
|
p, err := os.Open(s.StorageTmp.Join(upload.Id, fmt.Sprint(part)))
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithError(http.StatusNotFound, fmt.Errorf("upload part %d missing", part))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = io.Copy(ft, p)
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if uploadCompleteRequest.Sha256 != hex.EncodeToString(fsha.Sum(nil)) {
|
||||||
|
c.AbortWithError(http.StatusExpectationFailed, ErrUploadPartsCombineWrongSha256)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Close()
|
||||||
|
if err := os.Rename(
|
||||||
|
s.StorageUpload.Join(uploadCompleteRequest.File(&UploadCompleteFileOptions{IsTemp: true})...),
|
||||||
|
s.StorageUpload.Join(uploadCompleteRequest.File(nil)...),
|
||||||
|
); err != nil {
|
||||||
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
c.Status(http.StatusNoContent)
|
c.Status(http.StatusNoContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user