优化结构
This commit is contained in:
+80
-126
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -128,7 +129,7 @@ func (r *Store) UpdateDatabase(database *Database) {
|
||||
if config.Data == nil {
|
||||
config.Data = &Data{}
|
||||
}
|
||||
config.Data.Database = cloneDatabase(database)
|
||||
config.Data.Database = clonePtr(database)
|
||||
r.replace(config, false)
|
||||
}
|
||||
|
||||
@@ -358,162 +359,115 @@ func decode(v *viper.Viper) (*Config, error) {
|
||||
}
|
||||
|
||||
func setConfigPath(config *Config, path string) {
|
||||
if config != nil && config.Admin != nil {
|
||||
config.Admin.ConfigPath = path
|
||||
if config == nil {
|
||||
return
|
||||
}
|
||||
if config.Admin == nil {
|
||||
config.Admin = &Admin{}
|
||||
}
|
||||
config.Admin.ConfigPath = path
|
||||
}
|
||||
|
||||
// Every config type is plain data: scalars, pointers to structs, and slices of
|
||||
// those. clonePtr and cloneSlice cover both shapes, so a clone function below is
|
||||
// one line per pointer or slice field and nothing else. A field holding only
|
||||
// scalars needs no line at all — the struct assignment already copied it.
|
||||
func clonePtr[T any](value *T) *T {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
copied := *value
|
||||
return &copied
|
||||
}
|
||||
|
||||
func cloneSlice[T any](values []*T, clone func(*T) *T) []*T {
|
||||
if values == nil {
|
||||
return nil
|
||||
}
|
||||
copied := make([]*T, len(values))
|
||||
for i, item := range values {
|
||||
copied[i] = clone(item)
|
||||
}
|
||||
return copied
|
||||
}
|
||||
|
||||
func cloneConfig(value *Config) *Config {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
// Viper's mapstructure output contains only value fields and pointers;
|
||||
// round-tripping through a temporary map is unnecessarily lossy for
|
||||
// durations. Explicit copy via YAML gives us a robust deep copy while
|
||||
// preserving time.Duration values through the text hook.
|
||||
copy := *value
|
||||
if value.Server != nil {
|
||||
server := *value.Server
|
||||
copy.Server = &server
|
||||
if value.Server.HTTP != nil {
|
||||
http := *value.Server.HTTP
|
||||
copy.Server.HTTP = &http
|
||||
}
|
||||
copied := *value
|
||||
copied.Server = clonePtr(value.Server)
|
||||
if copied.Server != nil {
|
||||
copied.Server.HTTP = clonePtr(value.Server.HTTP)
|
||||
}
|
||||
if value.Data != nil {
|
||||
data := *value.Data
|
||||
copy.Data = &data
|
||||
data.Database = cloneDatabase(value.Data.Database)
|
||||
data.Redis = cloneRedis(value.Data.Redis)
|
||||
data.Mongo = cloneMongo(value.Data.Mongo)
|
||||
data.DatabaseList = make([]*Database, len(value.Data.DatabaseList))
|
||||
for i, item := range value.Data.DatabaseList {
|
||||
data.DatabaseList[i] = cloneDatabase(item)
|
||||
}
|
||||
data.RedisList = make([]*Redis, len(value.Data.RedisList))
|
||||
for i, item := range value.Data.RedisList {
|
||||
data.RedisList[i] = cloneRedis(item)
|
||||
}
|
||||
}
|
||||
if value.Admin != nil {
|
||||
copy.Admin = cloneAdmin(value.Admin)
|
||||
}
|
||||
return ©
|
||||
copied.Data = cloneData(value.Data)
|
||||
copied.Admin = cloneAdmin(value.Admin)
|
||||
return &copied
|
||||
}
|
||||
|
||||
func cloneDatabase(value *Database) *Database {
|
||||
func cloneData(value *Data) *Data {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
copy := *value
|
||||
return ©
|
||||
copied := *value
|
||||
copied.Database = clonePtr(value.Database)
|
||||
copied.Redis = cloneRedis(value.Redis)
|
||||
copied.Mongo = cloneMongo(value.Mongo)
|
||||
copied.DatabaseList = cloneSlice(value.DatabaseList, clonePtr)
|
||||
copied.RedisList = cloneSlice(value.RedisList, cloneRedis)
|
||||
return &copied
|
||||
}
|
||||
|
||||
func cloneRedis(value *Redis) *Redis {
|
||||
if value == nil {
|
||||
return nil
|
||||
copied := clonePtr(value)
|
||||
if copied != nil {
|
||||
copied.ClusterAddrs = slices.Clone(value.ClusterAddrs)
|
||||
}
|
||||
copy := *value
|
||||
copy.ClusterAddrs = append([]string(nil), value.ClusterAddrs...)
|
||||
return ©
|
||||
return copied
|
||||
}
|
||||
|
||||
func cloneMongo(value *Mongo) *Mongo {
|
||||
if value == nil {
|
||||
return nil
|
||||
copied := clonePtr(value)
|
||||
if copied != nil {
|
||||
copied.Hosts = cloneSlice(value.Hosts, clonePtr)
|
||||
}
|
||||
copy := *value
|
||||
copy.Hosts = make([]*MongoHost, len(value.Hosts))
|
||||
for i, item := range value.Hosts {
|
||||
if item != nil {
|
||||
host := *item
|
||||
copy.Hosts[i] = &host
|
||||
}
|
||||
}
|
||||
return ©
|
||||
return copied
|
||||
}
|
||||
|
||||
func cloneAdmin(value *Admin) *Admin {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
copy := *value
|
||||
if value.JWT != nil {
|
||||
item := *value.JWT
|
||||
copy.JWT = &item
|
||||
copied := *value
|
||||
copied.JWT = clonePtr(value.JWT)
|
||||
copied.Captcha = clonePtr(value.Captcha)
|
||||
copied.Local = clonePtr(value.Local)
|
||||
copied.Email = clonePtr(value.Email)
|
||||
copied.Media = clonePtr(value.Media)
|
||||
copied.System = clonePtr(value.System)
|
||||
copied.App = clonePtr(value.App)
|
||||
copied.DiskList = cloneSlice(value.DiskList, clonePtr)
|
||||
copied.Storage = cloneStorage(value.Storage)
|
||||
if copied.Zap = clonePtr(value.Zap); copied.Zap != nil {
|
||||
copied.Zap.FileOnlyModules = slices.Clone(value.Zap.FileOnlyModules)
|
||||
}
|
||||
if value.Captcha != nil {
|
||||
item := *value.Captcha
|
||||
copy.Captcha = &item
|
||||
if copied.CORS = clonePtr(value.CORS); copied.CORS != nil {
|
||||
copied.CORS.Whitelist = cloneSlice(value.CORS.Whitelist, clonePtr)
|
||||
}
|
||||
if value.Local != nil {
|
||||
item := *value.Local
|
||||
copy.Local = &item
|
||||
}
|
||||
if value.Email != nil {
|
||||
item := *value.Email
|
||||
copy.Email = &item
|
||||
}
|
||||
if value.Media != nil {
|
||||
item := *value.Media
|
||||
copy.Media = &item
|
||||
}
|
||||
if value.System != nil {
|
||||
item := *value.System
|
||||
copy.System = &item
|
||||
}
|
||||
if value.Zap != nil {
|
||||
item := *value.Zap
|
||||
item.FileOnlyModules = append([]string(nil), value.Zap.FileOnlyModules...)
|
||||
copy.Zap = &item
|
||||
}
|
||||
if value.App != nil {
|
||||
item := *value.App
|
||||
copy.App = &item
|
||||
}
|
||||
if value.CORS != nil {
|
||||
item := *value.CORS
|
||||
item.Whitelist = make([]*CORSRule, len(value.CORS.Whitelist))
|
||||
for i, rule := range value.CORS.Whitelist {
|
||||
if rule != nil {
|
||||
next := *rule
|
||||
item.Whitelist[i] = &next
|
||||
}
|
||||
}
|
||||
copy.CORS = &item
|
||||
}
|
||||
if value.Storage != nil {
|
||||
copy.Storage = cloneStorage(value.Storage)
|
||||
}
|
||||
copy.DiskList = make([]*Disk, len(value.DiskList))
|
||||
for i, item := range value.DiskList {
|
||||
if item != nil {
|
||||
next := *item
|
||||
copy.DiskList[i] = &next
|
||||
}
|
||||
}
|
||||
return ©
|
||||
return &copied
|
||||
}
|
||||
|
||||
func cloneStorage(value *Storage) *Storage {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
copy := *value
|
||||
if value.Qiniu != nil {
|
||||
item := *value.Qiniu
|
||||
copy.Qiniu = &item
|
||||
}
|
||||
copy.AliyunOSS = cloneObjectStore(value.AliyunOSS)
|
||||
copy.HuaweiOBS = cloneObjectStore(value.HuaweiOBS)
|
||||
copy.TencentCOS = cloneObjectStore(value.TencentCOS)
|
||||
copy.AWSS3 = cloneObjectStore(value.AWSS3)
|
||||
copy.CloudflareR2 = cloneObjectStore(value.CloudflareR2)
|
||||
copy.Minio = cloneObjectStore(value.Minio)
|
||||
return ©
|
||||
}
|
||||
func cloneObjectStore(value *ObjectStore) *ObjectStore {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
copy := *value
|
||||
return ©
|
||||
copied := *value
|
||||
copied.Qiniu = clonePtr(value.Qiniu)
|
||||
copied.AliyunOSS = clonePtr(value.AliyunOSS)
|
||||
copied.HuaweiOBS = clonePtr(value.HuaweiOBS)
|
||||
copied.TencentCOS = clonePtr(value.TencentCOS)
|
||||
copied.AWSS3 = clonePtr(value.AWSS3)
|
||||
copied.CloudflareR2 = clonePtr(value.CloudflareR2)
|
||||
copied.Minio = clonePtr(value.Minio)
|
||||
return &copied
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user