2022-07-13 06:26:42 +02:00
|
|
|
package storage
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
// LocalStorage is a local storage
|
|
|
|
type LocalStorage struct {
|
|
|
|
Storage
|
|
|
|
basedir string
|
|
|
|
logger *log.Logger
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewLocalStorage is the factory for LocalStorage
|
|
|
|
func NewLocalStorage(basedir string, logger *log.Logger) (*LocalStorage, error) {
|
|
|
|
return &LocalStorage{basedir: basedir, logger: logger}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Type returns the storage type
|
|
|
|
func (s *LocalStorage) Type() string {
|
|
|
|
return "local"
|
|
|
|
}
|
|
|
|
|
|
|
|
// Head retrieves content length of a file from storage
|
2022-07-14 18:02:18 +02:00
|
|
|
func (s *LocalStorage) Head(_ context.Context, token string, filename string) (contentLength uint64, err error) {
|
2022-07-13 06:26:42 +02:00
|
|
|
path := filepath.Join(s.basedir, token, filename)
|
|
|
|
|
|
|
|
var fi os.FileInfo
|
|
|
|
if fi, err = os.Lstat(path); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
contentLength = uint64(fi.Size())
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get retrieves a file from storage
|
2022-07-14 18:02:18 +02:00
|
|
|
func (s *LocalStorage) Get(_ context.Context, token string, filename string) (reader io.ReadCloser, contentLength uint64, err error) {
|
2022-07-13 06:26:42 +02:00
|
|
|
path := filepath.Join(s.basedir, token, filename)
|
|
|
|
|
|
|
|
// content type , content length
|
|
|
|
if reader, err = os.Open(path); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var fi os.FileInfo
|
|
|
|
if fi, err = os.Lstat(path); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
contentLength = uint64(fi.Size())
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete removes a file from storage
|
2022-07-14 18:02:18 +02:00
|
|
|
func (s *LocalStorage) Delete(_ context.Context, token string, filename string) (err error) {
|
2022-07-13 06:26:42 +02:00
|
|
|
metadata := filepath.Join(s.basedir, token, fmt.Sprintf("%s.metadata", filename))
|
|
|
|
_ = os.Remove(metadata)
|
|
|
|
|
|
|
|
path := filepath.Join(s.basedir, token, filename)
|
|
|
|
err = os.Remove(path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Purge cleans up the storage
|
2022-07-14 18:02:18 +02:00
|
|
|
func (s *LocalStorage) Purge(_ context.Context, days time.Duration) (err error) {
|
2022-07-13 06:26:42 +02:00
|
|
|
err = filepath.Walk(s.basedir,
|
|
|
|
func(path string, info os.FileInfo, err error) error {
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if info.IsDir() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if info.ModTime().Before(time.Now().Add(-1 * days)) {
|
|
|
|
err = os.Remove(path)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsNotExist indicates if a file doesn't exist on storage
|
|
|
|
func (s *LocalStorage) IsNotExist(err error) bool {
|
|
|
|
if err == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return os.IsNotExist(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Put saves a file on storage
|
2022-07-14 18:02:18 +02:00
|
|
|
func (s *LocalStorage) Put(_ context.Context, token string, filename string, reader io.Reader, contentType string, contentLength uint64) error {
|
2022-07-13 06:26:42 +02:00
|
|
|
var f io.WriteCloser
|
|
|
|
var err error
|
|
|
|
|
|
|
|
path := filepath.Join(s.basedir, token)
|
|
|
|
|
|
|
|
if err = os.MkdirAll(path, 0700); err != nil && !os.IsExist(err) {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
f, err = os.OpenFile(filepath.Join(path, filename), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
|
|
|
|
defer CloseCheck(f.Close)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err = io.Copy(f, reader); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|