2022-05-02 09:35:49 +02:00

123 lines
2.1 KiB
Go

package photosstore
import (
"crypto/sha1"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"time"
"github.com/gin-gonic/gin"
)
var (
ErrStoreChunkAlreadyExists = errors.New("chunk file already exists")
)
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 := s.Chunk(sum)
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 (s *Store) Chunk(sum string) *Chunk {
return &Chunk{s, sum, 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) Size() int64 {
st, err := os.Stat(c.Filename())
if err != nil {
return -1
}
return st.Size()
}
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(login string) error {
if c.FileExists() {
return ErrStoreChunkAlreadyExists
}
if err := c.Mkdir(); err != nil {
return err
}
if err := os.WriteFile(c.Filename(), c.Bytes, 0666); err != nil {
return err
}
meta, err := os.Create(c.Filename() + ".json")
if err != nil {
return err
}
enc := json.NewEncoder(meta)
enc.SetIndent("", " ")
return enc.Encode(gin.H{
"author": login,
"date": time.Now().UTC().Format("2006-01-02 15:04:05"),
"checksum": c.Sum,
"size": len(c.Bytes),
})
}
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
}