simplify error, compute global sha
This commit is contained in:
parent
2078373889
commit
fff782569f
@ -9,6 +9,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
@ -24,8 +25,15 @@ type UploadCommand struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UploadError struct {
|
type UploadError struct {
|
||||||
Error string `json:"error"`
|
Err string `json:"error"`
|
||||||
Status string `json:"string"`
|
Details []string `json:"details"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UploadError) Error() string {
|
||||||
|
if len(u.Details) == 0 {
|
||||||
|
return u.Err
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s: \n - %s", u.Err, strings.Join(u.Details, "\n - "))
|
||||||
}
|
}
|
||||||
|
|
||||||
type UploadCreate struct {
|
type UploadCreate struct {
|
||||||
@ -39,6 +47,12 @@ type UploadPartResult struct {
|
|||||||
PartSha256 string `json:"sha256"`
|
PartSha256 string `json:"sha256"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UploadCompleteRequest struct {
|
||||||
|
Sha256 string `json:"sha256" binding:"required,sha256"`
|
||||||
|
Name string `json:"name" binding:"required"`
|
||||||
|
Parts uint `json:"parts" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
type UploadFileRequest struct {
|
type UploadFileRequest struct {
|
||||||
Name string
|
Name string
|
||||||
Checksum string
|
Checksum string
|
||||||
@ -156,7 +170,7 @@ func (c *UploadCommand) FileUpload(sum string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err, ok := resp.Error().(*UploadError); ok {
|
if err, ok := resp.Error().(*UploadError); ok {
|
||||||
wgErrors[w] = errors.New(err.Error)
|
wgErrors[w] = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +193,7 @@ func (c *UploadCommand) FileUpload(sum string) error {
|
|||||||
|
|
||||||
if err, ok := resp.Error().(*UploadError); ok {
|
if err, ok := resp.Error().(*UploadError); ok {
|
||||||
logger.Println("Upload failed")
|
logger.Println("Upload failed")
|
||||||
return errors.New(err.Error)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if result, ok := resp.Result().(*UploadFileResponse); ok {
|
if result, ok := resp.Result().(*UploadFileResponse); ok {
|
||||||
@ -197,7 +211,7 @@ func (c *UploadCommand) Execute(args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err, ok := resp.Error().(*UploadError); ok {
|
if err, ok := resp.Error().(*UploadError); ok {
|
||||||
return errors.New(err.Error)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadId := resp.Result().(*UploadCreate).UploadId
|
uploadId := resp.Result().(*UploadCreate).UploadId
|
||||||
@ -216,7 +230,8 @@ func (c *UploadCommand) Execute(args []string) error {
|
|||||||
tee := io.TeeReader(f, progress)
|
tee := io.TeeReader(f, progress)
|
||||||
|
|
||||||
b := make([]byte, photosapi.MaxUploadPartSize)
|
b := make([]byte, photosapi.MaxUploadPartSize)
|
||||||
part := 0
|
parts := 0
|
||||||
|
completesha256 := sha256.New()
|
||||||
for {
|
for {
|
||||||
n, err := tee.Read(b)
|
n, err := tee.Read(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -227,15 +242,16 @@ func (c *UploadCommand) Execute(args []string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
part++
|
parts++
|
||||||
partsha256 := sha256.New()
|
partsha256 := sha256.New()
|
||||||
partsha256.Write(b[:n])
|
partsha256.Write(b[:n])
|
||||||
|
completesha256.Write(b[:n])
|
||||||
|
|
||||||
resp, err := cli.
|
resp, err := cli.
|
||||||
R().
|
R().
|
||||||
SetError(&UploadError{}).
|
SetError(&UploadError{}).
|
||||||
SetResult(&UploadPartResult{}).
|
SetResult(&UploadPartResult{}).
|
||||||
SetQueryParam("part", fmt.Sprint(part)).
|
SetQueryParam("part", fmt.Sprint(parts)).
|
||||||
SetQueryParam("sha256", hex.EncodeToString(partsha256.Sum(nil))).
|
SetQueryParam("sha256", hex.EncodeToString(partsha256.Sum(nil))).
|
||||||
SetBody(b[:n]).
|
SetBody(b[:n]).
|
||||||
SetPathParam("id", uploadId).
|
SetPathParam("id", uploadId).
|
||||||
@ -246,16 +262,39 @@ func (c *UploadCommand) Execute(args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err, ok := resp.Error().(*UploadError); ok {
|
if err, ok := resp.Error().(*UploadError); ok {
|
||||||
return errors.New(err.Error)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf(
|
fmt.Printf(
|
||||||
"Upload: %s\nParts: %d\n",
|
"Upload: %s\nParts: %d\n",
|
||||||
uploadId,
|
uploadId,
|
||||||
part,
|
parts,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
resp, err = cli.
|
||||||
|
R().
|
||||||
|
SetError(&UploadError{}).
|
||||||
|
SetPathParam("id", uploadId).
|
||||||
|
SetBody(&UploadCompleteRequest{
|
||||||
|
Sha256: hex.EncodeToString(completesha256.Sum(nil)),
|
||||||
|
Parts: uint(parts),
|
||||||
|
Name: filepath.Base(c.File),
|
||||||
|
}).
|
||||||
|
Post("/upload/{id}")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err, ok := resp.Error().(*UploadError); ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Response: %s\n", resp.Body())
|
||||||
|
|
||||||
|
cli.R().SetPathParam("id", uploadId).Delete("/upload/{id}")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/dsoprea/go-exif/v3"
|
"github.com/dsoprea/go-exif/v3"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@ -30,28 +29,6 @@ var (
|
|||||||
ErrStoreMissingName = errors.New("name required")
|
ErrStoreMissingName = errors.New("name required")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Model
|
|
||||||
type File struct {
|
|
||||||
ID uint32 `gorm:"primary_key" json:"id"`
|
|
||||||
Name string `gorm:"not null" json:"name"`
|
|
||||||
Checksum string `gorm:"unique;size:44;not null"`
|
|
||||||
Size uint64 `gorm:"not null"`
|
|
||||||
Author *Account `gorm:"constraint:OnDelete:SET NULL,OnUpdate:CASCADE" json:"author"`
|
|
||||||
AuthorId *uint32 `json:"-"`
|
|
||||||
Chunks []*FileChunk `gorm:"constraint:OnDelete:CASCADE,OnUpdate:CASCADE"`
|
|
||||||
CreatedAt time.Time `json:"created_at"`
|
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type FileChunk struct {
|
|
||||||
FileId uint32
|
|
||||||
File *File `gorm:"constraint:OnDelete:CASCADE,OnUpdate:CASCADE"`
|
|
||||||
Part uint32
|
|
||||||
Checksum string `gorm:"unique;size:44;not null"`
|
|
||||||
CreatedAt time.Time `json:"created_at"`
|
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Service
|
// Service
|
||||||
var CHUNK_SIZE int64 = 4 << 20
|
var CHUNK_SIZE int64 = 4 << 20
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
@ -23,6 +24,28 @@ var (
|
|||||||
ErrUploadPartWrongSha256 = errors.New("upload part wrong sha256")
|
ErrUploadPartWrongSha256 = errors.New("upload part wrong sha256")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Model
|
||||||
|
type File struct {
|
||||||
|
ID uint32 `gorm:"primary_key" json:"id"`
|
||||||
|
Name string `gorm:"not null" json:"name"`
|
||||||
|
Checksum string `gorm:"unique;size:44;not null"`
|
||||||
|
Size uint64 `gorm:"not null"`
|
||||||
|
Author *Account `gorm:"constraint:OnDelete:SET NULL,OnUpdate:CASCADE" json:"author"`
|
||||||
|
AuthorId *uint32 `json:"-"`
|
||||||
|
Chunks []*FileChunk `gorm:"constraint:OnDelete:CASCADE,OnUpdate:CASCADE"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileChunk struct {
|
||||||
|
FileId uint32
|
||||||
|
File *File `gorm:"constraint:OnDelete:CASCADE,OnUpdate:CASCADE"`
|
||||||
|
Part uint32
|
||||||
|
Checksum string `gorm:"unique;size:44;not null"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) UploadCreate(c *gin.Context) {
|
func (s *Service) UploadCreate(c *gin.Context) {
|
||||||
sha, err := uuid.NewRandom()
|
sha, err := uuid.NewRandom()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -131,10 +154,19 @@ type UploadCompleteRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) UploadComplete(c *gin.Context) {
|
func (s *Service) UploadComplete(c *gin.Context) {
|
||||||
var uploadCompleteRequest UploadCompleteRequest
|
var (
|
||||||
if c.BindJSON(&uploadCompleteRequest) != nil {
|
upload UploadUri
|
||||||
|
uploadCompleteRequest UploadCompleteRequest
|
||||||
|
)
|
||||||
|
if c.BindUri(&upload) != nil || c.BindJSON(&uploadCompleteRequest) != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !s.StorageTmp.Exists(upload.Id) {
|
||||||
|
c.AbortWithError(http.StatusNotFound, ErrUploadNotExists)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"sha256": uploadCompleteRequest.Sha256,
|
"sha256": uploadCompleteRequest.Sha256,
|
||||||
"parts": uploadCompleteRequest.Parts,
|
"parts": uploadCompleteRequest.Parts,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user