package photosapi import ( "errors" ) // Error var ( // Store ErrStoreBadChecksum = errors.New("checksum should be sha256 in hex format") ErrStoreBadChunkSize = errors.New("part file size should be 1MB max") ErrStoreMissingChunks = errors.New("part checksum missing") ErrStoreWrongChecksum = errors.New("wrong checksum") ErrStoreMismatchChecksum = errors.New("part files doesn't match the original checksum") ErrStoreAlreadyExists = errors.New("original file already exists") ErrStoreChunkAlreadyExists = errors.New("chunk file already exists") ErrStoreMissingName = errors.New("name required") ) // // Service // var CHUNK_SIZE int64 = 4 << 20 // type FileRequest struct { // Name string `json:"name"` // Checksum string `json:"checksum"` // Chunks []string `json:"chunks"` // } // func (s *Service) FileCreate(c *gin.Context) { // file := &FileRequest{} // if c.BindJSON(file) != nil { // return // } // if len(file.Name) < 1 { // c.AbortWithError(http.StatusBadRequest, ErrStoreMissingName) // return // } // if len(file.Checksum) != 40 { // c.AbortWithError(http.StatusBadRequest, ErrStoreBadChecksum) // return // } // if len(file.Chunks) == 0 { // c.AbortWithError(http.StatusBadRequest, ErrStoreMissingChunks) // return // } // for _, chunk := range file.Chunks { // if len(chunk) != 40 { // c.AbortWithError(http.StatusBadRequest, ErrStoreBadChecksum) // return // } // } // r, rs, err := s.Store.Combine(file.Chunks) // if err != nil { // if strings.HasPrefix(err.Error(), "chunk") && strings.HasSuffix(err.Error(), "doesn't exists") { // c.AbortWithError(http.StatusBadRequest, err) // } else { // c.AbortWithError(http.StatusInternalServerError, err) // } // return // } // if r != file.Checksum { // c.AbortWithError(http.StatusExpectationFailed, ErrStoreMismatchChecksum) // return // } // sess := s.CurrentSession(c) // f := &File{ // Name: file.Name, // Checksum: file.Checksum, // Size: rs, // AuthorId: &sess.AccountId, // } // err = s.DB.Transaction(func(tx *gorm.DB) error { // if err := tx.Create(f).Error; err != nil { // return err // } // for i, chunk := range file.Chunks { // fc := &FileChunk{ // FileId: f.ID, // Part: uint32(i + 1), // Checksum: chunk, // } // if err := tx.Create(fc).Error; err != nil { // return err // } // } // return nil // }) // if nerr, ok := err.(*pgconn.PgError); ok { // if nerr.Code == "23505" && nerr.Detail == fmt.Sprintf("Key (checksum)=(%s) already exists.", file.Checksum) { // err = nil // } // } // if err != nil { // c.AbortWithError(http.StatusInternalServerError, err) // return // } // c.JSON(http.StatusOK, gin.H{ // "sum": file.Checksum, // "nbChunks": len(file.Chunks), // "size": rs, // }) // } // func (s *Service) FileCreateChunk(c *gin.Context) { // if c.Request.ContentLength > CHUNK_SIZE { // c.AbortWithError(http.StatusBadRequest, ErrStoreBadChunkSize) // return // } // b := bytes.NewBuffer([]byte{}) // io.Copy(b, c.Request.Body) // sess := s.CurrentSession(c) // chunk := s.Store.NewChunk(b.Bytes()) // if err := chunk.Save(sess.Account.Login); err != nil { // if errors.Is(err, ErrStoreChunkAlreadyExists) { // c.JSON(http.StatusOK, gin.H{ // "checksum": chunk.Sum, // }) // } else { // c.AbortWithError(http.StatusBadRequest, err) // } // return // } // c.JSON(http.StatusOK, gin.H{ // "checksum": chunk.Sum, // }) // } // func (s *Service) FileChunkExists(c *gin.Context) { // checksum := c.Param("checksum") // if len(checksum) != 40 { // c.AbortWithError(http.StatusBadRequest, ErrStoreBadChecksum) // return // } // if s.Store.Chunk(checksum).FileExists() { // c.Status(http.StatusOK) // } else { // c.Status(http.StatusNotFound) // } // } // func (s *Service) FileExists(c *gin.Context) { // checksum := c.Param("checksum") // if len(checksum) != 40 { // c.AbortWithError(http.StatusBadRequest, ErrStoreBadChecksum) // return // } // var fileExists int64 // if err := s.DB.Model(&File{}).Where("checksum = ?", checksum).Count(&fileExists).Error; err != nil { // c.AbortWithError(http.StatusInternalServerError, err) // return // } // if fileExists > 0 { // c.Status(http.StatusOK) // } else { // c.Status(http.StatusNotFound) // } // } // func (s *Service) FileGet(c *gin.Context) { // checksum := c.Param("checksum") // if len(checksum) != 40 { // c.AbortWithError(http.StatusBadRequest, ErrStoreBadChecksum) // return // } // if checksum == c.GetHeader("If-None-Match") { // c.Status(http.StatusNotModified) // return // } // f := &File{} // if err := s.DB.Debug().Preload("Chunks").Where("checksum = ?", checksum).First(&f).Error; err != nil { // c.AbortWithError(http.StatusBadRequest, err) // return // } // chunks := make([]string, len(f.Chunks)) // for _, fc := range f.Chunks { // chunks[fc.Part-1] = fc.Checksum // } // reader, err := s.Store.NewStoreReader(chunks) // if err != nil { // c.AbortWithError(http.StatusInternalServerError, err) // return // } // defer reader.Close() // c.DataFromReader( // http.StatusOK, // reader.Size, // mime.TypeByExtension(filepath.Ext(f.Name)), // reader, // map[string]string{ // "Content-Disposition": fmt.Sprintf("inline; filename=\"%s\"", f.Name), // "ETag": f.Checksum, // }, // ) // } // func (s *Service) FileAnalyze(c *gin.Context) { // checksum := c.Param("checksum") // if len(checksum) != 40 { // c.AbortWithError(http.StatusBadRequest, ErrStoreBadChecksum) // return // } // f := &File{} // if err := s.DB.Debug().Preload("Chunks").Where("checksum = ?", checksum).First(&f).Error; err != nil { // c.AbortWithError(http.StatusBadRequest, err) // return // } // chunks := make([]string, len(f.Chunks)) // for _, fc := range f.Chunks { // chunks[fc.Part-1] = fc.Checksum // } // reader, err := s.Store.NewStoreReader(chunks) // if err != nil { // c.AbortWithError(http.StatusInternalServerError, err) // return // } // defer reader.Close() // rawExif, err := exif.SearchAndExtractExifWithReader(reader) // if err != nil { // c.AbortWithError(http.StatusInternalServerError, err) // return // } // entries, _, err := exif.GetFlatExifDataUniversalSearch(rawExif, nil, true) // if err != nil { // c.AbortWithError(http.StatusInternalServerError, err) // return // } // c.JSON(http.StatusOK, gin.H{ // "exif": entries, // }) // } func (s *Service) FileInit() { file := s.Gin.Group("/file") file.Use(s.RequireSession) // file.POST("", s.FileCreate) // file.HEAD("/:checksum", s.FileExists) // file.GET("/:checksum", s.FileGet) // file.POST("/chunk", s.FileCreateChunk) // file.HEAD("/chunk/:checksum", s.FileChunkExists) // file.GET("/analyze/:checksum", s.FileAnalyze) }