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) }