96 lines
1.6 KiB
Go
96 lines
1.6 KiB
Go
package store
|
|
|
|
import (
|
|
"crypto/sha1"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"gitlab.celogeek.com/photos/api/internal/photoserrors"
|
|
)
|
|
|
|
type Store struct {
|
|
Path string
|
|
}
|
|
|
|
type Chunk struct {
|
|
*Store
|
|
Sum string
|
|
Bytes []byte
|
|
}
|
|
|
|
func (s *Store) NewChunk(b []byte) *Chunk {
|
|
sum := sha1.New()
|
|
sum.Write(b)
|
|
sumString := hex.EncodeToString(sum.Sum(nil))
|
|
|
|
return &Chunk{s, sumString, b}
|
|
}
|
|
|
|
func (s *Store) LoadChunk(sum string) (*Chunk, error) {
|
|
c := &Chunk{s, sum, nil}
|
|
if !c.FileExists() {
|
|
return nil, fmt.Errorf("chunk %s doesn't exists", sum)
|
|
}
|
|
b, err := os.ReadFile(c.Filename())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
c.Bytes = b
|
|
return c, nil
|
|
}
|
|
|
|
func (c *Chunk) Dir() string {
|
|
return filepath.Join(c.Path, "storage", c.Sum[0:1], c.Sum[1:2])
|
|
}
|
|
|
|
func (c *Chunk) Filename() string {
|
|
return filepath.Join(c.Dir(), c.Sum)
|
|
}
|
|
|
|
func (c *Chunk) FileExists() bool {
|
|
fs, err := os.Stat(c.Filename())
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
return false
|
|
}
|
|
return !fs.IsDir()
|
|
}
|
|
|
|
func (c *Chunk) Mkdir() error {
|
|
return os.MkdirAll(c.Dir(), 0755)
|
|
}
|
|
|
|
func (c *Chunk) Save() error {
|
|
if c.FileExists() {
|
|
return photoserrors.ErrStoreChunkAlreadyExists
|
|
}
|
|
|
|
if err := c.Mkdir(); err != nil {
|
|
return err
|
|
}
|
|
|
|
fs, err := os.Create(c.Filename())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer fs.Close()
|
|
_, err = fs.Write(c.Bytes)
|
|
return err
|
|
}
|
|
|
|
func (s *Store) Combine(sumb []string) (string, uint64, error) {
|
|
sum := sha1.New()
|
|
size := uint64(0)
|
|
for _, sb := range sumb {
|
|
c, err := s.LoadChunk(sb)
|
|
if err != nil {
|
|
return "", 0, err
|
|
}
|
|
sum.Write(c.Bytes)
|
|
size += uint64(len(c.Bytes))
|
|
}
|
|
return hex.EncodeToString(sum.Sum(nil)), size, nil
|
|
}
|