mirror of
https://github.com/get-drexa/drive.git
synced 2025-11-30 21:41:39 +00:00
feat: impl fs backed blob store
This commit is contained in:
8
apps/backend/internal/blob/err.go
Normal file
8
apps/backend/internal/blob/err.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package blob
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrConflict = errors.New("key already used for a different blob")
|
||||||
|
ErrNotFound = errors.New("key not found")
|
||||||
|
)
|
||||||
95
apps/backend/internal/blob/fs_store.go
Normal file
95
apps/backend/internal/blob/fs_store.go
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
package blob
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ Store = &FSStore{}
|
||||||
|
|
||||||
|
type FSStore struct {
|
||||||
|
config FSStoreConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type FSStoreConfig struct {
|
||||||
|
Root string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFSStore(config FSStoreConfig) *FSStore {
|
||||||
|
return &FSStore{config: config}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FSStore) Retrieve(ctx context.Context, key Key) (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
|
||||||
|
}
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
3
apps/backend/internal/blob/key.go
Normal file
3
apps/backend/internal/blob/key.go
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
package blob
|
||||||
|
|
||||||
|
type Key string
|
||||||
13
apps/backend/internal/blob/store.go
Normal file
13
apps/backend/internal/blob/store.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package blob
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Store interface {
|
||||||
|
Put(ctx context.Context, key Key, reader io.Reader) error
|
||||||
|
Retrieve(ctx context.Context, key Key) (io.ReadCloser, error)
|
||||||
|
Delete(ctx context.Context, key Key) error
|
||||||
|
Move(ctx context.Context, srcKey, dstKey Key) error
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user