package blobs import ( "context" "errors" "io" "nf-repo/internal/interfaces" "nf-repo/internal/model" "nf-repo/internal/opt" "os" "path" "sync" ) type localHandler struct { base string sync.Mutex } func (l *localHandler) path(hash model.Hash) string { //return path.Join(l.base, hash.Hex) dir := path.Join(l.base, hash.Hex[:2], hash.Hex[2:4]) _ = os.MkdirAll(dir, 0755) return path.Join(dir, hash.Hex) } func (l *localHandler) Get(ctx context.Context, repo string, hash model.Hash) (io.ReadCloser, error) { var ( err error f *os.File ) l.Lock() defer l.Unlock() if f, err = os.Open(l.path(hash)); err != nil { if errors.Is(err, os.ErrNotExist) { return nil, opt.ErrNotFound } return nil, err } return f, nil } func (l *localHandler) Stat(ctx context.Context, repo string, hash model.Hash) (int64, error) { var ( err error info os.FileInfo ) l.Lock() defer l.Unlock() if info, err = os.Stat(l.path(hash)); err != nil { if errors.Is(err, os.ErrNotExist) { return 0, opt.ErrNotFound } return 0, err } return info.Size(), nil } func (l *localHandler) Put(ctx context.Context, repo string, hash model.Hash, rc io.ReadCloser) error { var ( err error f *os.File ) l.Lock() defer l.Unlock() if f, err = os.OpenFile(l.path(hash), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644); err != nil { return err } if _, err = io.Copy(f, rc); err != nil { return err } return nil } func (l *localHandler) Delete(ctx context.Context, repo string, hash model.Hash) error { var ( err error info os.FileInfo filename = l.path(hash) ) l.Lock() defer l.Unlock() if info, err = os.Stat(filename); err != nil { if errors.Is(err, os.ErrNotExist) { return opt.ErrNotFound } return err } _ = info return os.Remove(filename) } func NewLocalBlobHandler(baseDir string) interfaces.BlobHandler { _ = os.MkdirAll(baseDir, 0755) return &localHandler{base: baseDir} }