2022-05-07 20:40:14 +02:00

131 lines
2.8 KiB
Go

package photosapi
import (
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"io"
"net/http"
"os"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
var (
ErrUploadNotExists = errors.New("upload id doesn't exists")
)
func (s *Service) UploadCreate(c *gin.Context) {
sha, err := uuid.NewRandom()
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
if err := s.Storage.Create(StorageTmp, sha.String()); err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
c.JSON(http.StatusCreated, gin.H{
"status": "success",
"upload_id": sha.String(),
})
}
type UploadUri struct {
Id string `uri:"upload_id" binding:"required,uuid"`
}
type UploadPartQuery struct {
Part uint `form:"part" binding:"required"`
PartSha256 string `form:"sha256" binding:"required,sha256"`
}
func (s *Service) UploadPart(c *gin.Context) {
var (
upload UploadUri
uploadPart UploadPartQuery
)
if c.BindUri(&upload) != nil || c.BindQuery(&uploadPart) != nil {
return
}
if !s.Storage.Exists(StorageTmp, upload.Id) {
c.AbortWithError(http.StatusNotFound, ErrUploadNotExists)
return
}
f, err := os.Create(
s.Storage.Join(StorageTmp, upload.Id, fmt.Sprint(uploadPart.Part)),
)
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
defer f.Close()
defer c.Request.Body.Close()
sha := sha256.New()
t := io.TeeReader(c.Request.Body, sha)
w, err := io.Copy(f, t)
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
c.JSON(http.StatusCreated, gin.H{
"upload_id": upload.Id,
"part": uploadPart.Part,
"size": w,
"sha256": hex.EncodeToString(sha.Sum(nil)),
"status": "success",
})
}
func (s *Service) UploadCancel(c *gin.Context) {
var upload UploadUri
if c.BindUri(&upload) != nil {
return
}
if err := s.Storage.Delete(StorageTmp, upload.Id); err != nil {
c.AbortWithError(http.StatusNotFound, ErrUploadNotExists)
return
}
c.JSON(http.StatusOK, gin.H{
"status": "success",
})
}
type UploadCompleteRequest struct {
Sha256 string `json:"sha256" binding:"required,sha256"`
Name string `json:"name" binding:"required"`
Parts uint `json:"parts" binding:"required"`
}
func (s *Service) UploadComplete(c *gin.Context) {
var uploadCompleteRequest UploadCompleteRequest
if c.BindJSON(&uploadCompleteRequest) != nil {
return
}
c.JSON(http.StatusOK, gin.H{
"sha256": uploadCompleteRequest.Sha256,
"parts": uploadCompleteRequest.Parts,
"name": uploadCompleteRequest.Name,
})
}
func (s *Service) UploadInit() {
upload := s.Gin.Group("/upload")
upload.GET("/create", s.UploadCreate)
upload.POST("/part/:upload_id", s.UploadPart)
upload.GET("/cancel/:upload_id", s.UploadCancel)
upload.POST("/complete/:upload_id", s.UploadComplete)
}