2025-03-28 19:57:44 +01:00

146 lines
4.3 KiB
Go

package strategy
import (
"backea/internal/backup/models"
"backea/internal/backup/strategy/kopia"
"backea/internal/logging"
"fmt"
"os"
"path/filepath"
"time"
)
// StrategyError represents an error in strategy operations
type StrategyError struct {
Message string
Cause error
}
func (e *StrategyError) Error() string {
if e.Cause != nil {
return e.Message + ": " + e.Cause.Error()
}
return e.Message
}
func (e *StrategyError) Unwrap() error {
return e.Cause
}
func NewStrategyError(message string, cause error) *StrategyError {
return &StrategyError{
Message: message,
Cause: cause,
}
}
// Factory handles backup strategy creation
type Factory struct {
Config *models.Configuration
ConfigPath string
logger *logging.Logger
}
// NewFactory initializes and returns a Factory
func NewFactory(configPath string) (*Factory, error) {
cfg, err := models.LoadConfig(configPath)
if err != nil {
return nil, NewStrategyError("failed to load config", err)
}
return &Factory{
Config: cfg,
ConfigPath: configPath,
logger: logging.GetLogger(),
}, nil
}
// CreateBackupStrategyForService returns a backup strategy based on config
func (f *Factory) CreateBackupStrategyForService(groupName, serviceIndex string) (Strategy, error) {
serviceConfig, err := f.getServiceConfig(groupName, serviceIndex)
if err != nil {
return nil, err
}
sourcePath, err := f.getServicePath(groupName)
if err != nil {
return nil, err
}
switch serviceConfig.BackupStrategy.Type {
case "kopia":
return f.createKopiaStrategy(serviceConfig, sourcePath)
default:
return nil, NewStrategyError(fmt.Sprintf("unknown strategy type: %s", serviceConfig.BackupStrategy.Type), nil)
}
}
// createKopiaStrategy initializes a Kopia strategy
func (f *Factory) createKopiaStrategy(serviceConfig *models.BackupConfig, sourcePath string) (Strategy, error) {
provider, err := f.createKopiaProvider(serviceConfig.BackupStrategy)
if err != nil {
return nil, NewStrategyError("failed to create kopia provider", err)
}
retention := kopia.Retention(serviceConfig.BackupStrategy.Retention)
configPath := generateTempConfigPath(provider.GetProviderType())
return kopia.NewStrategy(retention, provider, configPath, sourcePath), nil
}
// createKopiaProvider returns a Kopia storage provider
func (f *Factory) createKopiaProvider(strategyConfig models.StrategyConfig) (kopia.Provider, error) {
switch strategyConfig.Provider {
case "local":
return kopia.NewLocalProvider(strategyConfig.Destination.Path), nil
case "b2", "backblaze":
return kopia.NewB2Provider(), nil
case "sftp":
host := strategyConfig.Destination.Host
basepath := strategyConfig.Destination.Path
username := strategyConfig.Destination.Username
keyFile := strategyConfig.Destination.SSHKey
return kopia.NewSFTPProvider(host, basepath, username, keyFile), nil
default:
return nil, NewStrategyError(fmt.Sprintf("unknown kopia provider type: %s", strategyConfig.Provider), nil)
}
}
// getServicePath returns a service's path
func (f *Factory) getServicePath(groupName string) (string, error) {
if serviceGroup, exists := f.Config.Services[groupName]; exists {
return serviceGroup.Source.Path, nil
}
return "", NewStrategyError(fmt.Sprintf("service group not found: %s", groupName), nil)
}
// getServiceConfig returns a service's config
func (f *Factory) getServiceConfig(groupName, serviceIndex string) (*models.BackupConfig, error) {
if serviceGroup, exists := f.Config.Services[groupName]; exists {
if backupConfig, exists := serviceGroup.BackupConfigs[serviceIndex]; exists {
return &backupConfig, nil
}
return nil, NewStrategyError(fmt.Sprintf("service index not found: %s.%s", groupName, serviceIndex), nil)
}
return nil, NewStrategyError(fmt.Sprintf("service group not found: %s", groupName), nil)
}
// ReloadConfig reloads configuration
func (f *Factory) ReloadConfig() error {
cfg, err := models.LoadConfig(f.ConfigPath)
if err != nil {
return NewStrategyError("could not reload config", err)
}
f.Config = cfg
return nil
}
// generateTempConfigPath creates a temp Kopia config path
func generateTempConfigPath(providerType string) string {
tmpConfigDir := filepath.Join(os.TempDir(), "kopia_configs")
_ = os.MkdirAll(tmpConfigDir, 0755) // Ensure directory exists
return filepath.Join(tmpConfigDir, fmt.Sprintf("kopia_%s_%d.config", providerType, time.Now().UnixNano()))
}