upload part

This commit is contained in:
celogeek 2022-05-02 09:00:46 +02:00
parent 54afe3ebcf
commit 4fbe92cdcf
Signed by: celogeek
GPG Key ID: E6B7BDCFC446233A
4 changed files with 171 additions and 12 deletions

View File

@ -15,12 +15,13 @@ import (
)
type Service struct {
Gin *gin.Engine
DB *gorm.DB
Config *ServiceConfig
Store *store.Store
LogOk *Logger
LogErr *Logger
Gin *gin.Engine
DB *gorm.DB
Config *ServiceConfig
Store *store.Store
Storage *Storage
LogOk *Logger
LogErr *Logger
}
type ServiceConfig struct {
@ -31,11 +32,12 @@ type ServiceConfig struct {
func New(config *ServiceConfig) *Service {
return &Service{
Gin: gin.New(),
Config: config,
Store: &store.Store{Path: config.StorePath},
LogOk: &Logger{os.Stdout, "Photos"},
LogErr: &Logger{os.Stderr, "Photos"},
Gin: gin.New(),
Config: config,
Store: &store.Store{Path: config.StorePath},
Storage: &Storage{Path: config.StorePath},
LogOk: &Logger{os.Stdout, "Photos"},
LogErr: &Logger{os.Stderr, "Photos"},
}
}
@ -49,6 +51,7 @@ func (s *Service) SetupRoutes() {
s.AccountInit()
s.MeInit()
s.FileInit()
s.UploadInit()
s.Gin.NoRoute(func(c *gin.Context) {
s.Error(c, http.StatusNotFound, photoserrors.ErrReqNotFound)

View File

@ -0,0 +1,40 @@
package api
import (
"fmt"
"os"
"path/filepath"
)
type Storage struct {
Path string
}
const (
StorageTmp = "tmp"
StorageUpload = "upload"
)
func (s *Storage) Join(paths ...string) string {
return filepath.Join(s.Path, filepath.Join(paths...))
}
func (s *Storage) Create(paths ...string) error {
return os.MkdirAll(s.Join(paths...), 0755)
}
func (s *Storage) Exists(paths ...string) bool {
f, err := os.Stat(s.Join(paths...))
if err != nil {
return false
}
return f.IsDir()
}
func (s *Storage) Delete(paths ...string) error {
if s.Exists(paths...) {
return os.RemoveAll(s.Join(paths...))
} else {
return fmt.Errorf("%s doesn't exists", s.Join(paths...))
}
}

View File

@ -0,0 +1,117 @@
package api
import (
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"io"
"net/http"
"os"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
func (s *Service) UploadCreate(c *gin.Context) {
sha, err := uuid.NewRandom()
if err != nil {
s.Error(c, http.StatusInternalServerError, err)
return
}
if err := s.Storage.Create(StorageTmp, sha.String()); err != nil {
s.Error(c, http.StatusInternalServerError, err)
return
}
c.JSON(http.StatusCreated, gin.H{
"status": "success",
"upload_id": sha.String(),
})
}
type UploadPartRequest struct {
UploadId string `uri:"upload_id" binding:"required,uuid"`
Part uint `uri:"part" binding:"required"`
}
func (s *Service) UploadPart(c *gin.Context) {
var uploadPart UploadPartRequest
if err := c.ShouldBindUri(&uploadPart); err != nil {
s.Error(c, http.StatusBadRequest, err)
return
}
if !s.Storage.Exists(StorageTmp, uploadPart.UploadId) {
s.Error(c, http.StatusNotFound, errors.New("upload id doesn't exists"))
return
}
f, err := os.Create(
s.Storage.Join(StorageTmp, uploadPart.UploadId, fmt.Sprint(uploadPart.Part)),
)
if err != nil {
s.Error(c, 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 {
s.Error(c, http.StatusInternalServerError, err)
return
}
c.JSON(http.StatusCreated, gin.H{
"upload_id": uploadPart.UploadId,
"part": uploadPart.Part,
"size": w,
"sha256": hex.EncodeToString(sha.Sum(nil)),
"status": "success",
})
}
func (s *Service) UploadCancel(c *gin.Context) {
upload_id := c.Param("upload_id")
if err := s.Storage.Delete(StorageTmp, upload_id); err != nil {
s.Error(c, http.StatusNotFound, errors.New("upload id doesn't exists"))
return
}
c.JSON(http.StatusOK, gin.H{
"status": "success",
})
}
type UploadCompleteRequest struct {
SHA256 string `json:"sha256" binding:"required,lowercase,alphanum,len=64"`
Name string `json:"name" binding:"required"`
Parts uint `json:"parts" binding:"required"`
}
func (s *Service) UploadComplete(c *gin.Context) {
var uploadCompleteRequest UploadCompleteRequest
if err := c.ShouldBindJSON(&uploadCompleteRequest); err != nil {
s.Error(c, http.StatusBadRequest, err)
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/:part", s.UploadPart)
upload.GET("/cancel/:upload_id", s.UploadCancel)
upload.POST("/complete/:upload_id", s.UploadComplete)
}

View File

@ -13,4 +13,3 @@ then
createdb photos
createuser photos
fi
tail -f data/db.log