package kopia import ( "context" "fmt" "log" "os" "os/exec" "strings" b2_client "backea/internal/client" ) // B2Provider implements the Provider interface for Backblaze B2 type B2Provider struct{} // NewB2Provider creates a new B2 provider func NewB2Provider() *B2Provider { return &B2Provider{} } // Connect connects to a B2 repository func (p *B2Provider) Connect(ctx context.Context, serviceName string, password string, configPath string) error { // Load environment variables for B2 credentials keyID := os.Getenv("B2_KEY_ID") applicationKey := os.Getenv("B2_APPLICATION_KEY") if keyID == "" || applicationKey == "" { return fmt.Errorf("B2_KEY_ID and B2_APPLICATION_KEY must be set in .env file") } bucketName := p.GetBucketName(serviceName) // Create B2 client and check if bucket exists, create if not B2Client, _ := b2_client.NewClientFromEnv() if B2Client == nil { return fmt.Errorf("B2 client not initialized") } _, err := B2Client.GetBucket(ctx, bucketName) if err != nil { log.Printf("Bucket %s not found, creating...", bucketName) _, err = B2Client.CreateBucket(ctx, bucketName, false) if err != nil { return fmt.Errorf("failed to create bucket: %w", err) } log.Printf("Created bucket: %s", bucketName) } // Try to connect to existing repository with config file connectCmd := exec.CommandContext( ctx, "kopia", "--config-file", configPath, "repository", "connect", "b2", "--bucket", bucketName, "--key-id", keyID, "--key", applicationKey, "--password", password, ) err = connectCmd.Run() if err != nil { // Connection failed, create new repository log.Printf("Creating new B2 repository for %s", serviceName) createCmd := exec.CommandContext( ctx, "kopia", "--config-file", configPath, "repository", "create", "b2", "--bucket", bucketName, "--key-id", keyID, "--key", applicationKey, "--password", password, ) createOutput, err := createCmd.CombinedOutput() if err != nil { return fmt.Errorf("failed to create repository: %w\nOutput: %s", err, createOutput) } } return nil } // GetRepositoryParams returns parameters for B2 operations func (p *B2Provider) GetRepositoryParams(serviceName string) ([]string, error) { keyID := os.Getenv("B2_KEY_ID") applicationKey := os.Getenv("B2_APPLICATION_KEY") if keyID == "" || applicationKey == "" { return nil, fmt.Errorf("B2_KEY_ID and B2_APPLICATION_KEY must be set in .env file") } bucketName := p.GetBucketName(serviceName) return []string{ "b2", "--bucket", bucketName, "--key-id", keyID, "--key", applicationKey, }, nil } // GetBucketName returns a bucket name for the service func (p *B2Provider) GetBucketName(serviceName string) string { // Backblaze doesn't allow dots in bucket names sanitized := strings.ReplaceAll(serviceName, ".", "-") // Add a prefix to make the bucket name unique return fmt.Sprintf("backea-%s", sanitized) } // GetProviderType returns the provider type identifier func (p *B2Provider) GetProviderType() string { return "b2" }