优化结构
This commit is contained in:
@@ -4,22 +4,23 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"kra/internal/biz/system"
|
||||
|
||||
"kra/internal/conf"
|
||||
"kra/internal/biz/system"
|
||||
configpkg "kra/internal/config"
|
||||
"kra/internal/integration/storage"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func (d *Data) RuntimeValues() (*conf.Data, *conf.AdminBackend) { return d.runtime.Values() }
|
||||
func (d *Data) RuntimeAdmin() *conf.AdminBackend { return d.runtime.Admin() }
|
||||
func (d *Data) RefreshDatabaseSources(value *conf.Data) error { return refreshDatabaseSources(value) }
|
||||
func (d *Data) Config() *configpkg.Config {
|
||||
if d == nil || d.runtime == nil {
|
||||
return nil
|
||||
}
|
||||
return d.runtime.Snapshot()
|
||||
}
|
||||
|
||||
func refreshDatabaseSources(value *conf.Data) error {
|
||||
func refreshDatabaseSources(value *configpkg.Data) error {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -37,7 +38,7 @@ func refreshDatabaseSources(value *conf.Data) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func refreshDatabaseSource(database *conf.Data_Database) error {
|
||||
func refreshDatabaseSource(database *configpkg.Database) error {
|
||||
if database == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -57,72 +58,50 @@ func refreshDatabaseSource(database *conf.Data_Database) error {
|
||||
}
|
||||
|
||||
func (d *Data) PersistConfig(context.Context) error { return d.persistConfig() }
|
||||
func (d *Data) PersistAdminConfig(ctx context.Context, raw []byte) error {
|
||||
currentData, currentAdmin := d.runtime.Values()
|
||||
next := proto.Clone(currentAdmin).(*conf.AdminBackend)
|
||||
if err := (protojson.UnmarshalOptions{DiscardUnknown: true}).Unmarshal(raw, next); err != nil {
|
||||
func (d *Data) PersistRuntimeConfig(ctx context.Context, value *configpkg.Config) error {
|
||||
current := d.Config()
|
||||
if current == nil {
|
||||
current = &configpkg.Config{}
|
||||
}
|
||||
next := configpkg.Clone(value)
|
||||
if next == nil {
|
||||
next = configpkg.Clone(current)
|
||||
}
|
||||
if next.Data == nil {
|
||||
next.Data = configpkg.CloneData(current.Data)
|
||||
}
|
||||
if next.Admin == nil {
|
||||
next.Admin = configpkg.CloneAdmin(current.Admin)
|
||||
}
|
||||
if next.Admin != nil && current.Admin != nil {
|
||||
if next.Admin.Storage == nil {
|
||||
next.Admin.Storage = configpkg.CloneStorage(current.Admin.Storage)
|
||||
}
|
||||
if next.Admin.Email == nil {
|
||||
next.Admin.Email = configpkg.CloneEmail(current.Admin.Email)
|
||||
}
|
||||
next.Admin.ConfigPath = current.Admin.ConfigPath
|
||||
}
|
||||
if next.Data == nil {
|
||||
next.Data = &configpkg.Data{}
|
||||
}
|
||||
if err := refreshDatabaseSources(next.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
if next.Storage == nil {
|
||||
next.Storage = currentAdmin.Storage
|
||||
}
|
||||
if next.Email == nil {
|
||||
next.Email = currentAdmin.Email
|
||||
}
|
||||
next.ConfigPath = currentAdmin.ConfigPath
|
||||
candidateStorage, err := storage.New(next)
|
||||
candidateStorage, err := storage.New(next.Admin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.persistStorageIntegrationConfig(ctx, next.Storage); err != nil {
|
||||
if err := d.persistStorageIntegrationConfig(ctx, next.Admin.Storage); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.persistEmailIntegrationConfig(ctx, next.Email); err != nil {
|
||||
if err := d.persistEmailIntegrationConfig(ctx, next.Admin.Email); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.persistConfigValues(currentData, next); err != nil {
|
||||
if err := d.persistConfigValues(next.Data, next.Admin); err != nil {
|
||||
return err
|
||||
}
|
||||
// Writing through the management API updates the same in-memory values
|
||||
// immediately; the file watcher remains the fallback for external edits.
|
||||
d.runtime.Replace(currentData, next)
|
||||
if d.storage != nil {
|
||||
d.storage.Replace(candidateStorage)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (d *Data) PersistRuntimeConfig(ctx context.Context, dataRaw, adminRaw []byte) error {
|
||||
currentData, currentAdmin := d.runtime.Values()
|
||||
nextData := proto.Clone(currentData).(*conf.Data)
|
||||
nextAdmin := proto.Clone(currentAdmin).(*conf.AdminBackend)
|
||||
options := protojson.UnmarshalOptions{DiscardUnknown: true}
|
||||
if err := options.Unmarshal(dataRaw, nextData); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := options.Unmarshal(adminRaw, nextAdmin); err != nil {
|
||||
return err
|
||||
}
|
||||
if nextAdmin.Storage == nil {
|
||||
nextAdmin.Storage = currentAdmin.Storage
|
||||
}
|
||||
if nextAdmin.Email == nil {
|
||||
nextAdmin.Email = currentAdmin.Email
|
||||
}
|
||||
nextAdmin.ConfigPath = currentAdmin.ConfigPath
|
||||
candidateStorage, err := storage.New(nextAdmin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.persistStorageIntegrationConfig(ctx, nextAdmin.Storage); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.persistEmailIntegrationConfig(ctx, nextAdmin.Email); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.persistConfigValues(nextData, nextAdmin); err != nil {
|
||||
return err
|
||||
}
|
||||
d.runtime.Replace(nextData, nextAdmin)
|
||||
d.runtime.Replace(next)
|
||||
if d.storage != nil {
|
||||
d.storage.Replace(candidateStorage)
|
||||
}
|
||||
@@ -140,24 +119,24 @@ func (d *Data) IsInitialized(context.Context) (bool, error) {
|
||||
// is the application-level first-install hook; data owns only lifecycle and
|
||||
// schema migration, while initialize owns system seed orchestration.
|
||||
func (d *Data) InitializeDatabase(ctx context.Context, input *system.DatabaseConfig, seed func(context.Context, *gorm.DB) error) error {
|
||||
config := &conf.Data_Database{}
|
||||
database := &configpkg.Database{}
|
||||
if current := d.runtime.Data(); current != nil && current.Database != nil {
|
||||
config = proto.Clone(current.Database).(*conf.Data_Database)
|
||||
database = configpkg.CloneDatabase(current.Database)
|
||||
}
|
||||
config.Driver = input.Driver
|
||||
config.Host = input.Host
|
||||
config.Port = input.Port
|
||||
config.User = input.User
|
||||
config.Password = input.Password
|
||||
config.Name = input.Name
|
||||
config.Path = input.Path
|
||||
config.Config = input.Config
|
||||
config.Source = ""
|
||||
source, err := databaseDSN(config, "")
|
||||
database.Driver = input.Driver
|
||||
database.Host = input.Host
|
||||
database.Port = input.Port
|
||||
database.User = input.User
|
||||
database.Password = input.Password
|
||||
database.Name = input.Name
|
||||
database.Path = input.Path
|
||||
database.Config = input.Config
|
||||
database.Source = ""
|
||||
source, err := databaseDSN(database, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.Source = source
|
||||
database.Source = source
|
||||
d.initMu.Lock()
|
||||
defer d.initMu.Unlock()
|
||||
initialized, err := d.IsInitialized(ctx)
|
||||
@@ -167,7 +146,7 @@ func (d *Data) InitializeDatabase(ctx context.Context, input *system.DatabaseCon
|
||||
if initialized {
|
||||
return errors.New("数据库已初始化,无需重复初始化")
|
||||
}
|
||||
candidate, err := openDatabase(config, true, input.Template, d.logger())
|
||||
candidate, err := openDatabase(database, true, input.Template, d.logger())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -189,7 +168,7 @@ func (d *Data) InitializeDatabase(ctx context.Context, input *system.DatabaseCon
|
||||
}
|
||||
}
|
||||
currentAdmin := d.runtime.Admin()
|
||||
var legacyStorage *conf.AdminBackend_Storage
|
||||
var legacyStorage *configpkg.Storage
|
||||
if currentAdmin != nil {
|
||||
legacyStorage = currentAdmin.Storage
|
||||
}
|
||||
@@ -197,7 +176,7 @@ func (d *Data) InitializeDatabase(ctx context.Context, input *system.DatabaseCon
|
||||
if err != nil {
|
||||
return fmt.Errorf("initialize storage integration configuration: %w", err)
|
||||
}
|
||||
var legacyEmail *conf.AdminBackend_Email
|
||||
var legacyEmail *configpkg.Email
|
||||
if currentAdmin != nil {
|
||||
legacyEmail = currentAdmin.Email
|
||||
}
|
||||
@@ -206,26 +185,30 @@ func (d *Data) InitializeDatabase(ctx context.Context, input *system.DatabaseCon
|
||||
return fmt.Errorf("initialize email integration configuration: %w", err)
|
||||
}
|
||||
signingKey := uuid.NewString()
|
||||
if err := d.persistDatabaseConfig(config, signingKey); err != nil {
|
||||
if err := d.persistDatabaseConfig(database, signingKey); err != nil {
|
||||
return fmt.Errorf("persist database configuration: %w", err)
|
||||
}
|
||||
integrationConfigs, err := readIntegrationRuntime(candidate)
|
||||
if err != nil {
|
||||
return fmt.Errorf("initialize integration runtime: %w", err)
|
||||
}
|
||||
d.activateDatabase(candidate, config)
|
||||
d.activateDatabase(candidate, database)
|
||||
activated = true
|
||||
currentData, currentAdmin := d.runtime.Values()
|
||||
current := d.Config()
|
||||
if current == nil {
|
||||
current = &configpkg.Config{}
|
||||
}
|
||||
currentData, currentAdmin := current.Data, current.Admin
|
||||
if currentAdmin == nil {
|
||||
currentAdmin = &conf.AdminBackend{}
|
||||
currentAdmin = &configpkg.Admin{}
|
||||
}
|
||||
if currentAdmin.Jwt == nil {
|
||||
currentAdmin.Jwt = &conf.AdminBackend_JWT{}
|
||||
if currentAdmin.JWT == nil {
|
||||
currentAdmin.JWT = &configpkg.JWT{}
|
||||
}
|
||||
currentAdmin.Jwt.SigningKey = signingKey
|
||||
currentAdmin.JWT.SigningKey = signingKey
|
||||
currentAdmin.Storage = storageConfig
|
||||
currentAdmin.Email = emailConfig
|
||||
d.runtime.Replace(currentData, currentAdmin)
|
||||
d.runtime.Replace(&configpkg.Config{Server: current.Server, Data: currentData, Admin: currentAdmin})
|
||||
if d.integrations != nil {
|
||||
d.integrations.Replace(integrationConfigs)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user