package storage import ( "context" "fmt" "strings" "git.eeqj.de/sneak/vaultik/internal/config" "git.eeqj.de/sneak/vaultik/internal/s3" "go.uber.org/fx" ) // Module exports storage functionality as an fx module. // It provides a Storer implementation based on the configured storage URL // or falls back to legacy S3 configuration. var Module = fx.Module("storage", fx.Provide(NewStorer), ) // NewStorer creates a Storer based on configuration. // If StorageURL is set, it uses URL-based configuration. // Otherwise, it falls back to legacy S3 configuration. func NewStorer(cfg *config.Config) (Storer, error) { if cfg.StorageURL != "" { return storerFromURL(cfg.StorageURL, cfg) } return storerFromLegacyS3Config(cfg) } func storerFromURL(rawURL string, cfg *config.Config) (Storer, error) { parsed, err := ParseStorageURL(rawURL) if err != nil { return nil, fmt.Errorf("parsing storage URL: %w", err) } switch parsed.Scheme { case "file": return NewFileStorer(parsed.Prefix) case "s3": // Build endpoint URL endpoint := parsed.Endpoint if endpoint == "" { endpoint = "s3.amazonaws.com" } // Add protocol if not present if parsed.UseSSL && !strings.HasPrefix(endpoint, "https://") && !strings.HasPrefix(endpoint, "http://") { endpoint = "https://" + endpoint } else if !parsed.UseSSL && !strings.HasPrefix(endpoint, "http://") && !strings.HasPrefix(endpoint, "https://") { endpoint = "http://" + endpoint } region := parsed.Region if region == "" { region = cfg.S3.Region if region == "" { region = "us-east-1" } } // Credentials come from config (not URL for security) client, err := s3.NewClient(context.Background(), s3.Config{ Endpoint: endpoint, Bucket: parsed.Bucket, Prefix: parsed.Prefix, AccessKeyID: cfg.S3.AccessKeyID, SecretAccessKey: cfg.S3.SecretAccessKey, Region: region, }) if err != nil { return nil, fmt.Errorf("creating S3 client: %w", err) } return NewS3Storer(client), nil default: return nil, fmt.Errorf("unsupported storage scheme: %s", parsed.Scheme) } } func storerFromLegacyS3Config(cfg *config.Config) (Storer, error) { endpoint := cfg.S3.Endpoint // Ensure protocol is present if !strings.HasPrefix(endpoint, "http://") && !strings.HasPrefix(endpoint, "https://") { if cfg.S3.UseSSL { endpoint = "https://" + endpoint } else { endpoint = "http://" + endpoint } } region := cfg.S3.Region if region == "" { region = "us-east-1" } client, err := s3.NewClient(context.Background(), s3.Config{ Endpoint: endpoint, Bucket: cfg.S3.Bucket, Prefix: cfg.S3.Prefix, AccessKeyID: cfg.S3.AccessKeyID, SecretAccessKey: cfg.S3.SecretAccessKey, Region: region, }) if err != nil { return nil, fmt.Errorf("creating S3 client: %w", err) } return NewS3Storer(client), nil }