123 lines
2.1 KiB
Go
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
|
|
}
|