优化结构
This commit is contained in:
@@ -3,184 +3,68 @@ package initialize
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"kra/internal/conf"
|
||||
"kra/pkg/protoutil"
|
||||
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
"kra/internal/config"
|
||||
)
|
||||
|
||||
type configurationEnvelope struct {
|
||||
Data json.RawMessage `json:"data"`
|
||||
Admin json.RawMessage `json:"admin"`
|
||||
Email *struct {
|
||||
To string `json:"to"`
|
||||
From string `json:"from"`
|
||||
Host string `json:"host"`
|
||||
Secret string `json:"secret"`
|
||||
Nickname string `json:"nickname"`
|
||||
Port int32 `json:"port"`
|
||||
IsSSL bool `json:"is-ssl"`
|
||||
IsLoginAuth bool `json:"is-loginauth"`
|
||||
} `json:"email"`
|
||||
Email json.RawMessage `json:"email"`
|
||||
}
|
||||
|
||||
func (r *Repo) ConfigurationJSON() (json.RawMessage, error) {
|
||||
dataConfig, adminConfig := r.backend.RuntimeValues()
|
||||
admin := map[string]any{"routerPrefix": ""}
|
||||
email := map[string]any{}
|
||||
if adminConfig != nil {
|
||||
admin["routerPrefix"] = adminConfig.RouterPrefix
|
||||
if adminConfig.System != nil {
|
||||
admin["system"] = map[string]any{
|
||||
"useRedis": adminConfig.System.UseRedis,
|
||||
"useMultipoint": adminConfig.System.UseMultipoint,
|
||||
"useStrictAuth": adminConfig.System.UseStrictAuth,
|
||||
"disableAutoMigrate": adminConfig.System.DisableAutoMigrate,
|
||||
"useMongo": adminConfig.System.UseMongo,
|
||||
"addr": adminConfig.System.Addr,
|
||||
"iplimitCount": adminConfig.System.IplimitCount,
|
||||
"iplimitTime": adminConfig.System.IplimitTime,
|
||||
}
|
||||
}
|
||||
if adminConfig.Jwt != nil {
|
||||
admin["jwt"] = map[string]any{"signingKey": "******", "expiresTime": durationString(adminConfig.Jwt.ExpiresTime), "bufferTime": durationString(adminConfig.Jwt.BufferTime), "issuer": adminConfig.Jwt.Issuer}
|
||||
}
|
||||
if adminConfig.Captcha != nil {
|
||||
admin["captcha"] = map[string]any{"keyLong": adminConfig.Captcha.KeyLong, "imgWidth": adminConfig.Captcha.ImgWidth, "imgHeight": adminConfig.Captcha.ImgHeight, "storeExpiration": durationString(adminConfig.Captcha.StoreExpiration)}
|
||||
}
|
||||
if adminConfig.Local != nil {
|
||||
admin["local"] = map[string]any{"storePath": adminConfig.Local.StorePath, "pathPrefix": adminConfig.Local.PathPrefix}
|
||||
}
|
||||
if adminConfig.Media != nil {
|
||||
chunkDir := adminConfig.Media.ChunkDir
|
||||
if chunkDir == "" {
|
||||
chunkDir = "uploads/chunks"
|
||||
}
|
||||
admin["media"] = map[string]any{"sessionTtl": adminConfig.Media.SessionTtl, "maxFileSize": adminConfig.Media.MaxFileSize, "chunkDir": chunkDir}
|
||||
}
|
||||
if adminConfig.Email != nil {
|
||||
secret := ""
|
||||
if adminConfig.Email.Secret != "" {
|
||||
secret = "******"
|
||||
}
|
||||
email = map[string]any{"to": adminConfig.Email.To, "from": adminConfig.Email.From, "host": adminConfig.Email.Host, "secret": secret, "nickname": adminConfig.Email.Nickname, "port": adminConfig.Email.Port, "is-ssl": adminConfig.Email.IsSsl, "is-loginauth": adminConfig.Email.IsLoginAuth}
|
||||
}
|
||||
if adminConfig.Storage != nil {
|
||||
storage := proto.Clone(adminConfig.Storage).(*conf.AdminBackend_Storage)
|
||||
maskStorageSecrets(storage)
|
||||
admin["storage"] = storage
|
||||
}
|
||||
disks := make([]map[string]any, 0, len(adminConfig.DiskList))
|
||||
for _, disk := range adminConfig.DiskList {
|
||||
if disk != nil {
|
||||
disks = append(disks, map[string]any{"mount_point": disk.MountPoint})
|
||||
}
|
||||
}
|
||||
admin["disk_list"] = disks
|
||||
if adminConfig.Zap != nil {
|
||||
admin["zap"] = adminConfig.Zap
|
||||
}
|
||||
if adminConfig.Cors != nil {
|
||||
admin["cors"] = adminConfig.Cors
|
||||
}
|
||||
if adminConfig.App != nil {
|
||||
admin["app"] = adminConfig.App
|
||||
}
|
||||
current := r.backend.Config()
|
||||
if current == nil {
|
||||
current = &config.Config{}
|
||||
}
|
||||
// Never mask secrets on the live runtime object. ConfigurationJSON is a
|
||||
// read-only operation; mutating dataConfig here would replace the actual
|
||||
// database/Redis/Mongo credentials with "******" and make the next reload
|
||||
// fail. Work on a clone, just as we already do for adminConfig.
|
||||
safeData := cloneDataConfig(dataConfig)
|
||||
maskDataSecrets(safeData)
|
||||
safeAdmin := cloneAdminConfig(adminConfig)
|
||||
if safeAdmin != nil {
|
||||
if safeAdmin.Jwt != nil {
|
||||
safeAdmin.Jwt.SigningKey = "******"
|
||||
}
|
||||
if safeAdmin.Email != nil && safeAdmin.Email.Secret != "" {
|
||||
safeAdmin.Email.Secret = "******"
|
||||
}
|
||||
maskStorageSecrets(safeAdmin.Storage)
|
||||
}
|
||||
dataMap := map[string]any{}
|
||||
if safeData != nil {
|
||||
raw, err := protojson.MarshalOptions{UseProtoNames: true}.Marshal(safeData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = json.Unmarshal(raw, &dataMap); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
config := compatibleConfiguration(safeData, safeAdmin)
|
||||
config["admin"], config["email"], config["data"] = admin, email, dataMap
|
||||
return json.Marshal(map[string]any{"config": config})
|
||||
safe := config.Clone(current)
|
||||
maskConfigSecrets(safe)
|
||||
return json.Marshal(map[string]any{"config": managementConfig(safe)})
|
||||
}
|
||||
|
||||
func (r *Repo) SaveConfigurationJSON(ctx context.Context, raw json.RawMessage) error {
|
||||
currentData, currentAdmin := r.backend.RuntimeValues()
|
||||
if currentAdmin == nil {
|
||||
return nil
|
||||
}
|
||||
nextData := cloneDataConfig(currentData)
|
||||
nextAdmin := proto.Clone(currentAdmin).(*conf.AdminBackend)
|
||||
if err := applyCompatibleConfiguration(raw, nextData, nextAdmin); err != nil {
|
||||
return err
|
||||
current := r.backend.Config()
|
||||
if current == nil {
|
||||
current = &config.Config{}
|
||||
}
|
||||
next := config.Clone(current)
|
||||
var value configurationEnvelope
|
||||
if err := json.Unmarshal(raw, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
options := protojson.UnmarshalOptions{DiscardUnknown: true}
|
||||
if len(value.Data) > 0 && string(value.Data) != "null" {
|
||||
if err := protoutil.MergeProtoJSON(nextData, value.Data, options); err != nil {
|
||||
if err := mergeJSON(value.Data, &next.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mergeJSON(value.Admin, &next.Admin); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(value.Email) > 0 && string(value.Email) != "null" {
|
||||
if next.Admin == nil {
|
||||
next.Admin = &config.Admin{}
|
||||
}
|
||||
if err := mergeJSON(value.Email, &next.Admin.Email); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(value.Admin) > 0 && string(value.Admin) != "null" {
|
||||
if err := protoutil.MergeProtoJSON(nextAdmin, value.Admin, options); err != nil {
|
||||
return err
|
||||
}
|
||||
preserveConfigSecrets(next, current)
|
||||
if next.Admin != nil && current.Admin != nil {
|
||||
next.Admin.ConfigPath = current.Admin.ConfigPath
|
||||
}
|
||||
preserveDataSecrets(nextData, currentData)
|
||||
preserveAdminSecrets(nextAdmin, currentAdmin)
|
||||
if value.Email != nil {
|
||||
if nextAdmin.Email == nil {
|
||||
nextAdmin.Email = &conf.AdminBackend_Email{}
|
||||
}
|
||||
nextAdmin.Email.To, nextAdmin.Email.From, nextAdmin.Email.Host = value.Email.To, value.Email.From, value.Email.Host
|
||||
nextAdmin.Email.Nickname, nextAdmin.Email.Port = value.Email.Nickname, value.Email.Port
|
||||
nextAdmin.Email.IsSsl, nextAdmin.Email.IsLoginAuth = value.Email.IsSSL, value.Email.IsLoginAuth
|
||||
if value.Email.Secret != "" && value.Email.Secret != "******" {
|
||||
nextAdmin.Email.Secret = value.Email.Secret
|
||||
}
|
||||
}
|
||||
if err := r.backend.RefreshDatabaseSources(nextData); err != nil {
|
||||
if err := refreshDatabaseSources(next.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
nextAdmin.ConfigPath = currentAdmin.ConfigPath
|
||||
dataRaw, err := protojson.MarshalOptions{UseProtoNames: true}.Marshal(nextData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
adminRaw, err := protojson.MarshalOptions{UseProtoNames: true}.Marshal(nextAdmin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return r.PersistRuntimeConfig(ctx, dataRaw, adminRaw)
|
||||
return r.PersistRuntimeConfig(ctx, next)
|
||||
}
|
||||
|
||||
func (r *Repo) DiskMountPoints() []string {
|
||||
config := r.backend.RuntimeAdmin()
|
||||
if config == nil {
|
||||
current := r.backend.Config()
|
||||
if current == nil || current.Admin == nil {
|
||||
return nil
|
||||
}
|
||||
points := make([]string, 0, len(config.DiskList))
|
||||
for _, item := range config.DiskList {
|
||||
points := make([]string, 0, len(current.Admin.DiskList))
|
||||
for _, item := range current.Admin.DiskList {
|
||||
if item != nil && item.MountPoint != "" {
|
||||
points = append(points, item.MountPoint)
|
||||
}
|
||||
@@ -188,37 +72,105 @@ func (r *Repo) DiskMountPoints() []string {
|
||||
return points
|
||||
}
|
||||
|
||||
func cloneDataConfig(value *conf.Data) *conf.Data {
|
||||
if value == nil {
|
||||
return &conf.Data{}
|
||||
func mergeJSON(raw json.RawMessage, target any) error {
|
||||
if len(raw) == 0 || string(raw) == "null" {
|
||||
return nil
|
||||
}
|
||||
return proto.Clone(value).(*conf.Data)
|
||||
return json.Unmarshal(raw, target)
|
||||
}
|
||||
|
||||
func cloneAdminConfig(value *conf.AdminBackend) *conf.AdminBackend {
|
||||
func managementConfig(value *config.Config) map[string]any {
|
||||
result := map[string]any{"data": map[string]any{}, "admin": map[string]any{}, "email": map[string]any{}}
|
||||
if value == nil {
|
||||
return &conf.AdminBackend{}
|
||||
return result
|
||||
}
|
||||
return proto.Clone(value).(*conf.AdminBackend)
|
||||
if value.Data != nil {
|
||||
result["data"] = value.Data
|
||||
}
|
||||
if value.Admin != nil {
|
||||
admin := value.Admin
|
||||
result["admin"] = map[string]any{
|
||||
"routerPrefix": admin.RouterPrefix,
|
||||
"jwt": managementJWT(admin.JWT),
|
||||
"captcha": managementCaptcha(admin.Captcha),
|
||||
"local": managementLocal(admin.Local),
|
||||
"media": managementMedia(admin.Media),
|
||||
"system": managementSystem(admin.System),
|
||||
"storage": admin.Storage,
|
||||
"disk_list": admin.DiskList,
|
||||
"zap": admin.Zap,
|
||||
"cors": admin.CORS,
|
||||
"app": admin.App,
|
||||
}
|
||||
if admin.Email != nil {
|
||||
result["email"] = map[string]any{
|
||||
"to": admin.Email.To, "from": admin.Email.From, "host": admin.Email.Host,
|
||||
"secret": admin.Email.Secret, "nickname": admin.Email.Nickname, "port": admin.Email.Port,
|
||||
"is-ssl": admin.Email.IsSSL, "is-loginauth": admin.Email.IsLoginAuth,
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func durationString(value *durationpb.Duration) string {
|
||||
func managementJWT(value *config.JWT) any {
|
||||
if value == nil {
|
||||
return "0s"
|
||||
return map[string]any{}
|
||||
}
|
||||
return value.AsDuration().String()
|
||||
return map[string]any{"signingKey": value.SigningKey, "expiresTime": value.ExpiresTime.String(), "bufferTime": value.BufferTime.String(), "issuer": value.Issuer}
|
||||
}
|
||||
func managementCaptcha(value *config.Captcha) any {
|
||||
if value == nil {
|
||||
return map[string]any{}
|
||||
}
|
||||
return map[string]any{"keyLong": value.KeyLong, "imgWidth": value.ImgWidth, "imgHeight": value.ImgHeight, "storeExpiration": value.StoreExpiration.String()}
|
||||
}
|
||||
func managementLocal(value *config.Local) any {
|
||||
if value == nil {
|
||||
return map[string]any{}
|
||||
}
|
||||
return map[string]any{"storePath": value.StorePath, "pathPrefix": value.PathPrefix}
|
||||
}
|
||||
func managementMedia(value *config.Media) any {
|
||||
if value == nil {
|
||||
return map[string]any{}
|
||||
}
|
||||
chunkDir := value.ChunkDir
|
||||
if chunkDir == "" {
|
||||
chunkDir = "uploads/chunks"
|
||||
}
|
||||
return map[string]any{"sessionTtl": value.SessionTTL, "maxFileSize": value.MaxFileSize, "chunkDir": chunkDir}
|
||||
}
|
||||
func managementSystem(value *config.System) any {
|
||||
if value == nil {
|
||||
return map[string]any{}
|
||||
}
|
||||
return map[string]any{"useRedis": value.UseRedis, "useMultipoint": value.UseMultipoint, "useStrictAuth": value.UseStrictAuth, "disableAutoMigrate": value.DisableAutoMigrate, "useMongo": value.UseMongo, "addr": value.Addr, "iplimitCount": value.IplimitCount, "iplimitTime": value.IplimitTime}
|
||||
}
|
||||
|
||||
func maskDataSecrets(value *conf.Data) {
|
||||
func maskConfigSecrets(value *config.Config) {
|
||||
if value == nil {
|
||||
return
|
||||
}
|
||||
maskDataSecrets(value.Data)
|
||||
if value.Admin == nil {
|
||||
return
|
||||
}
|
||||
if value.Admin.JWT != nil && value.Admin.JWT.SigningKey != "" {
|
||||
value.Admin.JWT.SigningKey = "******"
|
||||
}
|
||||
if value.Admin.Email != nil && value.Admin.Email.Secret != "" {
|
||||
value.Admin.Email.Secret = "******"
|
||||
}
|
||||
maskStorageSecrets(value.Admin.Storage)
|
||||
}
|
||||
|
||||
func maskDataSecrets(value *config.Data) {
|
||||
if value == nil {
|
||||
return
|
||||
}
|
||||
if value.Database != nil {
|
||||
value.Database.Password = "******"
|
||||
// Source may contain an embedded password (for example a MySQL DSN).
|
||||
// The management response must never expose it. Structured database
|
||||
// fields are retained and refreshDatabaseSources rebuilds Source when
|
||||
// the configuration is saved.
|
||||
value.Database.Source = ""
|
||||
}
|
||||
if value.Redis != nil {
|
||||
@@ -240,15 +192,34 @@ func maskDataSecrets(value *conf.Data) {
|
||||
}
|
||||
}
|
||||
|
||||
func preserveDataSecrets(next, current *conf.Data) {
|
||||
func preserveConfigSecrets(next, current *config.Config) {
|
||||
if next == nil || current == nil {
|
||||
return
|
||||
}
|
||||
if next.Database != nil && current.Database != nil && maskedSecret(next.Database.Password) {
|
||||
next.Database.Password = current.Database.Password
|
||||
preserveDataSecrets(next.Data, current.Data)
|
||||
if next.Admin == nil || current.Admin == nil {
|
||||
return
|
||||
}
|
||||
if next.Database != nil && current.Database != nil && next.Database.Source == "" {
|
||||
next.Database.Source = current.Database.Source
|
||||
if next.Admin.JWT != nil && current.Admin.JWT != nil && maskedSecret(next.Admin.JWT.SigningKey) {
|
||||
next.Admin.JWT.SigningKey = current.Admin.JWT.SigningKey
|
||||
}
|
||||
if next.Admin.Email != nil && current.Admin.Email != nil && maskedSecret(next.Admin.Email.Secret) {
|
||||
next.Admin.Email.Secret = current.Admin.Email.Secret
|
||||
}
|
||||
preserveStorageSecrets(next.Admin.Storage, current.Admin.Storage)
|
||||
}
|
||||
|
||||
func preserveDataSecrets(next, current *config.Data) {
|
||||
if next == nil || current == nil {
|
||||
return
|
||||
}
|
||||
if next.Database != nil && current.Database != nil {
|
||||
if maskedSecret(next.Database.Password) {
|
||||
next.Database.Password = current.Database.Password
|
||||
}
|
||||
if next.Database.Source == "" {
|
||||
next.Database.Source = current.Database.Source
|
||||
}
|
||||
}
|
||||
if next.Redis != nil && current.Redis != nil && maskedSecret(next.Redis.Password) {
|
||||
next.Redis.Password = current.Redis.Password
|
||||
@@ -256,83 +227,80 @@ func preserveDataSecrets(next, current *conf.Data) {
|
||||
if next.Mongo != nil && current.Mongo != nil && maskedSecret(next.Mongo.Password) {
|
||||
next.Mongo.Password = current.Mongo.Password
|
||||
}
|
||||
currentDatabases := make(map[string]*conf.Data_Database, len(current.DatabaseList))
|
||||
for _, item := range current.DatabaseList {
|
||||
preserveDatabaseListSecrets(next.DatabaseList, current.DatabaseList)
|
||||
preserveRedisListSecrets(next.RedisList, current.RedisList)
|
||||
}
|
||||
|
||||
func preserveDatabaseListSecrets(next, current []*config.Database) {
|
||||
byName := make(map[string]*config.Database, len(current))
|
||||
for _, item := range current {
|
||||
if item != nil && item.AliasName != "" {
|
||||
currentDatabases[item.AliasName] = item
|
||||
byName[item.AliasName] = item
|
||||
}
|
||||
}
|
||||
for i, item := range next.DatabaseList {
|
||||
var previous *conf.Data_Database
|
||||
if item != nil && item.AliasName != "" {
|
||||
previous = currentDatabases[item.AliasName]
|
||||
for index, item := range next {
|
||||
if item == nil {
|
||||
continue
|
||||
}
|
||||
if previous == nil && i < len(current.DatabaseList) {
|
||||
previous = current.DatabaseList[i]
|
||||
previous := byName[item.AliasName]
|
||||
if previous == nil && index < len(current) {
|
||||
previous = current[index]
|
||||
}
|
||||
if item != nil && previous != nil {
|
||||
if maskedSecret(item.Password) {
|
||||
item.Password = previous.Password
|
||||
}
|
||||
if item.Source == "" {
|
||||
item.Source = previous.Source
|
||||
}
|
||||
if previous == nil {
|
||||
continue
|
||||
}
|
||||
if maskedSecret(item.Password) {
|
||||
item.Password = previous.Password
|
||||
}
|
||||
if item.Source == "" {
|
||||
item.Source = previous.Source
|
||||
}
|
||||
}
|
||||
currentRedis := make(map[string]*conf.Data_Redis, len(current.RedisList))
|
||||
for _, item := range current.RedisList {
|
||||
}
|
||||
|
||||
func preserveRedisListSecrets(next, current []*config.Redis) {
|
||||
byName := make(map[string]*config.Redis, len(current))
|
||||
for _, item := range current {
|
||||
if item != nil && item.Name != "" {
|
||||
currentRedis[item.Name] = item
|
||||
byName[item.Name] = item
|
||||
}
|
||||
}
|
||||
for i, item := range next.RedisList {
|
||||
var previous *conf.Data_Redis
|
||||
if item != nil && item.Name != "" {
|
||||
previous = currentRedis[item.Name]
|
||||
for index, item := range next {
|
||||
if item == nil {
|
||||
continue
|
||||
}
|
||||
if previous == nil && i < len(current.RedisList) {
|
||||
previous = current.RedisList[i]
|
||||
previous := byName[item.Name]
|
||||
if previous == nil && index < len(current) {
|
||||
previous = current[index]
|
||||
}
|
||||
if item != nil && previous != nil && maskedSecret(item.Password) {
|
||||
if previous != nil && maskedSecret(item.Password) {
|
||||
item.Password = previous.Password
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func preserveAdminSecrets(next, current *conf.AdminBackend) {
|
||||
if next.Jwt != nil && current.Jwt != nil && maskedSecret(next.Jwt.SigningKey) {
|
||||
next.Jwt.SigningKey = current.Jwt.SigningKey
|
||||
}
|
||||
if next.Email != nil && current.Email != nil && maskedSecret(next.Email.Secret) {
|
||||
next.Email.Secret = current.Email.Secret
|
||||
}
|
||||
preserveStorageSecrets(next.Storage, current.Storage)
|
||||
}
|
||||
|
||||
func maskedSecret(value string) bool { return value == "" || value == "******" }
|
||||
|
||||
func objectStores(storage *conf.AdminBackend_Storage) []*conf.AdminBackend_ObjectStore {
|
||||
if storage == nil {
|
||||
func objectStores(value *config.Storage) []*config.ObjectStore {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
return []*conf.AdminBackend_ObjectStore{storage.AliyunOss, storage.HuaweiObs, storage.TencentCos, storage.AwsS3, storage.CloudflareR2, storage.Minio}
|
||||
return []*config.ObjectStore{value.AliyunOSS, value.HuaweiOBS, value.TencentCOS, value.AWSS3, value.CloudflareR2, value.Minio}
|
||||
}
|
||||
|
||||
func maskStorageSecrets(storage *conf.AdminBackend_Storage) {
|
||||
if storage == nil {
|
||||
func maskStorageSecrets(value *config.Storage) {
|
||||
if value == nil {
|
||||
return
|
||||
}
|
||||
if storage.Qiniu != nil && storage.Qiniu.SecretKey != "" {
|
||||
storage.Qiniu.SecretKey = "******"
|
||||
if value.Qiniu != nil && value.Qiniu.SecretKey != "" {
|
||||
value.Qiniu.SecretKey = "******"
|
||||
}
|
||||
for _, item := range objectStores(storage) {
|
||||
for _, item := range objectStores(value) {
|
||||
if item != nil && item.SecretKey != "" {
|
||||
item.SecretKey = "******"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func preserveStorageSecrets(next, current *conf.AdminBackend_Storage) {
|
||||
func preserveStorageSecrets(next, current *config.Storage) {
|
||||
if next == nil || current == nil {
|
||||
return
|
||||
}
|
||||
@@ -340,9 +308,43 @@ func preserveStorageSecrets(next, current *conf.AdminBackend_Storage) {
|
||||
next.Qiniu.SecretKey = current.Qiniu.SecretKey
|
||||
}
|
||||
nextItems, currentItems := objectStores(next), objectStores(current)
|
||||
for i := range nextItems {
|
||||
if nextItems[i] != nil && currentItems[i] != nil && maskedSecret(nextItems[i].SecretKey) {
|
||||
nextItems[i].SecretKey = currentItems[i].SecretKey
|
||||
for index := range nextItems {
|
||||
if nextItems[index] != nil && currentItems[index] != nil && maskedSecret(nextItems[index].SecretKey) {
|
||||
nextItems[index].SecretKey = currentItems[index].SecretKey
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func refreshDatabaseSources(value *config.Data) error {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
if err := refreshDatabaseSource(value.Database); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, database := range value.DatabaseList {
|
||||
if database == nil || database.Disable {
|
||||
continue
|
||||
}
|
||||
if err := refreshDatabaseSource(database); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func refreshDatabaseSource(database *config.Database) error {
|
||||
if database == nil {
|
||||
return nil
|
||||
}
|
||||
if database.Driver == "sqlite" && database.Path == "" {
|
||||
return errors.New("sqlite database path is required")
|
||||
}
|
||||
if database.Driver == "sqlite" {
|
||||
database.Source = database.Path
|
||||
} else {
|
||||
// Driver-specific DSN construction remains in data. Clearing Source
|
||||
// makes the data backend rebuild it from structured values.
|
||||
database.Source = ""
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user