func (a App) WriterTo(pathname string) (io.WriteCloser, error) {
	reader, writer := io.Pipe()
	go func() {
		if _, err := a.client.PutObject(context.Background(), a.bucket, getPath(pathname), reader, -1, minio.PutObjectOptions{}); err != nil {
			if closeErr := writer.Close(); closeErr != nil {
				err = fmt.Errorf("%s: %w", err, closeErr)
			}
			logger.Error("unable to put object: %s", err)
		}
	}()
	return writer, nil
}
WriterTo opens writer for given pathname
package s3
import (
	"context"
	"flag"
	"fmt"
	"io"
	"path"
	"sort"
	"strings"
	"time"
	"github.com/ViBiOh/fibr/pkg/provider"
	"github.com/ViBiOh/httputils/v4/pkg/flags"
	"github.com/ViBiOh/httputils/v4/pkg/logger"
	"github.com/minio/minio-go/v7"
	"github.com/minio/minio-go/v7/pkg/credentials"
)
type App struct {
	ignoreFn func(provider.StorageItem) bool
	bucket   string
	client   *minio.Client
}
type Config struct {
	endpoint     *string
	accessKey    *string
	secretAccess *string
	bucket       *string
	useSSL       *bool
}
func Flags(fs *flag.FlagSet, prefix string, overrides ...flags.Override) Config {
	return Config{
		endpoint:     flags.New(prefix, "s3", "Endpoint").Default("", overrides).Label("Storage Object endpoint").ToString(fs),
		accessKey:    flags.New(prefix, "s3", "AccessKey").Default("", overrides).Label("Storage Object Access Key").ToString(fs),
		secretAccess: flags.New(prefix, "s3", "SecretAccess").Default("", overrides).Label("Storage Object Secret Access").ToString(fs),
		bucket:       flags.New(prefix, "s3", "Bucket").Default("", overrides).Label("Storage Object Bucket").ToString(fs),
		useSSL:       flags.New(prefix, "s3", "SSL").Default(true, overrides).Label("Use SSL").ToBool(fs),
	}
}
func New(config Config) (App, error) {
	if len(*config.endpoint) == 0 {
		return App{}, nil
	}
	client, err := minio.New(*config.endpoint, &minio.Options{
		Creds:  credentials.NewStaticV4(*config.accessKey, *config.secretAccess, ""),
		Secure: *config.useSSL,
	})
	if err != nil {
		return App{}, fmt.Errorf("unable to create minio client: %s", err)
	}
	return App{
		client: client,
		bucket: *config.bucket,
	}, nil
}
func (a App) Enabled() bool {
	return a.client != nil
}
func (a App) WithIgnoreFn(ignoreFn func(provider.StorageItem) bool) provider.Storage {
	a.ignoreFn = ignoreFn
	return a
}
func (a App) Info(pathname string) (provider.StorageItem, error) {
	realPathname := getPath(pathname)
	if realPathname == "" {
		return provider.StorageItem{
			Name:     "/",
			Pathname: "/",
			IsDir:    true,
		}, nil
	}
	info, err := a.client.StatObject(context.Background(), a.bucket, realPathname, minio.GetObjectOptions{})
	if err != nil {
		return provider.StorageItem{}, convertError(fmt.Errorf("unable to stat object: %s", err))
	}
	return convertToItem(info), nil
}
func (a App) List(pathname string) ([]provider.StorageItem, error) {
	realPathname := getPath(pathname)
	baseRealPathname := path.Base(realPathname)
	objectsCh := a.client.ListObjects(context.Background(), a.bucket, minio.ListObjectsOptions{
		Prefix: realPathname,
	})
	var items []provider.StorageItem
	for object := range objectsCh {
		item := convertToItem(object)
		if item.IsDir && item.Name == baseRealPathname {
			continue
		}
		if a.ignoreFn != nil && a.ignoreFn(item) {
			continue
		}
		items = append(items, item)
	}
	sort.Sort(provider.ByHybridSort(items))
	return items, nil
}