first
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
package media
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// LocalStorage saves uploads under a directory on disk and serves them via
|
||||
// a static file route (mounted by main.go at /uploads when this driver is
|
||||
// active).
|
||||
type LocalStorage struct {
|
||||
dir string
|
||||
baseURL string
|
||||
}
|
||||
|
||||
func NewLocalStorage(dir, baseURL string) (*LocalStorage, error) {
|
||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
||||
return nil, fmt.Errorf("create upload dir: %w", err)
|
||||
}
|
||||
return &LocalStorage{dir: dir, baseURL: strings.TrimRight(baseURL, "/")}, nil
|
||||
}
|
||||
|
||||
func (s *LocalStorage) Save(_ context.Context, key string, reader io.Reader, _ int64, _ string) (string, error) {
|
||||
// key is always a freshly generated UUID-based name (see service.go),
|
||||
// never derived from user input, so path traversal is not reachable here.
|
||||
dest := filepath.Join(s.dir, filepath.Base(key))
|
||||
|
||||
f, err := os.OpenFile(dest, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("create file: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if _, err := io.Copy(f, reader); err != nil {
|
||||
return "", fmt.Errorf("write file: %w", err)
|
||||
}
|
||||
|
||||
return s.baseURL + "/" + filepath.Base(key), nil
|
||||
}
|
||||
|
||||
func (s *LocalStorage) Delete(_ context.Context, key string) error {
|
||||
err := os.Remove(filepath.Join(s.dir, filepath.Base(key)))
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return fmt.Errorf("delete file: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user