package app import ( "context" "fmt" "strconv" "gitea.maximumdirect.net/eric/distributor/internal/adapters/local" sshadapter "gitea.maximumdirect.net/eric/distributor/internal/adapters/ssh" "gitea.maximumdirect.net/eric/distributor/internal/config" "gitea.maximumdirect.net/eric/distributor/internal/storage" ) const storagePathKey = "path" const ( sshHostKey = "host" sshUserKey = "user" sshPortKey = "port" sshKeyFileKey = "ssh_key_file" sshKnownHostsKey = "known_hosts" sshHostKeyPolicyKey = "host_key_policy" ) type backendFactory struct { registry *storage.Registry } func newBackendFactory() *backendFactory { registry := storage.NewRegistry() _ = registry.Register(config.BackendLocal, func(ctx context.Context, cfg storage.OpenConfig) (storage.Backend, error) { if err := ctx.Err(); err != nil { return nil, err } return local.New(cfg[storagePathKey]) }) _ = registry.Register(config.BackendSSH, func(ctx context.Context, cfg storage.OpenConfig) (storage.Backend, error) { port, err := strconv.Atoi(cfg[sshPortKey]) if err != nil { return nil, fmt.Errorf("ssh port: %w", err) } return sshadapter.New(ctx, sshadapter.Options{ Host: cfg[sshHostKey], User: cfg[sshUserKey], Port: port, Root: cfg[storagePathKey], KeyFile: cfg[sshKeyFileKey], KnownHosts: cfg[sshKnownHostsKey], HostKeyPolicy: sshadapter.HostKeyPolicy(cfg[sshHostKeyPolicyKey]), }) }) return &backendFactory{registry: registry} } func (f *backendFactory) openSource(ctx context.Context, source config.Backend) (storage.Backend, error) { if source.Backend != config.BackendLocal && source.Backend != config.BackendSSH { return nil, fmt.Errorf("source backend %s is not implemented for execution", source.Backend) } return f.registry.Open(ctx, source.Backend, sourceOpenConfig(source)) } func (f *backendFactory) openDestination(ctx context.Context, destination config.Destination) (storage.Backend, error) { if destination.Backend != config.BackendLocal && destination.Backend != config.BackendSSH { return nil, fmt.Errorf("backend %s is not implemented for execution", destination.Backend) } return f.registry.Open(ctx, destination.Backend, destinationOpenConfig(destination)) } func (f *backendFactory) openLocalPath(ctx context.Context, path string) (storage.Backend, error) { return f.registry.Open(ctx, config.BackendLocal, storage.OpenConfig{storagePathKey: path}) } func sourceOpenConfig(source config.Backend) storage.OpenConfig { cfg := storage.OpenConfig{storagePathKey: source.Path} if source.Backend == config.BackendSSH { cfg[sshHostKey] = source.Host cfg[sshUserKey] = source.User cfg[sshPortKey] = strconv.Itoa(source.Port) cfg[sshKeyFileKey] = source.SSH.KeyFile cfg[sshKnownHostsKey] = source.SSH.KnownHosts cfg[sshHostKeyPolicyKey] = string(source.SSH.HostKeyPolicy) } return cfg } func destinationOpenConfig(destination config.Destination) storage.OpenConfig { cfg := storage.OpenConfig{storagePathKey: destination.Path} if destination.Backend == config.BackendSSH { cfg[sshHostKey] = destination.Host cfg[sshUserKey] = destination.User cfg[sshPortKey] = strconv.Itoa(destination.Port) cfg[sshKeyFileKey] = destination.SSH.KeyFile cfg[sshKnownHostsKey] = destination.SSH.KnownHosts cfg[sshHostKeyPolicyKey] = string(destination.SSH.HostKeyPolicy) } return cfg }