func provideFactory(option *providersOption) func(p factoryIn) Factory {
	if option.ctor == nil {
		option.ctor = newManager
	}
	return func(p factoryIn) Factory {
		factory := di.NewFactory(func(name string) (di.Pair, error) {
			var conf S3Config
			if err := p.Conf.Unmarshal(fmt.Sprintf("s3.%s", name), &conf); err != nil {
				if name != "default" {
					return di.Pair{}, fmt.Errorf("s3 configuration %s not found", name)
				}
				conf = S3Config{}
			}
			manager, err := option.ctor(ManagerArgs{
				Name:      name,
				Conf:      conf,
				Populator: p.Populator,
			})
			if err != nil {
				return di.Pair{}, fmt.Errorf("error constructing manager: %w", err)
			}
			return di.Pair{
				Closer: nil,
				Conn:   manager,
			}, nil
		})
		s3Factory := Factory{factory}
		if option.reloadable {
			s3Factory.SubscribeReloadEventFrom(p.Dispatcher)
		}
		return s3Factory
	}
}
provideFactory creates *Factory and *ots3.Manager. It is a valid dependency for package core.
package ots3
import (
	"context"
	"fmt"
	"io"
	"net/url"
	"github.com/DoNewsCode/core/config"
	"github.com/DoNewsCode/core/contract"
	"github.com/DoNewsCode/core/di"
	"github.com/go-kit/log"
	"github.com/opentracing/opentracing-go"
)
func Providers(optionFunc ...ProvidersOptionFunc) di.Deps {
	option := providersOption{
		ctor: newManager,
	}
	for _, f := range optionFunc {
		f(&option)
	}
	return di.Deps{provideFactory(&option), provideManager, provideConfig}
}
type Uploader interface {
	Upload(ctx context.Context, name string, reader io.Reader) (string, error)
}
type S3Config struct {
	AccessKey    string `json:"accessKey" yaml:"accessKey"`
	AccessSecret string `json:"accessSecret" yaml:"accessSecret"`
	Endpoint     string `json:"endpoint" yaml:"endpoint"`
	Region       string `json:"region" yaml:"region"`
	Bucket       string `json:"bucket" yaml:"bucket"`
	CdnUrl       string `json:"cdnUrl" yaml:"cdnUrl"`
}
type factoryIn struct {
	di.In
	Logger     log.Logger
	Conf       contract.ConfigUnmarshaler
	Populator  contract.DIPopulator `optional:"true"`
	Dispatcher contract.Dispatcher  `optional:"true"`
}