package location import ( "context" "net/http" "github.com/restic/restic/internal/backend" "github.com/restic/restic/internal/backend/limiter" ) type Registry struct { factories map[string]Factory } func NewRegistry() *Registry { return &Registry{ factories: make(map[string]Factory), } } func (r *Registry) Register(factory Factory) { if r.factories[factory.Scheme()] != nil { panic("duplicate backend") } r.factories[factory.Scheme()] = factory } func (r *Registry) Lookup(scheme string) Factory { return r.factories[scheme] } type Factory interface { Scheme() string ParseConfig(s string) (any, error) StripPassword(s string) string Create(ctx context.Context, cfg any, rt http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...any)) (backend.Backend, error) Open(ctx context.Context, cfg any, rt http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...any)) (backend.Backend, error) } type genericBackendFactory[C any, T backend.Backend] struct { scheme string parseConfigFn func(s string) (*C, error) stripPasswordFn func(s string) string createFn func(ctx context.Context, cfg C, rt http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...any)) (T, error) openFn func(ctx context.Context, cfg C, rt http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...any)) (T, error) } func (f *genericBackendFactory[C, T]) Scheme() string { return f.scheme } func (f *genericBackendFactory[C, T]) ParseConfig(s string) (any, error) { return f.parseConfigFn(s) } func (f *genericBackendFactory[C, T]) StripPassword(s string) string { if f.stripPasswordFn != nil { return f.stripPasswordFn(s) } return s } func (f *genericBackendFactory[C, T]) Create(ctx context.Context, cfg any, rt http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...any)) (backend.Backend, error) { return f.createFn(ctx, *cfg.(*C), rt, lim, errorLog) } func (f *genericBackendFactory[C, T]) Open(ctx context.Context, cfg any, rt http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...any)) (backend.Backend, error) { return f.openFn(ctx, *cfg.(*C), rt, lim, errorLog) } func NewHTTPBackendFactory[C any, T backend.Backend]( scheme string, parseConfigFn func(s string) (*C, error), stripPasswordFn func(s string) string, createFn func(ctx context.Context, cfg C, rt http.RoundTripper, errorLog func(string, ...any)) (T, error), openFn func(ctx context.Context, cfg C, rt http.RoundTripper, errorLog func(string, ...any)) (T, error)) Factory { return &genericBackendFactory[C, T]{ scheme: scheme, parseConfigFn: parseConfigFn, stripPasswordFn: stripPasswordFn, createFn: func(ctx context.Context, cfg C, rt http.RoundTripper, _ limiter.Limiter, errorLog func(string, ...any)) (T, error) { return createFn(ctx, cfg, rt, errorLog) }, openFn: func(ctx context.Context, cfg C, rt http.RoundTripper, _ limiter.Limiter, errorLog func(string, ...any)) (T, error) { return openFn(ctx, cfg, rt, errorLog) }, } } func NewLimitedBackendFactory[C any, T backend.Backend]( scheme string, parseConfigFn func(s string) (*C, error), stripPasswordFn func(s string) string, createFn func(ctx context.Context, cfg C, lim limiter.Limiter, errorLog func(string, ...any)) (T, error), openFn func(ctx context.Context, cfg C, lim limiter.Limiter, errorLog func(string, ...any)) (T, error)) Factory { return &genericBackendFactory[C, T]{ scheme: scheme, parseConfigFn: parseConfigFn, stripPasswordFn: stripPasswordFn, createFn: func(ctx context.Context, cfg C, _ http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...any)) (T, error) { return createFn(ctx, cfg, lim, errorLog) }, openFn: func(ctx context.Context, cfg C, _ http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...any)) (T, error) { return openFn(ctx, cfg, lim, errorLog) }, } }