2024-04-10 22:10:09 +08:00
|
|
|
package blobs
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
|
|
|
"io"
|
|
|
|
"nf-repo/internal/interfaces"
|
|
|
|
"nf-repo/internal/model"
|
|
|
|
"nf-repo/internal/opt"
|
2024-04-15 18:02:54 +08:00
|
|
|
"nf-repo/internal/verify"
|
2024-04-10 22:10:09 +08:00
|
|
|
"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
|
2024-04-15 18:02:54 +08:00
|
|
|
sp = l.path(hash)
|
2024-04-10 22:10:09 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
l.Lock()
|
|
|
|
defer l.Unlock()
|
|
|
|
|
2024-04-15 18:02:54 +08:00
|
|
|
if info, err = os.Stat(sp); err != nil {
|
2024-04-10 22:10:09 +08:00
|
|
|
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
|
2024-04-15 18:02:54 +08:00
|
|
|
nrc io.ReadCloser
|
2024-04-10 22:10:09 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
l.Lock()
|
|
|
|
defer l.Unlock()
|
|
|
|
|
2024-04-15 18:02:54 +08:00
|
|
|
if nrc, err = verify.ReadCloser(rc, verify.SizeUnknown, hash); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer nrc.Close()
|
|
|
|
|
2024-04-10 22:10:09 +08:00
|
|
|
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}
|
|
|
|
}
|