From 1c5b20015158721d9a5454b25dc016e2390c895c Mon Sep 17 00:00:00 2001 From: celogeek Date: Tue, 1 Mar 2022 15:13:27 +0100 Subject: [PATCH] upload chunks --- internal/photos/api/file.go | 115 +++++++++++++++++++++++++++++++----- 1 file changed, 99 insertions(+), 16 deletions(-) diff --git a/internal/photos/api/file.go b/internal/photos/api/file.go index 29debb3..1f0af5c 100644 --- a/internal/photos/api/file.go +++ b/internal/photos/api/file.go @@ -4,10 +4,14 @@ import ( "bytes" "crypto/sha1" "encoding/hex" + "fmt" "io" + "io/fs" "net/http" "os" "path/filepath" + "sort" + "strconv" "github.com/gin-gonic/gin" ) @@ -24,10 +28,83 @@ func (s *Service) PrepareStore() { } } +func (s *Service) StoreDir(checksum string) (string, error) { + dir := filepath.Join(s.Config.StorePath, "original", checksum[0:0], checksum[1:1], checksum[2:]) + err := os.MkdirAll(dir, 0755) + return dir, err +} + +func (s *Service) TempDir(checksum string) (string, error) { + dir := filepath.Join(s.Config.StorePath, "tmp", checksum) + err := os.MkdirAll(dir, 0755) + return dir, err +} + +type FileChunks struct { + N uint64 + Path fs.FS + Name string +} + +func (s *Service) FileChunks(checksum string) ([]FileChunks, error) { + base := filepath.Join(s.Config.StorePath, "tmp", checksum) + baseDir := os.DirFS(base) + dir, err := os.Open(base) + if err != nil { + return nil, err + } + defer dir.Close() + + files, err := dir.Readdirnames(-1) + if err != nil { + return nil, err + } + parts := []FileChunks{} + for _, f := range files { + n, err := strconv.ParseUint(f, 10, 64) + if err != nil { + continue + } + parts = append(parts, FileChunks{n, baseDir, f}) + } + + sort.Slice(parts, func(i, j int) bool { + return parts[i].N < parts[j].N + }) + return parts, nil +} + func (s *Service) FileCreate(c *gin.Context) { var originalChecksum = c.Param("original_checksum") + files, err := s.FileChunks(originalChecksum) + if err != nil { + s.Error(c, http.StatusInternalServerError, err) + return + } + + sum := sha1.New() + size := uint64(0) + for _, f := range files { + b, err := fs.ReadFile(f.Path, f.Name) + if err != nil { + s.Error(c, http.StatusInternalServerError, err) + return + } + sum.Write(b) + size += uint64(len(b)) + } + r := hex.EncodeToString(sum.Sum(nil)) + if r != originalChecksum { + fmt.Printf("R=%s, O=%s\n", r, originalChecksum) + s.Error(c, http.StatusExpectationFailed, ErrStoreMismatchChecksum) + return + } + c.JSON(http.StatusOK, gin.H{ - "original_checksum": originalChecksum, + "status": "success", + "checksum": originalChecksum, + "nbParts": len(files), + "size": size, }) } @@ -47,18 +124,16 @@ func (s *Service) FileChunk(c *gin.Context) { return } + p, err := strconv.ParseUint(part, 10, 64) + if err != nil || p < 1 { + s.Error(c, http.StatusBadRequest, ErrStoreBadPartNumber) + return + } + b := bytes.NewBuffer([]byte{}) io.Copy(b, c.Request.Body) c.Request.Body.Close() - f, err := os.Create(filepath.Join(s.Config.StorePath, "test")) - if err != nil { - s.Error(c, http.StatusInternalServerError, err) - return - } - f.Write(b.Bytes()) - f.Close() - sum := sha1.New() sum.Write(b.Bytes()) r := hex.EncodeToString(sum.Sum(nil)) @@ -68,13 +143,21 @@ func (s *Service) FileChunk(c *gin.Context) { return } + dir, err := s.TempDir(originalChecksum) + if err != nil { + s.Error(c, http.StatusInternalServerError, err) + return + } + + f, err := os.Create(filepath.Join(dir, part)) + if err != nil { + s.Error(c, http.StatusInternalServerError, err) + return + } + f.Write(b.Bytes()) + f.Close() + c.JSON(http.StatusOK, gin.H{ - "original_checksum": originalChecksum, - "part": part, - "part_checksum": partChecksum, - "body": gin.H{ - "checksum": r, - "size": b.Len(), - }, + "status": "success", }) }