126 lines
3.0 KiB
Go
126 lines
3.0 KiB
Go
package miniostorage
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"net/http"
|
|
"path"
|
|
"strings"
|
|
|
|
"git.company.lan/gopkg/filestore/remote"
|
|
"github.com/minio/minio-go/v7"
|
|
"github.com/minio/minio-go/v7/pkg/credentials"
|
|
)
|
|
|
|
// Убеждаемся в том, что мы всегда реализуем интерфейс remote.Storage.
|
|
var _ remote.Storage = (*MinioStorage)(nil)
|
|
|
|
func init() {
|
|
remote.Register("minio", &MinioStorage{})
|
|
}
|
|
|
|
type MinioStorage struct {
|
|
ctx context.Context
|
|
client *minio.Client
|
|
cfg *Config
|
|
}
|
|
|
|
func (s *MinioStorage) NewStorage(ctx context.Context, connString string) (remote.Storage, error) {
|
|
cfg, err := NewConfig(connString)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
opts := &minio.Options{
|
|
Creds: credentials.NewStaticV4(cfg.AccessKeyID, cfg.SecretKey, cfg.Token),
|
|
Region: cfg.Region,
|
|
Secure: cfg.Secure,
|
|
}
|
|
|
|
client, err := minio.New(cfg.Endpoint, opts)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
s.ctx = ctx
|
|
s.client = client
|
|
s.cfg = cfg
|
|
|
|
return s, nil
|
|
}
|
|
|
|
func (s *MinioStorage) Create(name string, opts ...remote.Option) (io.WriteCloser, error) {
|
|
name = path.Join(s.cfg.Prefix, name)
|
|
|
|
return newMinioWriter(s.ctx, s.client, s.cfg.BucketName, name, opts...), nil
|
|
}
|
|
|
|
func (s *MinioStorage) Open(name string) (http.File, error) {
|
|
name = path.Join(s.cfg.Prefix, name)
|
|
|
|
obj, err := s.client.GetObject(s.ctx, s.cfg.BucketName, name, minio.GetObjectOptions{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &minioFileWrapper{Object: obj, name: name}, nil
|
|
}
|
|
|
|
func (s *MinioStorage) Remove(name string) error {
|
|
name = path.Join(s.cfg.Prefix, name)
|
|
|
|
return s.client.RemoveObject(s.ctx, s.cfg.BucketName, name, minio.RemoveObjectOptions{})
|
|
}
|
|
|
|
func (s *MinioStorage) Stat(name string) (remote.FileInfo, error) {
|
|
name = path.Join(s.cfg.Prefix, name)
|
|
|
|
info, err := s.client.StatObject(s.ctx, s.cfg.BucketName, name, minio.StatObjectOptions{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return newMinioFileInfo(info), nil
|
|
}
|
|
|
|
func (s *MinioStorage) Exists(name string) (bool, error) {
|
|
name = path.Join(s.cfg.Prefix, name)
|
|
|
|
// Сначала проверяем, является ли путь файлом
|
|
if ok, err := s.IsFile(name); err == nil && ok {
|
|
return true, nil
|
|
}
|
|
// Если не файл, то проверяем, является ли путь каталогом
|
|
return s.IsDir(name)
|
|
}
|
|
|
|
func (s *MinioStorage) IsDir(name string) (bool, error) {
|
|
name = path.Join(s.cfg.Prefix, name)
|
|
|
|
options := minio.ListObjectsOptions{
|
|
Prefix: strings.TrimRight(name, "/") + "/",
|
|
Recursive: false,
|
|
MaxKeys: 1,
|
|
}
|
|
objectChan := s.client.ListObjects(s.ctx, s.cfg.BucketName, options)
|
|
object, ok := <-objectChan
|
|
if !ok {
|
|
return false, nil
|
|
}
|
|
if object.Err != nil {
|
|
return false, object.Err
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (s *MinioStorage) IsFile(name string) (bool, error) {
|
|
name = path.Join(s.cfg.Prefix, name)
|
|
|
|
_, err := s.client.StatObject(s.ctx, s.cfg.BucketName, name, minio.StatObjectOptions{})
|
|
if err == nil {
|
|
return true, nil
|
|
}
|
|
if strings.Contains(err.Error(), "The specified key does not exist.") {
|
|
return false, nil
|
|
}
|
|
return false, err
|
|
}
|