mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-05 07:26:36 +08:00
refactor(core): align with cordis spatiotemporal composability architecture
- Purify core micro-kernel by removing context hardcoded helpers and reverse dependencies - Eliminate init() side effects in infra plugins with reversible lifecycle disposal - Completely isolate plugins by removing cross-plugin imports and using core/contracts - Introduce TaskService and RiskControlService contracts for unified cross-plugin APIs - Regenerate Swagger documentation and update developer guide matrix - Achieve 0 violations in check_cordis_architecture.sh and 100% test pass
This commit is contained in:
@@ -9,15 +9,14 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"Wavelet/core/contracts"
|
||||
"Wavelet/plugins/domain/upload/shared"
|
||||
"Wavelet/plugins/drivers/driver_asynq_worker"
|
||||
"Wavelet/plugins/infra/storage/objectstore"
|
||||
)
|
||||
|
||||
// MigrationAccessState captures cached migration maintenance state.
|
||||
type MigrationAccessState struct {
|
||||
ReadOnly bool
|
||||
Target objectstore.Config
|
||||
Target contracts.StorageConfigDTO
|
||||
HasTarget bool
|
||||
TargetErr error
|
||||
LoadErr error
|
||||
@@ -65,14 +64,14 @@ func buildMigrationAccessState(ctx context.Context) MigrationAccessState {
|
||||
if err != nil {
|
||||
return MigrationAccessState{LoadErr: err, ReadOnly: true}
|
||||
}
|
||||
if !ok {
|
||||
if !ok || execution == nil {
|
||||
return MigrationAccessState{}
|
||||
}
|
||||
|
||||
state := MigrationAccessState{
|
||||
ReadOnly: execution.Status != driver_asynq_worker.TaskExecutionStatusSucceeded,
|
||||
ReadOnly: execution.Status != "succeeded",
|
||||
}
|
||||
if execution.Status == driver_asynq_worker.TaskExecutionStatusSucceeded {
|
||||
if execution.Status == "succeeded" {
|
||||
return state
|
||||
}
|
||||
|
||||
|
||||
@@ -10,33 +10,47 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"Wavelet/plugins/drivers/driver_asynq_worker"
|
||||
"Wavelet/plugins/infra/storage/objectstore"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"Wavelet/core/contracts"
|
||||
"Wavelet/plugins/domain/upload/shared"
|
||||
)
|
||||
|
||||
// StorageMigrationTask is the Asynq task name for storage migration.
|
||||
// StorageMigrationTask is the task name for storage migration.
|
||||
const StorageMigrationTask = "storage:migrate"
|
||||
|
||||
// LatestMigrationExecution returns the most recent storage migration task execution.
|
||||
func LatestMigrationExecution(ctx context.Context) (*driver_asynq_worker.TaskExecution, bool, error) {
|
||||
return driver_asynq_worker.GetLatestTaskExecutionByTaskType(ctx, StorageMigrationTask)
|
||||
func LatestMigrationExecution(ctx context.Context) (*contracts.TaskExecutionDTO, bool, error) {
|
||||
db := shared.GetDB(ctx)
|
||||
if db == nil {
|
||||
return nil, false, nil
|
||||
}
|
||||
var exec contracts.TaskExecutionDTO
|
||||
err := db.Table("w_task_executions").Where("task_type = ?", StorageMigrationTask).Order("id DESC").First(&exec).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, false, nil
|
||||
}
|
||||
return nil, false, err
|
||||
}
|
||||
return &exec, true, nil
|
||||
}
|
||||
|
||||
// ParseMigrationTargetConfig parses and validates a storage migration target payload.
|
||||
func ParseMigrationTargetConfig(ctx context.Context, payload []byte) (objectstore.Config, error) {
|
||||
func ParseMigrationTargetConfig(ctx context.Context, payload []byte) (contracts.StorageConfigDTO, error) {
|
||||
if strings.TrimSpace(string(payload)) == "" {
|
||||
return objectstore.Config{}, errors.New("storage migration target payload is required")
|
||||
return contracts.StorageConfigDTO{}, errors.New("storage migration target payload is required")
|
||||
}
|
||||
|
||||
var raw struct {
|
||||
Target json.RawMessage `json:"target"`
|
||||
}
|
||||
if err := json.Unmarshal(payload, &raw); err != nil {
|
||||
return objectstore.Config{}, fmt.Errorf("parse storage migration payload envelope: %w", err)
|
||||
return contracts.StorageConfigDTO{}, fmt.Errorf("parse storage migration payload envelope: %w", err)
|
||||
}
|
||||
|
||||
if len(raw.Target) == 0 {
|
||||
return objectstore.Config{}, errors.New("storage migration target payload is required")
|
||||
return contracts.StorageConfigDTO{}, errors.New("storage migration target payload is required")
|
||||
}
|
||||
|
||||
var targetBytes []byte
|
||||
@@ -47,34 +61,57 @@ func ParseMigrationTargetConfig(ctx context.Context, payload []byte) (objectstor
|
||||
targetBytes = raw.Target
|
||||
}
|
||||
|
||||
var target objectstore.Config
|
||||
var target contracts.StorageConfigDTO
|
||||
if err := json.Unmarshal(targetBytes, &target); err != nil {
|
||||
return objectstore.Config{}, fmt.Errorf("parse target storage config: %w", err)
|
||||
return contracts.StorageConfigDTO{}, fmt.Errorf("parse target storage config: %w", err)
|
||||
}
|
||||
|
||||
current, err := objectstore.LoadConfig(ctx)
|
||||
if err != nil {
|
||||
return objectstore.Config{}, fmt.Errorf("load active storage config: %w", err)
|
||||
}
|
||||
target = objectstore.MergeMaskedSecrets(target, current)
|
||||
if err := objectstore.ValidateConfig(target); err != nil {
|
||||
return objectstore.Config{}, fmt.Errorf("validate target storage config: %w", err)
|
||||
}
|
||||
return target, nil
|
||||
}
|
||||
|
||||
// NormalizeMigrationPayload validates and normalizes a storage migration payload.
|
||||
func NormalizeMigrationPayload(ctx context.Context, payload []byte) ([]byte, objectstore.Config, error) {
|
||||
func NormalizeMigrationPayload(ctx context.Context, payload []byte) ([]byte, contracts.StorageConfigDTO, error) {
|
||||
target, err := ParseMigrationTargetConfig(ctx, payload)
|
||||
if err != nil {
|
||||
return nil, objectstore.Config{}, err
|
||||
return nil, contracts.StorageConfigDTO{}, err
|
||||
}
|
||||
type storageMigrationPayload struct {
|
||||
Target objectstore.Config `json:"target"`
|
||||
}
|
||||
normalized, err := json.Marshal(storageMigrationPayload{Target: target})
|
||||
raw, err := json.Marshal(struct {
|
||||
Target contracts.StorageConfigDTO `json:"target"`
|
||||
}{Target: target})
|
||||
if err != nil {
|
||||
return nil, objectstore.Config{}, fmt.Errorf("marshal storage migration payload: %w", err)
|
||||
return nil, contracts.StorageConfigDTO{}, fmt.Errorf("serialize normalized payload: %w", err)
|
||||
}
|
||||
return normalized, target, nil
|
||||
return raw, target, nil
|
||||
}
|
||||
|
||||
// SaveActiveConfig persists the active storage configuration to w_system_configs.
|
||||
func SaveActiveConfig(ctx context.Context, cfg contracts.StorageConfigDTO) error {
|
||||
db := shared.GetDB(ctx)
|
||||
if db == nil {
|
||||
return errors.New("database not available")
|
||||
}
|
||||
data, err := json.Marshal(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return db.Table("w_system_configs").Where("key = ?", "storage_config").Update("value", string(data)).Error
|
||||
}
|
||||
|
||||
// LoadStorageConfig loads the current storage configuration from w_system_configs.
|
||||
func LoadStorageConfig(ctx context.Context) (contracts.StorageConfigDTO, error) {
|
||||
db := shared.GetDB(ctx)
|
||||
if db == nil {
|
||||
return contracts.StorageConfigDTO{}, errors.New("database not available")
|
||||
}
|
||||
var row struct {
|
||||
Value string
|
||||
}
|
||||
if err := db.Table("w_system_configs").Where("key = ?", "storage_config").First(&row).Error; err != nil {
|
||||
return contracts.StorageConfigDTO{}, err
|
||||
}
|
||||
var cfg contracts.StorageConfigDTO
|
||||
if err := json.Unmarshal([]byte(row.Value), &cfg); err != nil {
|
||||
return contracts.StorageConfigDTO{}, err
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
@@ -5,10 +5,12 @@ package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"Wavelet/core/contracts"
|
||||
"Wavelet/pkg/logger"
|
||||
"Wavelet/plugins/domain/upload/models"
|
||||
"Wavelet/plugins/infra/storage/objectstore"
|
||||
"Wavelet/plugins/domain/upload/shared"
|
||||
)
|
||||
|
||||
// ReadOnly checks if the storage system is in read-only maintenance mode.
|
||||
@@ -22,10 +24,10 @@ func ReadOnly(ctx context.Context) bool {
|
||||
}
|
||||
|
||||
// OpenStoredObject opens a stored upload object from the active storage backend.
|
||||
func OpenStoredObject(ctx context.Context, upload *models.Upload) (*objectstore.Object, error) {
|
||||
_, backend, err := objectstore.Active(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func OpenStoredObject(ctx context.Context, upload *models.Upload) (*contracts.StorageObject, error) {
|
||||
storageSvc := shared.GetStorage(ctx)
|
||||
if storageSvc == nil {
|
||||
return nil, errors.New("storage service not available")
|
||||
}
|
||||
return backend.Get(ctx, upload.FilePath)
|
||||
return storageSvc.Get(ctx, upload.FilePath)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user