2025-07-11 02:30:57 +08:00
|
|
|
|
package repo
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
2025-07-29 17:04:49 +08:00
|
|
|
|
"fmt"
|
2025-07-30 00:01:42 +08:00
|
|
|
|
"sync"
|
2025-10-28 11:07:00 +08:00
|
|
|
|
"time"
|
2025-07-29 17:04:49 +08:00
|
|
|
|
|
2025-07-18 09:42:07 +08:00
|
|
|
|
"github.com/ctwj/urldb/db/entity"
|
2025-08-18 13:38:52 +08:00
|
|
|
|
"github.com/ctwj/urldb/utils"
|
2025-07-11 02:30:57 +08:00
|
|
|
|
|
|
|
|
|
|
"gorm.io/gorm"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// SystemConfigRepository 系统配置Repository接口
|
|
|
|
|
|
type SystemConfigRepository interface {
|
|
|
|
|
|
BaseRepository[entity.SystemConfig]
|
2025-07-29 17:04:49 +08:00
|
|
|
|
FindAll() ([]entity.SystemConfig, error)
|
|
|
|
|
|
FindByKey(key string) (*entity.SystemConfig, error)
|
|
|
|
|
|
GetOrCreateDefault() ([]entity.SystemConfig, error)
|
|
|
|
|
|
UpsertConfigs(configs []entity.SystemConfig) error
|
|
|
|
|
|
GetConfigValue(key string) (string, error)
|
|
|
|
|
|
GetConfigBool(key string) (bool, error)
|
|
|
|
|
|
GetConfigInt(key string) (int, error)
|
2025-07-30 00:01:42 +08:00
|
|
|
|
GetCachedConfigs() map[string]string
|
|
|
|
|
|
ClearConfigCache()
|
2025-08-18 13:38:52 +08:00
|
|
|
|
SafeRefreshConfigCache() error
|
|
|
|
|
|
ValidateConfigIntegrity() error
|
2025-07-11 02:30:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SystemConfigRepositoryImpl 系统配置Repository实现
|
|
|
|
|
|
type SystemConfigRepositoryImpl struct {
|
|
|
|
|
|
BaseRepositoryImpl[entity.SystemConfig]
|
2025-07-30 00:01:42 +08:00
|
|
|
|
|
|
|
|
|
|
// 配置缓存
|
|
|
|
|
|
configCache map[string]string // key -> value
|
|
|
|
|
|
configCacheOnce sync.Once
|
|
|
|
|
|
configCacheMutex sync.RWMutex
|
2025-07-11 02:30:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// NewSystemConfigRepository 创建系统配置Repository
|
|
|
|
|
|
func NewSystemConfigRepository(db *gorm.DB) SystemConfigRepository {
|
|
|
|
|
|
return &SystemConfigRepositoryImpl{
|
|
|
|
|
|
BaseRepositoryImpl: BaseRepositoryImpl[entity.SystemConfig]{db: db},
|
2025-07-30 00:01:42 +08:00
|
|
|
|
configCache: make(map[string]string),
|
2025-07-11 02:30:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-29 17:04:49 +08:00
|
|
|
|
// FindAll 获取所有配置
|
|
|
|
|
|
func (r *SystemConfigRepositoryImpl) FindAll() ([]entity.SystemConfig, error) {
|
|
|
|
|
|
var configs []entity.SystemConfig
|
|
|
|
|
|
err := r.db.Find(&configs).Error
|
|
|
|
|
|
return configs, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// FindByKey 根据键查找配置
|
|
|
|
|
|
func (r *SystemConfigRepositoryImpl) FindByKey(key string) (*entity.SystemConfig, error) {
|
2025-07-11 02:30:57 +08:00
|
|
|
|
var config entity.SystemConfig
|
2025-07-29 17:04:49 +08:00
|
|
|
|
err := r.db.Where("key = ?", key).First(&config).Error
|
2025-07-11 02:30:57 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
return &config, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-29 17:04:49 +08:00
|
|
|
|
// UpsertConfigs 批量创建或更新配置
|
|
|
|
|
|
func (r *SystemConfigRepositoryImpl) UpsertConfigs(configs []entity.SystemConfig) error {
|
2025-08-18 13:38:52 +08:00
|
|
|
|
// 使用事务确保数据一致性
|
|
|
|
|
|
return r.db.Transaction(func(tx *gorm.DB) error {
|
|
|
|
|
|
// 在更新前备份当前配置
|
|
|
|
|
|
var existingConfigs []entity.SystemConfig
|
|
|
|
|
|
if err := tx.Find(&existingConfigs).Error; err != nil {
|
|
|
|
|
|
utils.Error("备份配置失败: %v", err)
|
|
|
|
|
|
// 不返回错误,继续执行更新
|
|
|
|
|
|
}
|
2025-07-11 02:30:57 +08:00
|
|
|
|
|
2025-08-18 13:38:52 +08:00
|
|
|
|
for _, config := range configs {
|
|
|
|
|
|
var existingConfig entity.SystemConfig
|
|
|
|
|
|
err := tx.Where("key = ?", config.Key).First(&existingConfig).Error
|
|
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
// 如果不存在,则创建
|
|
|
|
|
|
if err := tx.Create(&config).Error; err != nil {
|
|
|
|
|
|
utils.Error("创建配置失败 [%s]: %v", config.Key, err)
|
|
|
|
|
|
return fmt.Errorf("创建配置失败 [%s]: %v", config.Key, err)
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 如果存在,则更新
|
|
|
|
|
|
config.ID = existingConfig.ID
|
|
|
|
|
|
if err := tx.Save(&config).Error; err != nil {
|
|
|
|
|
|
utils.Error("更新配置失败 [%s]: %v", config.Key, err)
|
|
|
|
|
|
return fmt.Errorf("更新配置失败 [%s]: %v", config.Key, err)
|
|
|
|
|
|
}
|
2025-07-29 17:04:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-30 00:01:42 +08:00
|
|
|
|
|
2025-08-18 13:38:52 +08:00
|
|
|
|
// 更新成功后刷新缓存
|
|
|
|
|
|
r.refreshConfigCache()
|
|
|
|
|
|
return nil
|
|
|
|
|
|
})
|
2025-07-11 02:30:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetOrCreateDefault 获取配置或创建默认配置
|
2025-07-29 17:04:49 +08:00
|
|
|
|
func (r *SystemConfigRepositoryImpl) GetOrCreateDefault() ([]entity.SystemConfig, error) {
|
2025-10-28 11:07:00 +08:00
|
|
|
|
startTime := utils.GetCurrentTime()
|
2025-07-29 17:04:49 +08:00
|
|
|
|
configs, err := r.FindAll()
|
2025-10-28 11:07:00 +08:00
|
|
|
|
initialQueryDuration := time.Since(startTime)
|
2025-07-11 02:30:57 +08:00
|
|
|
|
if err != nil {
|
2025-10-28 11:07:00 +08:00
|
|
|
|
utils.Error("获取所有系统配置失败: %v,耗时: %v", err, initialQueryDuration)
|
2025-07-29 17:04:49 +08:00
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果没有配置,创建默认配置
|
|
|
|
|
|
if len(configs) == 0 {
|
2025-08-18 13:38:52 +08:00
|
|
|
|
utils.Info("未找到任何配置,创建默认配置")
|
2025-07-29 17:04:49 +08:00
|
|
|
|
defaultConfigs := []entity.SystemConfig{
|
|
|
|
|
|
{Key: entity.ConfigKeySiteTitle, Value: entity.ConfigDefaultSiteTitle, Type: entity.ConfigTypeString},
|
|
|
|
|
|
{Key: entity.ConfigKeySiteDescription, Value: entity.ConfigDefaultSiteDescription, Type: entity.ConfigTypeString},
|
|
|
|
|
|
{Key: entity.ConfigKeyKeywords, Value: entity.ConfigDefaultKeywords, Type: entity.ConfigTypeString},
|
|
|
|
|
|
{Key: entity.ConfigKeyAuthor, Value: entity.ConfigDefaultAuthor, Type: entity.ConfigTypeString},
|
|
|
|
|
|
{Key: entity.ConfigKeyCopyright, Value: entity.ConfigDefaultCopyright, Type: entity.ConfigTypeString},
|
|
|
|
|
|
{Key: entity.ConfigKeyAutoProcessReadyResources, Value: entity.ConfigDefaultAutoProcessReadyResources, Type: entity.ConfigTypeBool},
|
|
|
|
|
|
{Key: entity.ConfigKeyAutoProcessInterval, Value: entity.ConfigDefaultAutoProcessInterval, Type: entity.ConfigTypeInt},
|
|
|
|
|
|
{Key: entity.ConfigKeyAutoTransferEnabled, Value: entity.ConfigDefaultAutoTransferEnabled, Type: entity.ConfigTypeBool},
|
|
|
|
|
|
{Key: entity.ConfigKeyAutoTransferLimitDays, Value: entity.ConfigDefaultAutoTransferLimitDays, Type: entity.ConfigTypeInt},
|
|
|
|
|
|
{Key: entity.ConfigKeyAutoTransferMinSpace, Value: entity.ConfigDefaultAutoTransferMinSpace, Type: entity.ConfigTypeInt},
|
|
|
|
|
|
{Key: entity.ConfigKeyAutoFetchHotDramaEnabled, Value: entity.ConfigDefaultAutoFetchHotDramaEnabled, Type: entity.ConfigTypeBool},
|
|
|
|
|
|
{Key: entity.ConfigKeyApiToken, Value: entity.ConfigDefaultApiToken, Type: entity.ConfigTypeString},
|
2025-08-20 15:03:14 +08:00
|
|
|
|
{Key: entity.ConfigKeyForbiddenWords, Value: entity.ConfigDefaultForbiddenWords, Type: entity.ConfigTypeString},
|
|
|
|
|
|
{Key: entity.ConfigKeyAdKeywords, Value: entity.ConfigDefaultAdKeywords, Type: entity.ConfigTypeString},
|
|
|
|
|
|
{Key: entity.ConfigKeyAutoInsertAd, Value: entity.ConfigDefaultAutoInsertAd, Type: entity.ConfigTypeString},
|
2025-08-18 13:38:52 +08:00
|
|
|
|
{Key: entity.ConfigKeyPageSize, Value: entity.ConfigDefaultPageSize, Type: entity.ConfigTypeInt},
|
|
|
|
|
|
{Key: entity.ConfigKeyMaintenanceMode, Value: entity.ConfigDefaultMaintenanceMode, Type: entity.ConfigTypeBool},
|
|
|
|
|
|
{Key: entity.ConfigKeyEnableRegister, Value: entity.ConfigDefaultEnableRegister, Type: entity.ConfigTypeBool},
|
|
|
|
|
|
{Key: entity.ConfigKeyThirdPartyStatsCode, Value: entity.ConfigDefaultThirdPartyStatsCode, Type: entity.ConfigTypeString},
|
2025-08-20 15:03:14 +08:00
|
|
|
|
{Key: entity.ConfigKeyMeilisearchEnabled, Value: entity.ConfigDefaultMeilisearchEnabled, Type: entity.ConfigTypeBool},
|
|
|
|
|
|
{Key: entity.ConfigKeyMeilisearchHost, Value: entity.ConfigDefaultMeilisearchHost, Type: entity.ConfigTypeString},
|
|
|
|
|
|
{Key: entity.ConfigKeyMeilisearchPort, Value: entity.ConfigDefaultMeilisearchPort, Type: entity.ConfigTypeString},
|
|
|
|
|
|
{Key: entity.ConfigKeyMeilisearchMasterKey, Value: entity.ConfigDefaultMeilisearchMasterKey, Type: entity.ConfigTypeString},
|
|
|
|
|
|
{Key: entity.ConfigKeyMeilisearchIndexName, Value: entity.ConfigDefaultMeilisearchIndexName, Type: entity.ConfigTypeString},
|
2025-10-20 01:52:19 +08:00
|
|
|
|
{Key: entity.ConfigKeyEnableAnnouncements, Value: entity.ConfigDefaultEnableAnnouncements, Type: entity.ConfigTypeBool},
|
|
|
|
|
|
{Key: entity.ConfigKeyAnnouncements, Value: entity.ConfigDefaultAnnouncements, Type: entity.ConfigTypeJSON},
|
|
|
|
|
|
{Key: entity.ConfigKeyEnableFloatButtons, Value: entity.ConfigDefaultEnableFloatButtons, Type: entity.ConfigTypeBool},
|
|
|
|
|
|
{Key: entity.ConfigKeyWechatSearchImage, Value: entity.ConfigDefaultWechatSearchImage, Type: entity.ConfigTypeString},
|
|
|
|
|
|
{Key: entity.ConfigKeyTelegramQrImage, Value: entity.ConfigDefaultTelegramQrImage, Type: entity.ConfigTypeString},
|
2025-10-27 23:41:35 +08:00
|
|
|
|
{Key: entity.ConfigKeyQrCodeStyle, Value: entity.ConfigDefaultQrCodeStyle, Type: entity.ConfigTypeString},
|
2025-07-11 02:30:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-28 11:07:00 +08:00
|
|
|
|
createStart := utils.GetCurrentTime()
|
2025-07-29 17:04:49 +08:00
|
|
|
|
err = r.UpsertConfigs(defaultConfigs)
|
2025-10-28 11:07:00 +08:00
|
|
|
|
createDuration := time.Since(createStart)
|
2025-07-11 02:30:57 +08:00
|
|
|
|
if err != nil {
|
2025-10-28 11:07:00 +08:00
|
|
|
|
utils.Error("创建默认系统配置失败: %v,耗时: %v", err, createDuration)
|
2025-07-11 02:30:57 +08:00
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-28 11:07:00 +08:00
|
|
|
|
totalDuration := time.Since(startTime)
|
|
|
|
|
|
utils.Info("创建默认系统配置成功,数量: %d,总耗时: %v", len(defaultConfigs), totalDuration)
|
2025-07-29 17:04:49 +08:00
|
|
|
|
return defaultConfigs, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-08 17:26:48 +08:00
|
|
|
|
// 检查是否有缺失的配置项,如果有则添加
|
|
|
|
|
|
requiredConfigs := map[string]entity.SystemConfig{
|
|
|
|
|
|
entity.ConfigKeySiteTitle: {Key: entity.ConfigKeySiteTitle, Value: entity.ConfigDefaultSiteTitle, Type: entity.ConfigTypeString},
|
|
|
|
|
|
entity.ConfigKeySiteDescription: {Key: entity.ConfigKeySiteDescription, Value: entity.ConfigDefaultSiteDescription, Type: entity.ConfigTypeString},
|
|
|
|
|
|
entity.ConfigKeyKeywords: {Key: entity.ConfigKeyKeywords, Value: entity.ConfigDefaultKeywords, Type: entity.ConfigTypeString},
|
|
|
|
|
|
entity.ConfigKeyAuthor: {Key: entity.ConfigKeyAuthor, Value: entity.ConfigDefaultAuthor, Type: entity.ConfigTypeString},
|
|
|
|
|
|
entity.ConfigKeyCopyright: {Key: entity.ConfigKeyCopyright, Value: entity.ConfigDefaultCopyright, Type: entity.ConfigTypeString},
|
|
|
|
|
|
entity.ConfigKeyAutoProcessReadyResources: {Key: entity.ConfigKeyAutoProcessReadyResources, Value: entity.ConfigDefaultAutoProcessReadyResources, Type: entity.ConfigTypeBool},
|
|
|
|
|
|
entity.ConfigKeyAutoProcessInterval: {Key: entity.ConfigKeyAutoProcessInterval, Value: entity.ConfigDefaultAutoProcessInterval, Type: entity.ConfigTypeInt},
|
|
|
|
|
|
entity.ConfigKeyAutoTransferEnabled: {Key: entity.ConfigKeyAutoTransferEnabled, Value: entity.ConfigDefaultAutoTransferEnabled, Type: entity.ConfigTypeBool},
|
|
|
|
|
|
entity.ConfigKeyAutoTransferLimitDays: {Key: entity.ConfigKeyAutoTransferLimitDays, Value: entity.ConfigDefaultAutoTransferLimitDays, Type: entity.ConfigTypeInt},
|
|
|
|
|
|
entity.ConfigKeyAutoTransferMinSpace: {Key: entity.ConfigKeyAutoTransferMinSpace, Value: entity.ConfigDefaultAutoTransferMinSpace, Type: entity.ConfigTypeInt},
|
|
|
|
|
|
entity.ConfigKeyAutoFetchHotDramaEnabled: {Key: entity.ConfigKeyAutoFetchHotDramaEnabled, Value: entity.ConfigDefaultAutoFetchHotDramaEnabled, Type: entity.ConfigTypeBool},
|
|
|
|
|
|
entity.ConfigKeyApiToken: {Key: entity.ConfigKeyApiToken, Value: entity.ConfigDefaultApiToken, Type: entity.ConfigTypeString},
|
2025-08-20 15:03:14 +08:00
|
|
|
|
entity.ConfigKeyForbiddenWords: {Key: entity.ConfigKeyForbiddenWords, Value: entity.ConfigDefaultForbiddenWords, Type: entity.ConfigTypeString},
|
2025-08-13 00:28:18 +08:00
|
|
|
|
entity.ConfigKeyAdKeywords: {Key: entity.ConfigKeyAdKeywords, Value: entity.ConfigDefaultAdKeywords, Type: entity.ConfigTypeString},
|
|
|
|
|
|
entity.ConfigKeyAutoInsertAd: {Key: entity.ConfigKeyAutoInsertAd, Value: entity.ConfigDefaultAutoInsertAd, Type: entity.ConfigTypeString},
|
2025-08-08 17:26:48 +08:00
|
|
|
|
entity.ConfigKeyPageSize: {Key: entity.ConfigKeyPageSize, Value: entity.ConfigDefaultPageSize, Type: entity.ConfigTypeInt},
|
|
|
|
|
|
entity.ConfigKeyMaintenanceMode: {Key: entity.ConfigKeyMaintenanceMode, Value: entity.ConfigDefaultMaintenanceMode, Type: entity.ConfigTypeBool},
|
|
|
|
|
|
entity.ConfigKeyEnableRegister: {Key: entity.ConfigKeyEnableRegister, Value: entity.ConfigDefaultEnableRegister, Type: entity.ConfigTypeBool},
|
2025-08-10 13:52:41 +08:00
|
|
|
|
entity.ConfigKeyThirdPartyStatsCode: {Key: entity.ConfigKeyThirdPartyStatsCode, Value: entity.ConfigDefaultThirdPartyStatsCode, Type: entity.ConfigTypeString},
|
2025-08-20 15:03:14 +08:00
|
|
|
|
entity.ConfigKeyMeilisearchEnabled: {Key: entity.ConfigKeyMeilisearchEnabled, Value: entity.ConfigDefaultMeilisearchEnabled, Type: entity.ConfigTypeBool},
|
|
|
|
|
|
entity.ConfigKeyMeilisearchHost: {Key: entity.ConfigKeyMeilisearchHost, Value: entity.ConfigDefaultMeilisearchHost, Type: entity.ConfigTypeString},
|
|
|
|
|
|
entity.ConfigKeyMeilisearchPort: {Key: entity.ConfigKeyMeilisearchPort, Value: entity.ConfigDefaultMeilisearchPort, Type: entity.ConfigTypeString},
|
|
|
|
|
|
entity.ConfigKeyMeilisearchMasterKey: {Key: entity.ConfigKeyMeilisearchMasterKey, Value: entity.ConfigDefaultMeilisearchMasterKey, Type: entity.ConfigTypeString},
|
|
|
|
|
|
entity.ConfigKeyMeilisearchIndexName: {Key: entity.ConfigKeyMeilisearchIndexName, Value: entity.ConfigDefaultMeilisearchIndexName, Type: entity.ConfigTypeString},
|
2025-10-20 01:52:19 +08:00
|
|
|
|
entity.ConfigKeyEnableAnnouncements: {Key: entity.ConfigKeyEnableAnnouncements, Value: entity.ConfigDefaultEnableAnnouncements, Type: entity.ConfigTypeBool},
|
|
|
|
|
|
entity.ConfigKeyAnnouncements: {Key: entity.ConfigKeyAnnouncements, Value: entity.ConfigDefaultAnnouncements, Type: entity.ConfigTypeJSON},
|
|
|
|
|
|
entity.ConfigKeyEnableFloatButtons: {Key: entity.ConfigKeyEnableFloatButtons, Value: entity.ConfigDefaultEnableFloatButtons, Type: entity.ConfigTypeBool},
|
|
|
|
|
|
entity.ConfigKeyWechatSearchImage: {Key: entity.ConfigKeyWechatSearchImage, Value: entity.ConfigDefaultWechatSearchImage, Type: entity.ConfigTypeString},
|
|
|
|
|
|
entity.ConfigKeyTelegramQrImage: {Key: entity.ConfigKeyTelegramQrImage, Value: entity.ConfigDefaultTelegramQrImage, Type: entity.ConfigTypeString},
|
2025-08-08 17:26:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查现有配置中是否有缺失的配置项
|
|
|
|
|
|
existingKeys := make(map[string]bool)
|
|
|
|
|
|
for _, config := range configs {
|
|
|
|
|
|
existingKeys[config.Key] = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 找出缺失的配置项
|
|
|
|
|
|
var missingConfigs []entity.SystemConfig
|
|
|
|
|
|
for key, requiredConfig := range requiredConfigs {
|
|
|
|
|
|
if !existingKeys[key] {
|
|
|
|
|
|
missingConfigs = append(missingConfigs, requiredConfig)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果有缺失的配置项,则添加它们
|
|
|
|
|
|
if len(missingConfigs) > 0 {
|
2025-10-28 11:07:00 +08:00
|
|
|
|
upsertStart := utils.GetCurrentTime()
|
2025-08-08 17:26:48 +08:00
|
|
|
|
err = r.UpsertConfigs(missingConfigs)
|
2025-10-28 11:07:00 +08:00
|
|
|
|
upsertDuration := time.Since(upsertStart)
|
2025-08-08 17:26:48 +08:00
|
|
|
|
if err != nil {
|
2025-10-28 11:07:00 +08:00
|
|
|
|
utils.Error("添加缺失的系统配置失败: %v,耗时: %v", err, upsertDuration)
|
2025-08-08 17:26:48 +08:00
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
2025-10-28 11:07:00 +08:00
|
|
|
|
utils.Debug("添加缺失的系统配置完成,数量: %d,耗时: %v", len(missingConfigs), upsertDuration)
|
2025-08-08 17:26:48 +08:00
|
|
|
|
// 重新获取所有配置
|
|
|
|
|
|
configs, err = r.FindAll()
|
|
|
|
|
|
if err != nil {
|
2025-10-28 11:07:00 +08:00
|
|
|
|
utils.Error("重新获取所有系统配置失败: %v", err)
|
2025-08-08 17:26:48 +08:00
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-28 11:07:00 +08:00
|
|
|
|
totalDuration := time.Since(startTime)
|
|
|
|
|
|
utils.Debug("GetOrCreateDefault完成,总数: %d,总耗时: %v", len(configs), totalDuration)
|
2025-07-29 17:04:49 +08:00
|
|
|
|
return configs, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-30 00:01:42 +08:00
|
|
|
|
// initConfigCache 初始化配置缓存
|
|
|
|
|
|
func (r *SystemConfigRepositoryImpl) initConfigCache() {
|
|
|
|
|
|
r.configCacheOnce.Do(func() {
|
|
|
|
|
|
// 获取所有配置
|
|
|
|
|
|
configs, err := r.FindAll()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
// 如果获取失败,尝试创建默认配置
|
|
|
|
|
|
configs, err = r.GetOrCreateDefault()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化缓存
|
|
|
|
|
|
r.configCacheMutex.Lock()
|
|
|
|
|
|
defer r.configCacheMutex.Unlock()
|
|
|
|
|
|
|
|
|
|
|
|
for _, config := range configs {
|
|
|
|
|
|
r.configCache[config.Key] = config.Value
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// refreshConfigCache 刷新配置缓存
|
|
|
|
|
|
func (r *SystemConfigRepositoryImpl) refreshConfigCache() {
|
|
|
|
|
|
// 重置Once,允许重新初始化
|
|
|
|
|
|
r.configCacheOnce = sync.Once{}
|
|
|
|
|
|
|
|
|
|
|
|
// 清空缓存
|
|
|
|
|
|
r.configCacheMutex.Lock()
|
|
|
|
|
|
r.configCache = make(map[string]string)
|
|
|
|
|
|
r.configCacheMutex.Unlock()
|
|
|
|
|
|
|
|
|
|
|
|
// 重新初始化缓存
|
|
|
|
|
|
r.initConfigCache()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-18 13:38:52 +08:00
|
|
|
|
// SafeRefreshConfigCache 安全的刷新配置缓存(带错误处理)
|
|
|
|
|
|
func (r *SystemConfigRepositoryImpl) SafeRefreshConfigCache() error {
|
|
|
|
|
|
defer func() {
|
|
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
|
|
utils.Error("配置缓存刷新时发生panic: %v", r)
|
|
|
|
|
|
}
|
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
|
|
r.refreshConfigCache()
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ValidateConfigIntegrity 验证配置完整性
|
|
|
|
|
|
func (r *SystemConfigRepositoryImpl) ValidateConfigIntegrity() error {
|
|
|
|
|
|
configs, err := r.FindAll()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("获取配置失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查关键配置是否存在
|
|
|
|
|
|
requiredKeys := []string{
|
|
|
|
|
|
entity.ConfigKeySiteTitle,
|
|
|
|
|
|
entity.ConfigKeySiteDescription,
|
|
|
|
|
|
entity.ConfigKeyKeywords,
|
|
|
|
|
|
entity.ConfigKeyAuthor,
|
|
|
|
|
|
entity.ConfigKeyCopyright,
|
|
|
|
|
|
entity.ConfigKeyAutoProcessReadyResources,
|
|
|
|
|
|
entity.ConfigKeyAutoProcessInterval,
|
|
|
|
|
|
entity.ConfigKeyAutoTransferEnabled,
|
|
|
|
|
|
entity.ConfigKeyAutoTransferLimitDays,
|
|
|
|
|
|
entity.ConfigKeyAutoTransferMinSpace,
|
|
|
|
|
|
entity.ConfigKeyAutoFetchHotDramaEnabled,
|
|
|
|
|
|
entity.ConfigKeyApiToken,
|
|
|
|
|
|
entity.ConfigKeyPageSize,
|
|
|
|
|
|
entity.ConfigKeyMaintenanceMode,
|
|
|
|
|
|
entity.ConfigKeyEnableRegister,
|
|
|
|
|
|
entity.ConfigKeyThirdPartyStatsCode,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
existingKeys := make(map[string]bool)
|
|
|
|
|
|
for _, config := range configs {
|
|
|
|
|
|
existingKeys[config.Key] = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var missingKeys []string
|
|
|
|
|
|
for _, key := range requiredKeys {
|
|
|
|
|
|
if !existingKeys[key] {
|
|
|
|
|
|
missingKeys = append(missingKeys, key)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if len(missingKeys) > 0 {
|
|
|
|
|
|
utils.Error("发现缺失的配置项: %v", missingKeys)
|
|
|
|
|
|
return fmt.Errorf("配置不完整,缺失: %v", missingKeys)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
utils.Info("配置完整性检查通过")
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-29 17:04:49 +08:00
|
|
|
|
// GetConfigValue 获取配置值(字符串)
|
|
|
|
|
|
func (r *SystemConfigRepositoryImpl) GetConfigValue(key string) (string, error) {
|
2025-07-30 00:01:42 +08:00
|
|
|
|
// 初始化缓存
|
|
|
|
|
|
r.initConfigCache()
|
|
|
|
|
|
|
|
|
|
|
|
// 从缓存中读取
|
|
|
|
|
|
r.configCacheMutex.RLock()
|
|
|
|
|
|
value, exists := r.configCache[key]
|
|
|
|
|
|
r.configCacheMutex.RUnlock()
|
|
|
|
|
|
|
|
|
|
|
|
if exists {
|
|
|
|
|
|
return value, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果缓存中没有,尝试从数据库获取(可能是新添加的配置)
|
2025-07-29 17:04:49 +08:00
|
|
|
|
config, err := r.FindByKey(key)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return "", err
|
|
|
|
|
|
}
|
2025-07-30 00:01:42 +08:00
|
|
|
|
|
|
|
|
|
|
// 更新缓存
|
|
|
|
|
|
r.configCacheMutex.Lock()
|
|
|
|
|
|
r.configCache[key] = config.Value
|
|
|
|
|
|
r.configCacheMutex.Unlock()
|
|
|
|
|
|
|
2025-07-29 17:04:49 +08:00
|
|
|
|
return config.Value, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetConfigBool 获取配置值(布尔)
|
|
|
|
|
|
func (r *SystemConfigRepositoryImpl) GetConfigBool(key string) (bool, error) {
|
|
|
|
|
|
value, err := r.GetConfigValue(key)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return false, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
switch value {
|
|
|
|
|
|
case "true", "1", "yes":
|
|
|
|
|
|
return true, nil
|
|
|
|
|
|
case "false", "0", "no":
|
|
|
|
|
|
return false, nil
|
|
|
|
|
|
default:
|
|
|
|
|
|
return false, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetConfigInt 获取配置值(整数)
|
|
|
|
|
|
func (r *SystemConfigRepositoryImpl) GetConfigInt(key string) (int, error) {
|
|
|
|
|
|
value, err := r.GetConfigValue(key)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return 0, err
|
2025-07-11 02:30:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-29 17:04:49 +08:00
|
|
|
|
// 这里需要导入 strconv 包,但为了避免循环导入,我们使用简单的转换
|
|
|
|
|
|
var result int
|
|
|
|
|
|
_, err = fmt.Sscanf(value, "%d", &result)
|
|
|
|
|
|
return result, err
|
2025-07-11 02:30:57 +08:00
|
|
|
|
}
|
2025-07-30 00:01:42 +08:00
|
|
|
|
|
|
|
|
|
|
// GetCachedConfigs 获取所有缓存的配置(用于调试)
|
|
|
|
|
|
func (r *SystemConfigRepositoryImpl) GetCachedConfigs() map[string]string {
|
|
|
|
|
|
r.initConfigCache()
|
|
|
|
|
|
|
|
|
|
|
|
r.configCacheMutex.RLock()
|
|
|
|
|
|
defer r.configCacheMutex.RUnlock()
|
|
|
|
|
|
|
|
|
|
|
|
// 返回缓存的副本
|
|
|
|
|
|
result := make(map[string]string)
|
|
|
|
|
|
for k, v := range r.configCache {
|
|
|
|
|
|
result[k] = v
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ClearConfigCache 清空配置缓存(用于测试或手动刷新)
|
|
|
|
|
|
func (r *SystemConfigRepositoryImpl) ClearConfigCache() {
|
|
|
|
|
|
r.configCacheMutex.Lock()
|
|
|
|
|
|
r.configCache = make(map[string]string)
|
|
|
|
|
|
r.configCacheMutex.Unlock()
|
|
|
|
|
|
|
|
|
|
|
|
// 重置Once,允许重新初始化
|
|
|
|
|
|
r.configCacheOnce = sync.Once{}
|
|
|
|
|
|
}
|