fsys/storage.go

167 lines
3.6 KiB
Go
Raw Normal View History

2024-11-17 16:00:48 +01:00
package fsys
import (
2024-11-18 22:34:07 +01:00
"bytes"
"context"
2024-11-17 16:00:48 +01:00
"errors"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
2024-11-18 22:39:35 +01:00
"io"
2024-11-18 22:34:07 +01:00
"net/http"
"os"
"path/filepath"
"strings"
2024-11-17 16:00:48 +01:00
)
var (
ErrInvalidStorageType = errors.New("invalid storage type")
ErrInvalidPath = errors.New("invalid path")
ErrFileNotFound = errors.New("file not found")
)
type Storage struct {
config *Config
s3Client *minio.Client
2024-11-18 22:34:07 +01:00
ctx context.Context
2024-11-17 16:00:48 +01:00
}
type Config struct {
Type string
Path string
S3Endpoint string
S3Location string
S3Secure bool
S3AccessID string
S3AccessKey string
S3BucketName string
}
func New(config *Config) (*Storage, error) {
newStorage := new(Storage)
newStorage.config = config
2024-11-18 22:34:07 +01:00
newStorage.ctx = context.Background()
2024-11-17 16:00:48 +01:00
switch config.Type {
case "minio", "s3":
s3Client, err := minio.New(config.S3Endpoint, &minio.Options{
Creds: credentials.NewStaticV4(config.S3AccessID, config.S3AccessKey, ""),
Secure: config.S3Secure,
})
if err != nil {
return nil, err
}
2024-11-18 22:34:07 +01:00
bucketExists, err := s3Client.BucketExists(newStorage.ctx, config.S3BucketName)
if err != nil {
return nil, err
}
if !bucketExists {
if err := s3Client.MakeBucket(newStorage.ctx, config.S3BucketName, minio.MakeBucketOptions{}); err != nil {
return nil, err
}
}
2024-11-17 16:00:48 +01:00
newStorage.s3Client = s3Client
case "local":
2024-11-18 22:34:07 +01:00
if err := os.MkdirAll(config.Path, 0740); err != nil {
return nil, err
}
2024-11-17 16:00:48 +01:00
default:
return nil, ErrInvalidStorageType
}
return newStorage, nil
}
2024-11-18 22:34:07 +01:00
func (s *Storage) Open(name string) (*File, error) {
returnFile := new(File)
returnFile.storage = s
if s.s3Client != nil {
object, err := s.s3Client.GetObject(s.ctx, s.config.S3BucketName, name, minio.GetObjectOptions{})
if err != nil {
errResp := minio.ToErrorResponse(err)
if errResp.StatusCode == http.StatusNotFound {
return nil, ErrFileNotFound
} else {
return nil, err
}
}
objectStat, err := object.Stat()
if err != nil {
errResp := minio.ToErrorResponse(err)
if errResp.StatusCode == http.StatusNotFound {
return nil, ErrFileNotFound
} else {
return nil, err
}
}
returnFile.Name = objectStat.Key
returnFile.file = object
} else {
if _, err := os.Stat(filepath.Join(s.config.Path, name)); err != nil && os.IsNotExist(err) {
return nil, ErrFileNotFound
} else if err != nil {
return nil, err
}
file, err := os.Open(filepath.Join(s.config.Path, name))
if err != nil {
return nil, err
}
returnFile.file = file
cutStr, _ := strings.CutPrefix(file.Name(), filepath.Clean(s.config.Path)+"/")
returnFile.Name = cutStr
}
return returnFile, nil
}
func (s *Storage) Read(name string) ([]byte, error) {
if s.s3Client != nil {
object, err := s.s3Client.GetObject(s.ctx, s.config.S3BucketName, name, minio.GetObjectOptions{})
if err != nil {
errResp := minio.ToErrorResponse(err)
if errResp.StatusCode == http.StatusNotFound {
return nil, ErrFileNotFound
} else {
return nil, err
}
}
2024-11-18 22:39:35 +01:00
objectBytes, err := io.ReadAll(object)
if err != nil {
2024-11-18 22:34:07 +01:00
return nil, err
}
2024-11-18 22:39:35 +01:00
2024-11-18 22:34:07 +01:00
return objectBytes, nil
} else {
return os.ReadFile(filepath.Join(s.config.Path, name))
}
}
type WriteOptions struct {
S3Tags map[string]string
}
func (s *Storage) Write(name string, data []byte, opts WriteOptions) error {
if s.s3Client != nil {
if _, err := s.s3Client.PutObject(s.ctx, s.config.S3BucketName, name, bytes.NewReader(data), int64(len(data)), minio.PutObjectOptions{
UserTags: opts.S3Tags,
}); err != nil {
return err
}
return nil
} else {
return os.WriteFile(filepath.Join(s.config.Path, name), data, 0640)
}
}