mirror of
https://github.com/Awuqing/BackupX.git
synced 2026-09-05 07:26:43 +08:00
refactor: simplify architecture and harden lifecycle
Remove obsolete implementations, centralize background task ownership and terminal-state recovery, consolidate frontend routing and log streaming, and enforce project-wide verification in CI.
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
package rclone
|
||||
|
||||
import "backupx/server/internal/storage"
|
||||
|
||||
// NewDefaultRegistry returns the storage factory set shared by Master, Agent,
|
||||
// and the standalone Backint process.
|
||||
func NewDefaultRegistry() *storage.Registry {
|
||||
registry := storage.NewRegistry(
|
||||
NewLocalDiskFactory(),
|
||||
NewS3Factory(),
|
||||
NewWebDAVFactory(),
|
||||
NewGoogleDriveFactory(),
|
||||
NewAliyunOSSFactory(),
|
||||
NewTencentCOSFactory(),
|
||||
NewQiniuKodoFactory(),
|
||||
NewFTPFactory(),
|
||||
NewRcloneFactory(),
|
||||
)
|
||||
RegisterAllBackends(registry)
|
||||
return registry
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
@@ -10,26 +9,6 @@ import (
|
||||
"backupx/server/internal/apperror"
|
||||
)
|
||||
|
||||
type providerFactoryWithNew interface {
|
||||
New(context.Context, map[string]any) (StorageProvider, error)
|
||||
}
|
||||
|
||||
type providerFactoryWithCreate interface {
|
||||
Create(context.Context, json.RawMessage) (StorageProvider, error)
|
||||
}
|
||||
|
||||
type providerFactoryWithSensitiveFields interface {
|
||||
SensitiveFields() []string
|
||||
}
|
||||
|
||||
type providerFactoryWithSensitiveKeys interface {
|
||||
SensitiveKeys() []string
|
||||
}
|
||||
|
||||
type providerFactoryWithValidate interface {
|
||||
Validate(json.RawMessage) error
|
||||
}
|
||||
|
||||
type Registry struct {
|
||||
mu sync.RWMutex
|
||||
factories map[ProviderType]ProviderFactory
|
||||
@@ -78,115 +57,20 @@ func (r *Registry) SensitiveFields(providerType string) []string {
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if typed, ok := factory.(providerFactoryWithSensitiveFields); ok {
|
||||
return typed.SensitiveFields()
|
||||
}
|
||||
if typed, ok := factory.(providerFactoryWithSensitiveKeys); ok {
|
||||
return typed.SensitiveKeys()
|
||||
}
|
||||
return nil
|
||||
return factory.SensitiveFields()
|
||||
}
|
||||
|
||||
func (r *Registry) SensitiveKeys(providerType string) []string {
|
||||
return r.SensitiveFields(providerType)
|
||||
}
|
||||
|
||||
func (r *Registry) Validate(providerType string, raw json.RawMessage) error {
|
||||
factory, ok := r.Factory(providerType)
|
||||
if !ok {
|
||||
return apperror.BadRequest("STORAGE_PROVIDER_UNSUPPORTED", "不支持的存储类型", fmt.Errorf("unsupported storage provider type: %s", providerType))
|
||||
}
|
||||
if typed, ok := factory.(providerFactoryWithValidate); ok {
|
||||
if err := typed.Validate(raw); err != nil {
|
||||
return apperror.BadRequest("STORAGE_TARGET_INVALID_CONFIG", "存储目标配置不合法", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
configMap, err := decodeConfigMap(raw)
|
||||
if err != nil {
|
||||
return apperror.BadRequest("STORAGE_TARGET_INVALID_CONFIG", "存储目标配置不合法", err)
|
||||
}
|
||||
if typed, ok := factory.(providerFactoryWithNew); ok {
|
||||
if _, err := typed.New(context.Background(), configMap); err != nil {
|
||||
return apperror.BadRequest("STORAGE_TARGET_INVALID_CONFIG", "存储目标配置不合法", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return apperror.BadRequest("STORAGE_TARGET_INVALID_CONFIG", "存储目标配置不合法", fmt.Errorf("provider %s has no validator", providerType))
|
||||
}
|
||||
|
||||
func (r *Registry) Create(ctx context.Context, providerType string, rawConfig any) (StorageProvider, error) {
|
||||
func (r *Registry) Create(ctx context.Context, providerType string, config map[string]any) (StorageProvider, error) {
|
||||
factory, ok := r.Factory(providerType)
|
||||
if !ok {
|
||||
return nil, apperror.BadRequest("STORAGE_PROVIDER_UNSUPPORTED", "不支持的存储类型", fmt.Errorf("unsupported storage provider type: %s", providerType))
|
||||
}
|
||||
raw, configMap, err := normalizeConfig(rawConfig)
|
||||
if config == nil {
|
||||
config = map[string]any{}
|
||||
}
|
||||
provider, err := factory.New(ctx, config)
|
||||
if err != nil {
|
||||
return nil, apperror.BadRequest("STORAGE_TARGET_INVALID_CONFIG", "存储目标配置不合法", err)
|
||||
return nil, apperror.BadRequest("STORAGE_TARGET_INVALID_CONFIG", "无法创建存储客户端", err)
|
||||
}
|
||||
if typed, ok := factory.(providerFactoryWithNew); ok {
|
||||
provider, err := typed.New(ctx, configMap)
|
||||
if err != nil {
|
||||
return nil, apperror.BadRequest("STORAGE_TARGET_INVALID_CONFIG", "无法创建存储客户端", err)
|
||||
}
|
||||
return provider, nil
|
||||
}
|
||||
if typed, ok := factory.(providerFactoryWithCreate); ok {
|
||||
provider, err := typed.Create(ctx, raw)
|
||||
if err != nil {
|
||||
return nil, apperror.BadRequest("STORAGE_TARGET_INVALID_CONFIG", "无法创建存储客户端", err)
|
||||
}
|
||||
return provider, nil
|
||||
}
|
||||
return nil, apperror.BadRequest("STORAGE_TARGET_INVALID_CONFIG", "无法创建存储客户端", fmt.Errorf("provider %s has no constructor", providerType))
|
||||
}
|
||||
|
||||
func normalizeConfig(rawConfig any) (json.RawMessage, map[string]any, error) {
|
||||
switch value := rawConfig.(type) {
|
||||
case nil:
|
||||
return json.RawMessage("{}"), map[string]any{}, nil
|
||||
case map[string]any:
|
||||
raw, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("marshal config: %w", err)
|
||||
}
|
||||
return raw, value, nil
|
||||
case json.RawMessage:
|
||||
configMap, err := decodeConfigMap(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return value, configMap, nil
|
||||
case []byte:
|
||||
raw := json.RawMessage(value)
|
||||
configMap, err := decodeConfigMap(raw)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return raw, configMap, nil
|
||||
default:
|
||||
raw, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("marshal config: %w", err)
|
||||
}
|
||||
configMap, err := decodeConfigMap(raw)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return raw, configMap, nil
|
||||
}
|
||||
}
|
||||
|
||||
func decodeConfigMap(raw json.RawMessage) (map[string]any, error) {
|
||||
if len(raw) == 0 {
|
||||
return map[string]any{}, nil
|
||||
}
|
||||
var configMap map[string]any
|
||||
if err := json.Unmarshal(raw, &configMap); err != nil {
|
||||
return nil, fmt.Errorf("decode config: %w", err)
|
||||
}
|
||||
if configMap == nil {
|
||||
return map[string]any{}, nil
|
||||
}
|
||||
return configMap, nil
|
||||
return provider, nil
|
||||
}
|
||||
|
||||
@@ -66,6 +66,8 @@ type StorageRangeDownloader interface {
|
||||
|
||||
type ProviderFactory interface {
|
||||
Type() ProviderType
|
||||
SensitiveFields() []string
|
||||
New(context.Context, map[string]any) (StorageProvider, error)
|
||||
}
|
||||
|
||||
// StorageAbout 是可选能力接口,支持查询远端存储空间。
|
||||
|
||||
Reference in New Issue
Block a user