kra-new/internal/service/system_config.go

283 lines
10 KiB
Go

package service
import (
"context"
"encoding/json"
"time"
"kra/internal/conf"
"kra/internal/service/dto"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/durationpb"
)
func (s *SystemConfigService) PersistConfig(ctx context.Context) error {
return s.uc.PersistConfig(ctx)
}
func (s *SystemConfigService) PersistAdminConfig(ctx context.Context, value *conf.AdminBackend) error {
raw, err := protojson.MarshalOptions{UseProtoNames: true}.Marshal(value)
if err != nil {
return err
}
return s.uc.PersistAdminConfig(ctx, raw)
}
func (s *SystemConfigService) ReloadConfig(ctx context.Context) error { return s.uc.ReloadConfig(ctx) }
func (s *SystemConfigService) DiskMountPoints() []string {
config := s.runtime.Admin()
if config == nil {
return nil
}
points := make([]string, 0, len(config.DiskList))
for _, item := range config.DiskList {
if item != nil && item.MountPoint != "" {
points = append(points, item.MountPoint)
}
}
return points
}
func (s *SystemConfigService) SystemConfig() map[string]any {
admin := map[string]any{"routerPrefix": ""}
email := map[string]any{}
config := s.runtime.Admin()
if config == nil {
return map[string]any{"config": map[string]any{"admin": admin, "email": email, "data": map[string]any{}}}
}
admin["routerPrefix"] = config.RouterPrefix
if config.System != nil {
admin["system"] = map[string]any{"useRedis": config.System.UseRedis, "useMultipoint": config.System.UseMultipoint, "useStrictAuth": config.System.UseStrictAuth, "disableAutoMigrate": config.System.DisableAutoMigrate, "useMongo": config.System.UseMongo}
}
if config.Jwt != nil {
admin["jwt"] = map[string]any{"signingKey": "******", "expiresTime": config.Jwt.ExpiresTime.AsDuration().String(), "bufferTime": config.Jwt.BufferTime.AsDuration().String(), "issuer": config.Jwt.Issuer}
}
if config.Captcha != nil {
admin["captcha"] = map[string]any{"keyLong": config.Captcha.KeyLong, "imgWidth": config.Captcha.ImgWidth, "imgHeight": config.Captcha.ImgHeight, "storeExpiration": config.Captcha.StoreExpiration.AsDuration().String()}
}
if config.Local != nil {
admin["local"] = map[string]any{"storePath": config.Local.StorePath, "pathPrefix": config.Local.PathPrefix}
}
if config.Media != nil {
admin["media"] = map[string]any{"sessionTtl": config.Media.SessionTtl, "maxFileSize": config.Media.MaxFileSize}
}
if config.Email != nil {
email = map[string]any{"to": config.Email.To, "from": config.Email.From, "host": config.Email.Host, "secret": "******", "nickname": config.Email.Nickname, "port": config.Email.Port, "is-ssl": config.Email.IsSsl, "is-loginauth": config.Email.IsLoginAuth}
}
if config.Storage != nil {
storage := proto.Clone(config.Storage).(*conf.AdminBackend_Storage)
maskStorageSecrets(storage)
admin["storage"] = storage
}
if config.Zap != nil {
admin["zap"] = config.Zap
}
if config.Cors != nil {
admin["cors"] = config.Cors
}
if config.App != nil {
admin["app"] = config.App
}
data := s.runtime.Data()
if data != nil {
if data.Database != nil {
data.Database.Password = "******"
}
if data.Redis != nil {
data.Redis.Password = "******"
}
if data.Mongo != nil {
data.Mongo.Password = "******"
}
for _, database := range data.DatabaseList {
if database != nil {
database.Password = "******"
}
}
for _, redis := range data.RedisList {
if redis != nil {
redis.Password = "******"
}
}
}
dataMap := map[string]any{}
if raw, err := (protojson.MarshalOptions{UseProtoNames: true}).Marshal(data); err == nil {
_ = json.Unmarshal(raw, &dataMap)
}
return map[string]any{"config": map[string]any{"admin": admin, "email": email, "data": dataMap}}
}
func (s *SystemConfigService) SaveSystemConfig(ctx context.Context, req *dto.SetSystemConfigRequest) error {
config := s.runtime.Admin()
if config == nil {
return nil
}
next := proto.Clone(config).(*conf.AdminBackend)
data := s.runtime.Data()
next.RouterPrefix = req.Config.Admin.RouterPrefix
if next.System == nil {
next.System = &conf.AdminBackend_System{}
}
next.System.UseRedis = req.Config.Admin.System.UseRedis
next.System.UseMultipoint = req.Config.Admin.System.UseMultipoint
next.System.UseStrictAuth = req.Config.Admin.System.UseStrictAuth
next.System.DisableAutoMigrate = req.Config.Admin.System.DisableAutoMigrate
next.System.UseMongo = req.Config.Admin.System.UseMongo
if req.Config.Admin.Zap != nil {
next.Zap = req.Config.Admin.Zap
}
if req.Config.Admin.Cors != nil {
next.Cors = req.Config.Admin.Cors
}
if req.Config.Admin.App != nil {
next.App = req.Config.Admin.App
}
if next.Jwt != nil {
if req.Config.Admin.JWT.SigningKey != "" && req.Config.Admin.JWT.SigningKey != "******" {
next.Jwt.SigningKey = req.Config.Admin.JWT.SigningKey
}
if req.Config.Admin.JWT.Issuer != "" {
next.Jwt.Issuer = req.Config.Admin.JWT.Issuer
}
if value, err := time.ParseDuration(req.Config.Admin.JWT.ExpiresTime); err == nil && value > 0 {
next.Jwt.ExpiresTime = durationpb.New(value)
}
if value, err := time.ParseDuration(req.Config.Admin.JWT.BufferTime); err == nil && value >= 0 {
next.Jwt.BufferTime = durationpb.New(value)
}
}
if next.Captcha != nil {
if req.Config.Admin.Captcha.KeyLong > 0 {
next.Captcha.KeyLong = req.Config.Admin.Captcha.KeyLong
}
if req.Config.Admin.Captcha.ImgWidth > 0 {
next.Captcha.ImgWidth = req.Config.Admin.Captcha.ImgWidth
}
if req.Config.Admin.Captcha.ImgHeight > 0 {
next.Captcha.ImgHeight = req.Config.Admin.Captcha.ImgHeight
}
if value, err := time.ParseDuration(req.Config.Admin.Captcha.StoreExpiration); err == nil && value > 0 {
next.Captcha.StoreExpiration = durationpb.New(value)
}
}
if next.Local != nil {
if req.Config.Admin.Local.StorePath != "" {
next.Local.StorePath = req.Config.Admin.Local.StorePath
}
if req.Config.Admin.Local.PathPrefix != "" {
next.Local.PathPrefix = req.Config.Admin.Local.PathPrefix
}
}
if next.Media != nil {
if req.Config.Admin.Media.SessionTTL > 0 {
next.Media.SessionTtl = req.Config.Admin.Media.SessionTTL
}
next.Media.MaxFileSize = req.Config.Admin.Media.MaxFileSize
}
if req.Config.Admin.Storage != nil {
preserveStorageSecrets(req.Config.Admin.Storage, next.Storage)
next.Storage = req.Config.Admin.Storage
}
if next.Email != nil && req.Config.Email != nil {
next.Email.To, next.Email.From, next.Email.Host = req.Config.Email.To, req.Config.Email.From, req.Config.Email.Host
next.Email.Nickname, next.Email.Port = req.Config.Email.Nickname, req.Config.Email.Port
next.Email.IsSsl, next.Email.IsLoginAuth = req.Config.Email.IsSSL, req.Config.Email.IsLoginAuth
if req.Config.Email.Secret != "" && req.Config.Email.Secret != "******" {
next.Email.Secret = req.Config.Email.Secret
}
}
if req.Config.Data != nil {
if data == nil {
data = &conf.Data{}
}
if value := req.Config.Data.Database; value != nil {
password := value.Password
if data.Database != nil && (password == "" || password == "******") {
password = data.Database.Password
}
data.Database = &conf.Data_Database{Driver: value.Driver, Source: value.Source, Host: value.Host, Port: value.Port, User: value.User, Password: password, Name: value.Name, Config: value.Config, Path: value.Path, Prefix: value.Prefix, Engine: value.Engine, LogMode: value.LogMode, MaxIdleConns: value.MaxIdleConns, MaxOpenConns: value.MaxOpenConns, ConnMaxLifetime: value.ConnMaxLifetime, Singular: value.Singular}
}
if value := req.Config.Data.Redis; value != nil {
password := value.Password
if data.Redis != nil && (password == "" || password == "******") {
password = data.Redis.Password
}
redis := &conf.Data_Redis{Network: value.Network, Addr: value.Addr, Name: value.Name, Password: password, Db: value.DB, UseCluster: value.UseCluster, ClusterAddrs: value.ClusterAddrs}
if duration, parseErr := time.ParseDuration(value.ReadTimeout); parseErr == nil && duration >= 0 {
redis.ReadTimeout = durationpb.New(duration)
}
if duration, parseErr := time.ParseDuration(value.WriteTimeout); parseErr == nil && duration >= 0 {
redis.WriteTimeout = durationpb.New(duration)
}
data.Redis = redis
}
if req.Config.Data.DatabaseList != nil {
for i, item := range req.Config.Data.DatabaseList {
if item != nil && (item.Password == "" || item.Password == "******") && i < len(data.DatabaseList) && data.DatabaseList[i] != nil {
item.Password = data.DatabaseList[i].Password
}
}
data.DatabaseList = req.Config.Data.DatabaseList
}
if req.Config.Data.RedisList != nil {
for i, item := range req.Config.Data.RedisList {
if item != nil && (item.Password == "" || item.Password == "******") && i < len(data.RedisList) && data.RedisList[i] != nil {
item.Password = data.RedisList[i].Password
}
}
data.RedisList = req.Config.Data.RedisList
}
if req.Config.Data.Mongo != nil {
if data.Mongo != nil && (req.Config.Data.Mongo.Password == "" || req.Config.Data.Mongo.Password == "******") {
req.Config.Data.Mongo.Password = data.Mongo.Password
}
data.Mongo = req.Config.Data.Mongo
}
}
dataRaw, err := protojson.MarshalOptions{UseProtoNames: true}.Marshal(data)
if err != nil {
return err
}
adminRaw, err := protojson.MarshalOptions{UseProtoNames: true}.Marshal(next)
if err != nil {
return err
}
return s.uc.PersistRuntimeConfig(ctx, dataRaw, adminRaw)
}
func objectStores(storage *conf.AdminBackend_Storage) []*conf.AdminBackend_ObjectStore {
if storage == nil {
return nil
}
return []*conf.AdminBackend_ObjectStore{storage.AliyunOss, storage.HuaweiObs, storage.TencentCos, storage.AwsS3, storage.CloudflareR2, storage.Minio}
}
func maskStorageSecrets(storage *conf.AdminBackend_Storage) {
if storage.Qiniu != nil {
storage.Qiniu.SecretKey = "******"
}
for _, item := range objectStores(storage) {
if item != nil {
item.SecretKey = "******"
}
}
}
func preserveStorageSecrets(next, current *conf.AdminBackend_Storage) {
if next == nil || current == nil {
return
}
if next.Qiniu != nil && current.Qiniu != nil && (next.Qiniu.SecretKey == "" || next.Qiniu.SecretKey == "******") {
next.Qiniu.SecretKey = current.Qiniu.SecretKey
}
nextItems, currentItems := objectStores(next), objectStores(current)
for i := range nextItems {
if nextItems[i] != nil && currentItems[i] != nil && (nextItems[i].SecretKey == "" || nextItems[i].SecretKey == "******") {
nextItems[i].SecretKey = currentItems[i].SecretKey
}
}
}