81 lines
1.7 KiB
Go
81 lines
1.7 KiB
Go
package fsblob
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"nano-run/services/blob"
|
|
)
|
|
|
|
// Dummy file storage: large storage based on file system.
|
|
// ID - just name of file, but content will be written atomically.
|
|
func New(rootDir string) blob.Blob {
|
|
return &fsBlob{
|
|
rootDir: rootDir,
|
|
checker: func(id string) bool {
|
|
return true
|
|
},
|
|
}
|
|
}
|
|
|
|
func NewCheck(rootDir string, checkFn func(string) bool) blob.Blob {
|
|
return &fsBlob{
|
|
rootDir: rootDir,
|
|
checker: checkFn,
|
|
}
|
|
}
|
|
|
|
type fsBlob struct {
|
|
rootDir string
|
|
checker func(id string) bool
|
|
}
|
|
|
|
func (k *fsBlob) Push(id string, handler func(out io.Writer) error) error {
|
|
if !k.checker(id) {
|
|
return fmt.Errorf("push: invalid id %s", id)
|
|
}
|
|
dir := filepath.Join(k.rootDir, id[0:1])
|
|
err := os.MkdirAll(dir, 0755)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
tempFile := filepath.Join(dir, id+".temp")
|
|
destFile := filepath.Join(dir, id)
|
|
|
|
tempF, err := os.Create(tempFile)
|
|
if err != nil {
|
|
return fmt.Errorf("fsblob: put data: create temp file: %w", err)
|
|
}
|
|
err = handler(tempF)
|
|
flushErr := tempF.Close()
|
|
if err != nil {
|
|
_ = os.Remove(tempFile)
|
|
return err
|
|
}
|
|
if flushErr != nil {
|
|
_ = os.Remove(tempFile)
|
|
return fmt.Errorf("fsblob: put data: flush content to temp file: %w", err)
|
|
}
|
|
|
|
err = os.Rename(tempFile, destFile)
|
|
if err != nil {
|
|
return fmt.Errorf("fsblob: put data: commit file: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (k *fsBlob) Get(id string) (io.ReadCloser, error) {
|
|
if !k.checker(id) {
|
|
return nil, fmt.Errorf("get: invalid id %s", id)
|
|
}
|
|
dir := filepath.Join(k.rootDir, id[0:1])
|
|
destFile := filepath.Join(dir, id)
|
|
f, err := os.Open(destFile)
|
|
if err == nil {
|
|
return f, nil
|
|
}
|
|
return nil, fmt.Errorf("fsblob: get file: %w", err)
|
|
}
|