Files
drive/apps/backend/internal/blob/fs_store.go

155 lines
3.1 KiB
Go
Raw Normal View History

2025-11-26 20:11:12 +00:00
package blob
import (
"context"
"io"
"os"
"path/filepath"
2025-11-28 22:31:00 +00:00
"github.com/get-drexa/drexa/internal/ioext"
2025-11-26 20:11:12 +00:00
)
var _ Store = &FSStore{}
type FSStore struct {
config FSStoreConfig
}
type FSStoreConfig struct {
2025-11-30 19:19:54 +00:00
Root string
2025-11-26 20:11:12 +00:00
}
func NewFSStore(config FSStoreConfig) *FSStore {
return &FSStore{config: config}
}
2025-11-29 18:39:21 +00:00
func (s *FSStore) Initialize(ctx context.Context) error {
return os.MkdirAll(s.config.Root, 0755)
}
2025-11-26 20:11:12 +00:00
func (s *FSStore) Put(ctx context.Context, key Key, reader io.Reader) error {
path := filepath.Join(s.config.Root, string(key))
err := os.MkdirAll(filepath.Dir(path), 0755)
if err != nil {
return err
}
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0644)
if err != nil {
if os.IsExist(err) {
return ErrConflict
}
return err
}
defer f.Close()
_, err = io.Copy(f, reader)
if err != nil {
_ = os.Remove(path)
return err
}
return nil
}
2025-11-28 22:31:00 +00:00
func (s *FSStore) Read(ctx context.Context, key Key) (io.ReadCloser, error) {
2025-11-26 20:11:12 +00:00
path := filepath.Join(s.config.Root, string(key))
f, err := os.Open(path)
if err != nil {
if os.IsNotExist(err) {
return nil, ErrNotFound
}
return nil, err
}
return f, nil
}
2025-11-28 22:31:00 +00:00
func (s *FSStore) ReadRange(ctx context.Context, key Key, offset, length int64) (io.ReadCloser, error) {
path := filepath.Join(s.config.Root, string(key))
f, err := os.Open(path)
if err != nil {
if os.IsNotExist(err) {
return nil, ErrNotFound
}
return nil, err
}
_, err = f.Seek(offset, io.SeekStart)
if err != nil {
return nil, err
}
return ioext.NewLimitReadCloser(f, length), nil
}
func (s *FSStore) ReadSize(ctx context.Context, key Key) (int64, error) {
path := filepath.Join(s.config.Root, string(key))
fi, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return 0, ErrNotFound
}
return 0, err
}
return fi.Size(), nil
}
2025-11-26 20:11:12 +00:00
func (s *FSStore) Delete(ctx context.Context, key Key) error {
err := os.Remove(filepath.Join(s.config.Root, string(key)))
// no op if file does not exist
// swallow error if file does not exist
if err != nil && !os.IsNotExist(err) {
return err
}
return nil
}
2025-11-30 01:16:44 +00:00
func (s *FSStore) DeletePrefix(ctx context.Context, prefix Key) error {
prefixPath := filepath.Join(s.config.Root, string(prefix))
err := os.RemoveAll(prefixPath)
if err != nil && !os.IsNotExist(err) {
return err
}
return nil
}
2025-11-28 22:31:00 +00:00
func (s *FSStore) Update(ctx context.Context, key Key, opts UpdateOptions) error {
// Update is a no-op for FSStore
return nil
}
2025-11-26 20:11:12 +00:00
func (s *FSStore) Move(ctx context.Context, srcKey, dstKey Key) error {
oldPath := filepath.Join(s.config.Root, string(srcKey))
newPath := filepath.Join(s.config.Root, string(dstKey))
_, err := os.Stat(newPath)
if err == nil {
return ErrConflict
}
err = os.MkdirAll(filepath.Dir(newPath), 0755)
if err != nil {
return err
}
err = os.Rename(oldPath, newPath)
if err != nil {
if os.IsNotExist(err) {
return ErrNotFound
}
return err
}
return nil
}
2025-11-30 19:19:54 +00:00
func (s *FSStore) SupportsDirectUpload() bool {
return false
}
func (s *FSStore) GenerateUploadURL(ctx context.Context, key Key, opts UploadURLOptions) (string, error) {
return "", nil
}