update: 系统配置重构

This commit is contained in:
Kerwin
2025-07-29 17:04:49 +08:00
parent ba7dd4d064
commit 4d3f4a082e
10 changed files with 528 additions and 218 deletions

View File

@@ -3,7 +3,6 @@ package converter
import ( import (
"github.com/ctwj/urldb/db/dto" "github.com/ctwj/urldb/db/dto"
"github.com/ctwj/urldb/db/entity" "github.com/ctwj/urldb/db/entity"
"github.com/gin-gonic/gin"
) )
// ToResourceResponse 将Resource实体转换为ResourceResponse // ToResourceResponse 将Resource实体转换为ResourceResponse
@@ -214,25 +213,3 @@ func ToReadyResourceResponseList(resources []entity.ReadyResource) []dto.ReadyRe
// Key: req.Key, // Key: req.Key,
// } // }
// } // }
// SystemConfigToPublicResponse 返回不含 api_token 的系统配置响应
func SystemConfigToPublicResponse(config *entity.SystemConfig) gin.H {
return gin.H{
"id": config.ID,
"created_at": config.CreatedAt.Format("2006-01-02 15:04:05"),
"updated_at": config.UpdatedAt.Format("2006-01-02 15:04:05"),
"site_title": config.SiteTitle,
"site_description": config.SiteDescription,
"keywords": config.Keywords,
"author": config.Author,
"copyright": config.Copyright,
"auto_process_ready_resources": config.AutoProcessReadyResources,
"auto_process_interval": config.AutoProcessInterval,
"auto_transfer_enabled": config.AutoTransferEnabled,
"auto_transfer_limit_days": config.AutoTransferLimitDays,
"auto_transfer_min_space": config.AutoTransferMinSpace,
"auto_fetch_hot_drama_enabled": config.AutoFetchHotDramaEnabled,
"page_size": config.PageSize,
"maintenance_mode": config.MaintenanceMode,
}
}

View File

@@ -1,74 +1,200 @@
package converter package converter
import ( import (
"strconv"
"time" "time"
"github.com/ctwj/urldb/db/dto" "github.com/ctwj/urldb/db/dto"
"github.com/ctwj/urldb/db/entity" "github.com/ctwj/urldb/db/entity"
) )
// SystemConfigToResponse 将系统配置实体转换为响应DTO // SystemConfigToResponse 将系统配置实体列表转换为响应DTO
func SystemConfigToResponse(config *entity.SystemConfig) *dto.SystemConfigResponse { func SystemConfigToResponse(configs []entity.SystemConfig) *dto.SystemConfigResponse {
if config == nil { if len(configs) == 0 {
return nil return getDefaultConfigResponse()
} }
return &dto.SystemConfigResponse{ response := getDefaultConfigResponse()
ID: config.ID,
CreatedAt: config.CreatedAt.Format(time.RFC3339),
UpdatedAt: config.UpdatedAt.Format(time.RFC3339),
// SEO 配置 // 将键值对转换为结构体
SiteTitle: config.SiteTitle, for _, config := range configs {
SiteDescription: config.SiteDescription, switch config.Key {
Keywords: config.Keywords, case entity.ConfigKeySiteTitle:
Author: config.Author, response.SiteTitle = config.Value
Copyright: config.Copyright, case entity.ConfigKeySiteDescription:
response.SiteDescription = config.Value
// 自动处理配置组 case entity.ConfigKeyKeywords:
AutoProcessReadyResources: config.AutoProcessReadyResources, response.Keywords = config.Value
AutoProcessInterval: config.AutoProcessInterval, case entity.ConfigKeyAuthor:
AutoTransferEnabled: config.AutoTransferEnabled, response.Author = config.Value
AutoTransferLimitDays: config.AutoTransferLimitDays, case entity.ConfigKeyCopyright:
AutoTransferMinSpace: config.AutoTransferMinSpace, response.Copyright = config.Value
AutoFetchHotDramaEnabled: config.AutoFetchHotDramaEnabled, case entity.ConfigKeyAutoProcessReadyResources:
if val, err := strconv.ParseBool(config.Value); err == nil {
// API配置 response.AutoProcessReadyResources = val
ApiToken: config.ApiToken, }
case entity.ConfigKeyAutoProcessInterval:
// 其他配置 if val, err := strconv.Atoi(config.Value); err == nil {
PageSize: config.PageSize, response.AutoProcessInterval = val
MaintenanceMode: config.MaintenanceMode, }
case entity.ConfigKeyAutoTransferEnabled:
if val, err := strconv.ParseBool(config.Value); err == nil {
response.AutoTransferEnabled = val
}
case entity.ConfigKeyAutoTransferLimitDays:
if val, err := strconv.Atoi(config.Value); err == nil {
response.AutoTransferLimitDays = val
}
case entity.ConfigKeyAutoTransferMinSpace:
if val, err := strconv.Atoi(config.Value); err == nil {
response.AutoTransferMinSpace = val
}
case entity.ConfigKeyAutoFetchHotDramaEnabled:
if val, err := strconv.ParseBool(config.Value); err == nil {
response.AutoFetchHotDramaEnabled = val
}
case entity.ConfigKeyApiToken:
response.ApiToken = config.Value
case entity.ConfigKeyPageSize:
if val, err := strconv.Atoi(config.Value); err == nil {
response.PageSize = val
}
case entity.ConfigKeyMaintenanceMode:
if val, err := strconv.ParseBool(config.Value); err == nil {
response.MaintenanceMode = val
}
}
} }
// 设置时间戳(使用第一个配置的时间)
if len(configs) > 0 {
response.CreatedAt = configs[0].CreatedAt.Format(time.RFC3339)
response.UpdatedAt = configs[0].UpdatedAt.Format(time.RFC3339)
}
return response
} }
// RequestToSystemConfig 将请求DTO转换为系统配置实体 // RequestToSystemConfig 将请求DTO转换为系统配置实体列表
func RequestToSystemConfig(req *dto.SystemConfigRequest) *entity.SystemConfig { func RequestToSystemConfig(req *dto.SystemConfigRequest) []entity.SystemConfig {
if req == nil { if req == nil {
return nil return nil
} }
return &entity.SystemConfig{ configs := []entity.SystemConfig{
// SEO 配置 {Key: entity.ConfigKeySiteTitle, Value: req.SiteTitle, Type: entity.ConfigTypeString},
SiteTitle: req.SiteTitle, {Key: entity.ConfigKeySiteDescription, Value: req.SiteDescription, Type: entity.ConfigTypeString},
SiteDescription: req.SiteDescription, {Key: entity.ConfigKeyKeywords, Value: req.Keywords, Type: entity.ConfigTypeString},
Keywords: req.Keywords, {Key: entity.ConfigKeyAuthor, Value: req.Author, Type: entity.ConfigTypeString},
Author: req.Author, {Key: entity.ConfigKeyCopyright, Value: req.Copyright, Type: entity.ConfigTypeString},
Copyright: req.Copyright, {Key: entity.ConfigKeyAutoProcessReadyResources, Value: strconv.FormatBool(req.AutoProcessReadyResources), Type: entity.ConfigTypeBool},
{Key: entity.ConfigKeyAutoProcessInterval, Value: strconv.Itoa(req.AutoProcessInterval), Type: entity.ConfigTypeInt},
{Key: entity.ConfigKeyAutoTransferEnabled, Value: strconv.FormatBool(req.AutoTransferEnabled), Type: entity.ConfigTypeBool},
{Key: entity.ConfigKeyAutoTransferLimitDays, Value: strconv.Itoa(req.AutoTransferLimitDays), Type: entity.ConfigTypeInt},
{Key: entity.ConfigKeyAutoTransferMinSpace, Value: strconv.Itoa(req.AutoTransferMinSpace), Type: entity.ConfigTypeInt},
{Key: entity.ConfigKeyAutoFetchHotDramaEnabled, Value: strconv.FormatBool(req.AutoFetchHotDramaEnabled), Type: entity.ConfigTypeBool},
{Key: entity.ConfigKeyApiToken, Value: req.ApiToken, Type: entity.ConfigTypeString},
{Key: entity.ConfigKeyPageSize, Value: strconv.Itoa(req.PageSize), Type: entity.ConfigTypeInt},
{Key: entity.ConfigKeyMaintenanceMode, Value: strconv.FormatBool(req.MaintenanceMode), Type: entity.ConfigTypeBool},
}
// 自动处理配置组 return configs
AutoProcessReadyResources: req.AutoProcessReadyResources, }
AutoProcessInterval: req.AutoProcessInterval,
AutoTransferEnabled: req.AutoTransferEnabled,
AutoTransferLimitDays: req.AutoTransferLimitDays,
AutoTransferMinSpace: req.AutoTransferMinSpace,
AutoFetchHotDramaEnabled: req.AutoFetchHotDramaEnabled,
// API配置 // SystemConfigToPublicResponse 返回不含 api_token 的系统配置响应
ApiToken: req.ApiToken, func SystemConfigToPublicResponse(configs []entity.SystemConfig) map[string]interface{} {
response := map[string]interface{}{
entity.ConfigResponseFieldID: 0,
entity.ConfigResponseFieldCreatedAt: time.Now().Format("2006-01-02 15:04:05"),
entity.ConfigResponseFieldUpdatedAt: time.Now().Format("2006-01-02 15:04:05"),
entity.ConfigResponseFieldSiteTitle: entity.ConfigDefaultSiteTitle,
entity.ConfigResponseFieldSiteDescription: entity.ConfigDefaultSiteDescription,
entity.ConfigResponseFieldKeywords: entity.ConfigDefaultKeywords,
entity.ConfigResponseFieldAuthor: entity.ConfigDefaultAuthor,
entity.ConfigResponseFieldCopyright: entity.ConfigDefaultCopyright,
entity.ConfigResponseFieldAutoProcessReadyResources: false,
entity.ConfigResponseFieldAutoProcessInterval: 30,
entity.ConfigResponseFieldAutoTransferEnabled: false,
entity.ConfigResponseFieldAutoTransferLimitDays: 0,
entity.ConfigResponseFieldAutoTransferMinSpace: 100,
entity.ConfigResponseFieldAutoFetchHotDramaEnabled: false,
entity.ConfigResponseFieldPageSize: 100,
entity.ConfigResponseFieldMaintenanceMode: false,
}
// 其他配置 // 将键值对转换为map
PageSize: req.PageSize, for _, config := range configs {
MaintenanceMode: req.MaintenanceMode, switch config.Key {
case entity.ConfigKeySiteTitle:
response[entity.ConfigResponseFieldSiteTitle] = config.Value
case entity.ConfigKeySiteDescription:
response[entity.ConfigResponseFieldSiteDescription] = config.Value
case entity.ConfigKeyKeywords:
response[entity.ConfigResponseFieldKeywords] = config.Value
case entity.ConfigKeyAuthor:
response[entity.ConfigResponseFieldAuthor] = config.Value
case entity.ConfigKeyCopyright:
response[entity.ConfigResponseFieldCopyright] = config.Value
case entity.ConfigKeyAutoProcessReadyResources:
if val, err := strconv.ParseBool(config.Value); err == nil {
response[entity.ConfigResponseFieldAutoProcessReadyResources] = val
}
case entity.ConfigKeyAutoProcessInterval:
if val, err := strconv.Atoi(config.Value); err == nil {
response[entity.ConfigResponseFieldAutoProcessInterval] = val
}
case entity.ConfigKeyAutoTransferEnabled:
if val, err := strconv.ParseBool(config.Value); err == nil {
response[entity.ConfigResponseFieldAutoTransferEnabled] = val
}
case entity.ConfigKeyAutoTransferLimitDays:
if val, err := strconv.Atoi(config.Value); err == nil {
response[entity.ConfigResponseFieldAutoTransferLimitDays] = val
}
case entity.ConfigKeyAutoTransferMinSpace:
if val, err := strconv.Atoi(config.Value); err == nil {
response[entity.ConfigResponseFieldAutoTransferMinSpace] = val
}
case entity.ConfigKeyAutoFetchHotDramaEnabled:
if val, err := strconv.ParseBool(config.Value); err == nil {
response[entity.ConfigResponseFieldAutoFetchHotDramaEnabled] = val
}
case entity.ConfigKeyPageSize:
if val, err := strconv.Atoi(config.Value); err == nil {
response[entity.ConfigResponseFieldPageSize] = val
}
case entity.ConfigKeyMaintenanceMode:
if val, err := strconv.ParseBool(config.Value); err == nil {
response[entity.ConfigResponseFieldMaintenanceMode] = val
}
}
}
// 设置时间戳(使用第一个配置的时间)
if len(configs) > 0 {
response[entity.ConfigResponseFieldCreatedAt] = configs[0].CreatedAt.Format("2006-01-02 15:04:05")
response[entity.ConfigResponseFieldUpdatedAt] = configs[0].UpdatedAt.Format("2006-01-02 15:04:05")
}
return response
}
// getDefaultConfigResponse 获取默认配置响应
func getDefaultConfigResponse() *dto.SystemConfigResponse {
return &dto.SystemConfigResponse{
SiteTitle: entity.ConfigDefaultSiteTitle,
SiteDescription: entity.ConfigDefaultSiteDescription,
Keywords: entity.ConfigDefaultKeywords,
Author: entity.ConfigDefaultAuthor,
Copyright: entity.ConfigDefaultCopyright,
AutoProcessReadyResources: false,
AutoProcessInterval: 30,
AutoTransferEnabled: false,
AutoTransferLimitDays: 0,
AutoTransferMinSpace: 100,
AutoFetchHotDramaEnabled: false,
ApiToken: entity.ConfigDefaultApiToken,
PageSize: 100,
MaintenanceMode: false,
} }
} }

View File

@@ -53,3 +53,15 @@ type SystemConfigResponse struct {
PageSize int `json:"page_size"` PageSize int `json:"page_size"`
MaintenanceMode bool `json:"maintenance_mode"` MaintenanceMode bool `json:"maintenance_mode"`
} }
// SystemConfigItem 单个配置项
type SystemConfigItem struct {
Key string `json:"key"`
Value string `json:"value"`
Type string `json:"type"`
}
// SystemConfigListResponse 配置列表响应
type SystemConfigListResponse struct {
Configs []SystemConfigItem `json:"configs"`
}

View File

@@ -4,33 +4,16 @@ import (
"time" "time"
) )
// SystemConfig 系统配置实体 // SystemConfig 系统配置实体(键值对形式)
type SystemConfig struct { type SystemConfig struct {
ID uint `json:"id" gorm:"primaryKey"` ID uint `json:"id" gorm:"primaryKey"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
// SEO 配置 // 键值对配置
SiteTitle string `json:"site_title" gorm:"size:200;not null;default:'老九网盘资源数据库'"` Key string `json:"key" gorm:"size:100;not null;uniqueIndex"`
SiteDescription string `json:"site_description" gorm:"size:500"` Value string `json:"value" gorm:"size:1000"`
Keywords string `json:"keywords" gorm:"size:500"` Type string `json:"type" gorm:"size:20;default:'string'"` // string, int, bool, json
Author string `json:"author" gorm:"size:100"`
Copyright string `json:"copyright" gorm:"size:200"`
// 自动处理配置组
AutoProcessReadyResources bool `json:"auto_process_ready_resources" gorm:"default:false"` // 自动处理待处理资源
AutoProcessInterval int `json:"auto_process_interval" gorm:"default:30"` // 自动处理间隔(分钟)
AutoTransferEnabled bool `json:"auto_transfer_enabled" gorm:"default:false"` // 开启自动转存
AutoTransferLimitDays int `json:"auto_transfer_limit_days" gorm:"default:0"` // 自动转存限制天数0表示不限制
AutoTransferMinSpace int `json:"auto_transfer_min_space" gorm:"default:100"` // 最小存储空间GB
AutoFetchHotDramaEnabled bool `json:"auto_fetch_hot_drama_enabled" gorm:"default:false"` // 自动拉取热播剧名字
// API配置
ApiToken string `json:"api_token" gorm:"size:100;uniqueIndex"` // 公开API访问令牌
// 其他配置
PageSize int `json:"page_size" gorm:"default:100"`
MaintenanceMode bool `json:"maintenance_mode" gorm:"default:false"`
} }
// TableName 指定表名 // TableName 指定表名

View File

@@ -0,0 +1,89 @@
package entity
// ConfigKey 配置键常量
const (
// SEO 配置
ConfigKeySiteTitle = "site_title"
ConfigKeySiteDescription = "site_description"
ConfigKeyKeywords = "keywords"
ConfigKeyAuthor = "author"
ConfigKeyCopyright = "copyright"
// 自动处理配置组
ConfigKeyAutoProcessReadyResources = "auto_process_ready_resources"
ConfigKeyAutoProcessInterval = "auto_process_interval"
ConfigKeyAutoTransferEnabled = "auto_transfer_enabled"
ConfigKeyAutoTransferLimitDays = "auto_transfer_limit_days"
ConfigKeyAutoTransferMinSpace = "auto_transfer_min_space"
ConfigKeyAutoFetchHotDramaEnabled = "auto_fetch_hot_drama_enabled"
// API配置
ConfigKeyApiToken = "api_token"
// 其他配置
ConfigKeyPageSize = "page_size"
ConfigKeyMaintenanceMode = "maintenance_mode"
)
// ConfigType 配置类型常量
const (
ConfigTypeString = "string"
ConfigTypeInt = "int"
ConfigTypeBool = "bool"
ConfigTypeJSON = "json"
)
// ConfigResponseField API响应字段名常量
const (
// 基础字段
ConfigResponseFieldID = "id"
ConfigResponseFieldCreatedAt = "created_at"
ConfigResponseFieldUpdatedAt = "updated_at"
// SEO 配置字段
ConfigResponseFieldSiteTitle = "site_title"
ConfigResponseFieldSiteDescription = "site_description"
ConfigResponseFieldKeywords = "keywords"
ConfigResponseFieldAuthor = "author"
ConfigResponseFieldCopyright = "copyright"
// 自动处理配置字段
ConfigResponseFieldAutoProcessReadyResources = "auto_process_ready_resources"
ConfigResponseFieldAutoProcessInterval = "auto_process_interval"
ConfigResponseFieldAutoTransferEnabled = "auto_transfer_enabled"
ConfigResponseFieldAutoTransferLimitDays = "auto_transfer_limit_days"
ConfigResponseFieldAutoTransferMinSpace = "auto_transfer_min_space"
ConfigResponseFieldAutoFetchHotDramaEnabled = "auto_fetch_hot_drama_enabled"
// API配置字段
ConfigResponseFieldApiToken = "api_token"
// 其他配置字段
ConfigResponseFieldPageSize = "page_size"
ConfigResponseFieldMaintenanceMode = "maintenance_mode"
)
// ConfigDefaultValue 配置默认值常量
const (
// SEO 配置默认值
ConfigDefaultSiteTitle = "老九网盘资源数据库"
ConfigDefaultSiteDescription = "专业的老九网盘资源数据库"
ConfigDefaultKeywords = "网盘,资源管理,文件分享"
ConfigDefaultAuthor = "系统管理员"
ConfigDefaultCopyright = "© 2024 老九网盘资源数据库"
// 自动处理配置默认值
ConfigDefaultAutoProcessReadyResources = "false"
ConfigDefaultAutoProcessInterval = "30"
ConfigDefaultAutoTransferEnabled = "false"
ConfigDefaultAutoTransferLimitDays = "0"
ConfigDefaultAutoTransferMinSpace = "100"
ConfigDefaultAutoFetchHotDramaEnabled = "false"
// API配置默认值
ConfigDefaultApiToken = ""
// 其他配置默认值
ConfigDefaultPageSize = "100"
ConfigDefaultMaintenanceMode = "false"
)

View File

@@ -1,6 +1,8 @@
package repo package repo
import ( import (
"fmt"
"github.com/ctwj/urldb/db/entity" "github.com/ctwj/urldb/db/entity"
"gorm.io/gorm" "gorm.io/gorm"
@@ -9,9 +11,13 @@ import (
// SystemConfigRepository 系统配置Repository接口 // SystemConfigRepository 系统配置Repository接口
type SystemConfigRepository interface { type SystemConfigRepository interface {
BaseRepository[entity.SystemConfig] BaseRepository[entity.SystemConfig]
FindFirst() (*entity.SystemConfig, error) FindAll() ([]entity.SystemConfig, error)
GetOrCreateDefault() (*entity.SystemConfig, error) FindByKey(key string) (*entity.SystemConfig, error)
Upsert(config *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)
} }
// SystemConfigRepositoryImpl 系统配置Repository实现 // SystemConfigRepositoryImpl 系统配置Repository实现
@@ -26,55 +32,117 @@ func NewSystemConfigRepository(db *gorm.DB) SystemConfigRepository {
} }
} }
// FindFirst 获取第一个配置(通常只有一个配置 // FindAll 获取所有配置
func (r *SystemConfigRepositoryImpl) FindFirst() (*entity.SystemConfig, error) { 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) {
var config entity.SystemConfig var config entity.SystemConfig
err := r.db.First(&config).Error err := r.db.Where("key = ?", key).First(&config).Error
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &config, nil return &config, nil
} }
// Upsert 创建或更新系统配置 // UpsertConfigs 批量创建或更新配置
func (r *SystemConfigRepositoryImpl) Upsert(config *entity.SystemConfig) error { func (r *SystemConfigRepositoryImpl) UpsertConfigs(configs []entity.SystemConfig) error {
var existingConfig entity.SystemConfig for _, config := range configs {
err := r.db.First(&existingConfig).Error var existingConfig entity.SystemConfig
err := r.db.Where("key = ?", config.Key).First(&existingConfig).Error
if err != nil { if err != nil {
// 如果不存在,则创建 // 如果不存在,则创建
return r.db.Create(config).Error if err := r.db.Create(&config).Error; err != nil {
} else { return err
// 如果存在,则更新 }
config.ID = existingConfig.ID } else {
return r.db.Save(config).Error // 如果存在,则更新
config.ID = existingConfig.ID
if err := r.db.Save(&config).Error; err != nil {
return err
}
}
} }
return nil
} }
// GetOrCreateDefault 获取配置或创建默认配置 // GetOrCreateDefault 获取配置或创建默认配置
func (r *SystemConfigRepositoryImpl) GetOrCreateDefault() (*entity.SystemConfig, error) { func (r *SystemConfigRepositoryImpl) GetOrCreateDefault() ([]entity.SystemConfig, error) {
config, err := r.FindFirst() configs, err := r.FindAll()
if err != nil { if err != nil {
// 创建默认配置 return nil, err
defaultConfig := &entity.SystemConfig{ }
SiteTitle: "老九网盘资源数据库",
SiteDescription: "专业的老九网盘资源数据库", // 如果没有配置,创建默认配置
Keywords: "网盘,资源管理,文件分享", if len(configs) == 0 {
Author: "系统管理员", defaultConfigs := []entity.SystemConfig{
Copyright: "© 2024 老九网盘资源数据库", {Key: entity.ConfigKeySiteTitle, Value: entity.ConfigDefaultSiteTitle, Type: entity.ConfigTypeString},
AutoProcessReadyResources: false, {Key: entity.ConfigKeySiteDescription, Value: entity.ConfigDefaultSiteDescription, Type: entity.ConfigTypeString},
AutoProcessInterval: 30, {Key: entity.ConfigKeyKeywords, Value: entity.ConfigDefaultKeywords, Type: entity.ConfigTypeString},
PageSize: 100, {Key: entity.ConfigKeyAuthor, Value: entity.ConfigDefaultAuthor, Type: entity.ConfigTypeString},
MaintenanceMode: false, {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},
{Key: entity.ConfigKeyPageSize, Value: entity.ConfigDefaultPageSize, Type: entity.ConfigTypeInt},
{Key: entity.ConfigKeyMaintenanceMode, Value: entity.ConfigDefaultMaintenanceMode, Type: entity.ConfigTypeBool},
} }
err = r.db.Create(defaultConfig).Error err = r.UpsertConfigs(defaultConfigs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return defaultConfig, nil return defaultConfigs, nil
} }
return config, nil return configs, nil
}
// GetConfigValue 获取配置值(字符串)
func (r *SystemConfigRepositoryImpl) GetConfigValue(key string) (string, error) {
config, err := r.FindByKey(key)
if err != nil {
return "", err
}
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
}
// 这里需要导入 strconv 包,但为了避免循环导入,我们使用简单的转换
var result int
_, err = fmt.Sscanf(value, "%d", &result)
return result, err
} }

View File

@@ -5,6 +5,7 @@ import (
"github.com/ctwj/urldb/db/converter" "github.com/ctwj/urldb/db/converter"
"github.com/ctwj/urldb/db/dto" "github.com/ctwj/urldb/db/dto"
"github.com/ctwj/urldb/db/entity"
"github.com/ctwj/urldb/db/repo" "github.com/ctwj/urldb/db/repo"
"github.com/ctwj/urldb/utils" "github.com/ctwj/urldb/utils"
@@ -25,13 +26,13 @@ func NewSystemConfigHandler(systemConfigRepo repo.SystemConfigRepository) *Syste
// GetConfig 获取系统配置 // GetConfig 获取系统配置
func (h *SystemConfigHandler) GetConfig(c *gin.Context) { func (h *SystemConfigHandler) GetConfig(c *gin.Context) {
config, err := h.systemConfigRepo.GetOrCreateDefault() configs, err := h.systemConfigRepo.GetOrCreateDefault()
if err != nil { if err != nil {
ErrorResponse(c, "获取系统配置失败", http.StatusInternalServerError) ErrorResponse(c, "获取系统配置失败", http.StatusInternalServerError)
return return
} }
configResponse := converter.SystemConfigToResponse(config) configResponse := converter.SystemConfigToResponse(configs)
SuccessResponse(c, configResponse) SuccessResponse(c, configResponse)
} }
@@ -71,39 +72,39 @@ func (h *SystemConfigHandler) UpdateConfig(c *gin.Context) {
} }
// 转换为实体 // 转换为实体
config := converter.RequestToSystemConfig(&req) configs := converter.RequestToSystemConfig(&req)
if config == nil { if configs == nil {
ErrorResponse(c, "数据转换失败", http.StatusInternalServerError) ErrorResponse(c, "数据转换失败", http.StatusInternalServerError)
return return
} }
// 保存配置 // 保存配置
err := h.systemConfigRepo.Upsert(config) err := h.systemConfigRepo.UpsertConfigs(configs)
if err != nil { if err != nil {
ErrorResponse(c, "保存系统配置失败", http.StatusInternalServerError) ErrorResponse(c, "保存系统配置失败", http.StatusInternalServerError)
return return
} }
// 返回更新后的配置 // 返回更新后的配置
updatedConfig, err := h.systemConfigRepo.FindFirst() updatedConfigs, err := h.systemConfigRepo.FindAll()
if err != nil { if err != nil {
ErrorResponse(c, "获取更新后的配置失败", http.StatusInternalServerError) ErrorResponse(c, "获取更新后的配置失败", http.StatusInternalServerError)
return return
} }
configResponse := converter.SystemConfigToResponse(updatedConfig) configResponse := converter.SystemConfigToResponse(updatedConfigs)
SuccessResponse(c, configResponse) SuccessResponse(c, configResponse)
} }
// GetSystemConfig 获取系统配置使用全局repoManager // GetSystemConfig 获取系统配置使用全局repoManager
func GetSystemConfig(c *gin.Context) { func GetSystemConfig(c *gin.Context) {
config, err := repoManager.SystemConfigRepository.GetOrCreateDefault() configs, err := repoManager.SystemConfigRepository.GetOrCreateDefault()
if err != nil { if err != nil {
ErrorResponse(c, "获取系统配置失败", http.StatusInternalServerError) ErrorResponse(c, "获取系统配置失败", http.StatusInternalServerError)
return return
} }
configResponse := converter.SystemConfigToResponse(config) configResponse := converter.SystemConfigToResponse(configs)
SuccessResponse(c, configResponse) SuccessResponse(c, configResponse)
} }
@@ -143,14 +144,14 @@ func UpdateSystemConfig(c *gin.Context) {
} }
// 转换为实体 // 转换为实体
config := converter.RequestToSystemConfig(&req) configs := converter.RequestToSystemConfig(&req)
if config == nil { if configs == nil {
ErrorResponse(c, "数据转换失败", http.StatusInternalServerError) ErrorResponse(c, "数据转换失败", http.StatusInternalServerError)
return return
} }
// 保存配置 // 保存配置
err := repoManager.SystemConfigRepository.Upsert(config) err := repoManager.SystemConfigRepository.UpsertConfigs(configs)
if err != nil { if err != nil {
ErrorResponse(c, "保存系统配置失败", http.StatusInternalServerError) ErrorResponse(c, "保存系统配置失败", http.StatusInternalServerError)
return return
@@ -172,24 +173,24 @@ func UpdateSystemConfig(c *gin.Context) {
} }
// 返回更新后的配置 // 返回更新后的配置
updatedConfig, err := repoManager.SystemConfigRepository.FindFirst() updatedConfigs, err := repoManager.SystemConfigRepository.FindAll()
if err != nil { if err != nil {
ErrorResponse(c, "获取更新后的配置失败", http.StatusInternalServerError) ErrorResponse(c, "获取更新后的配置失败", http.StatusInternalServerError)
return return
} }
configResponse := converter.SystemConfigToResponse(updatedConfig) configResponse := converter.SystemConfigToResponse(updatedConfigs)
SuccessResponse(c, configResponse) SuccessResponse(c, configResponse)
} }
// 新增公开获取系统配置不含api_token // 新增公开获取系统配置不含api_token
func GetPublicSystemConfig(c *gin.Context) { func GetPublicSystemConfig(c *gin.Context) {
config, err := repoManager.SystemConfigRepository.GetOrCreateDefault() configs, err := repoManager.SystemConfigRepository.GetOrCreateDefault()
if err != nil { if err != nil {
ErrorResponse(c, "获取系统配置失败", http.StatusInternalServerError) ErrorResponse(c, "获取系统配置失败", http.StatusInternalServerError)
return return
} }
configResponse := converter.SystemConfigToPublicResponse(config) configResponse := converter.SystemConfigToPublicResponse(configs)
SuccessResponse(c, configResponse) SuccessResponse(c, configResponse)
} }
@@ -204,17 +205,25 @@ func ToggleAutoProcess(c *gin.Context) {
} }
// 获取当前配置 // 获取当前配置
config, err := repoManager.SystemConfigRepository.GetOrCreateDefault() configs, err := repoManager.SystemConfigRepository.GetOrCreateDefault()
if err != nil { if err != nil {
ErrorResponse(c, "获取系统配置失败", http.StatusInternalServerError) ErrorResponse(c, "获取系统配置失败", http.StatusInternalServerError)
return return
} }
// 更新自动处理配置 // 更新自动处理配置
config.AutoProcessReadyResources = req.AutoProcessReadyResources for i, config := range configs {
if config.Key == entity.ConfigKeyAutoProcessReadyResources {
configs[i].Value = "true"
if !req.AutoProcessReadyResources {
configs[i].Value = "false"
}
break
}
}
// 保存配置 // 保存配置
err = repoManager.SystemConfigRepository.Upsert(config) err = repoManager.SystemConfigRepository.UpsertConfigs(configs)
if err != nil { if err != nil {
ErrorResponse(c, "保存系统配置失败", http.StatusInternalServerError) ErrorResponse(c, "保存系统配置失败", http.StatusInternalServerError)
return return
@@ -232,14 +241,18 @@ func ToggleAutoProcess(c *gin.Context) {
repoManager.CategoryRepository, repoManager.CategoryRepository,
) )
if scheduler != nil { if scheduler != nil {
// 获取其他配置值
autoFetchHotDrama, _ := repoManager.SystemConfigRepository.GetConfigBool(entity.ConfigKeyAutoFetchHotDramaEnabled)
autoTransfer, _ := repoManager.SystemConfigRepository.GetConfigBool(entity.ConfigKeyAutoTransferEnabled)
scheduler.UpdateSchedulerStatusWithAutoTransfer( scheduler.UpdateSchedulerStatusWithAutoTransfer(
config.AutoFetchHotDramaEnabled, autoFetchHotDrama,
config.AutoProcessReadyResources, req.AutoProcessReadyResources,
config.AutoTransferEnabled, autoTransfer,
) )
} }
// 返回更新后的配置 // 返回更新后的配置
configResponse := converter.SystemConfigToResponse(config) configResponse := converter.SystemConfigToResponse(configs)
SuccessResponse(c, configResponse) SuccessResponse(c, configResponse)
} }

48
main.go
View File

@@ -7,6 +7,7 @@ import (
"github.com/ctwj/urldb/utils" "github.com/ctwj/urldb/utils"
"github.com/ctwj/urldb/db" "github.com/ctwj/urldb/db"
"github.com/ctwj/urldb/db/entity"
"github.com/ctwj/urldb/db/repo" "github.com/ctwj/urldb/db/repo"
"github.com/ctwj/urldb/handlers" "github.com/ctwj/urldb/handlers"
"github.com/ctwj/urldb/middleware" "github.com/ctwj/urldb/middleware"
@@ -81,33 +82,34 @@ func main() {
) )
// 检查系统配置,决定是否启动各种自动任务 // 检查系统配置,决定是否启动各种自动任务
systemConfig, err := repoManager.SystemConfigRepository.GetOrCreateDefault() autoProcessReadyResources, err := repoManager.SystemConfigRepository.GetConfigBool(entity.ConfigKeyAutoProcessReadyResources)
if err != nil { if err != nil {
utils.Error("获取系统配置失败: %v", err) utils.Error("获取自动处理待处理资源配置失败: %v", err)
} else if autoProcessReadyResources {
scheduler.StartReadyResourceScheduler()
utils.Info("已启动待处理资源自动处理任务")
} else { } else {
// 检查是否启动待处理资源自动处理任务 utils.Info("系统配置中自动处理待处理资源功能已禁用,跳过启动定时任务")
if systemConfig.AutoProcessReadyResources { }
scheduler.StartReadyResourceScheduler()
utils.Info("已启动待处理资源自动处理任务")
} else {
utils.Info("系统配置中自动处理待处理资源功能已禁用,跳过启动定时任务")
}
// 检查是否启动热播剧自动拉取任务 autoFetchHotDramaEnabled, err := repoManager.SystemConfigRepository.GetConfigBool(entity.ConfigKeyAutoFetchHotDramaEnabled)
if systemConfig.AutoFetchHotDramaEnabled { if err != nil {
scheduler.StartHotDramaScheduler() utils.Error("获取自动拉取热播剧配置失败: %v", err)
utils.Info("已启动热播剧自动拉取任务") } else if autoFetchHotDramaEnabled {
} else { scheduler.StartHotDramaScheduler()
utils.Info("系统配置中自动拉取热播剧功能已禁用,跳过启动定时任务") utils.Info("已启动热播剧自动拉取任务")
} } else {
utils.Info("系统配置中自动拉取热播剧功能已禁用,跳过启动定时任务")
}
// 检查是否启动自动转存任务 autoTransferEnabled, err := repoManager.SystemConfigRepository.GetConfigBool(entity.ConfigKeyAutoTransferEnabled)
if systemConfig.AutoTransferEnabled { if err != nil {
scheduler.StartAutoTransferScheduler() utils.Error("获取自动转存配置失败: %v", err)
utils.Info("已启动自动转存任务") } else if autoTransferEnabled {
} else { scheduler.StartAutoTransferScheduler()
utils.Info("系统配置中自动转存功能已禁用,跳过启动定时任务") utils.Info("已启动自动转存任务")
} } else {
utils.Info("系统配置中自动转存功能已禁用,跳过启动定时任务")
} }
// 创建Gin实例 // 创建Gin实例

View File

@@ -3,6 +3,7 @@ package middleware
import ( import (
"net/http" "net/http"
"github.com/ctwj/urldb/db/entity"
"github.com/ctwj/urldb/db/repo" "github.com/ctwj/urldb/db/repo"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@@ -45,7 +46,8 @@ func PublicAPIAuth() gin.HandlerFunc {
return return
} }
config, err := repoManager.SystemConfigRepository.FindFirst() // 验证API Token
apiTokenConfig, err := repoManager.SystemConfigRepository.GetConfigValue(entity.ConfigKeyApiToken)
if err != nil { if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{ c.JSON(http.StatusInternalServerError, gin.H{
"success": false, "success": false,
@@ -56,7 +58,7 @@ func PublicAPIAuth() gin.HandlerFunc {
return return
} }
if config.ApiToken == "" { if apiTokenConfig == "" {
c.JSON(http.StatusServiceUnavailable, gin.H{ c.JSON(http.StatusServiceUnavailable, gin.H{
"success": false, "success": false,
"message": "API Token未配置", "message": "API Token未配置",
@@ -66,7 +68,7 @@ func PublicAPIAuth() gin.HandlerFunc {
return return
} }
if config.ApiToken != apiToken { if apiTokenConfig != apiToken {
c.JSON(http.StatusUnauthorized, gin.H{ c.JSON(http.StatusUnauthorized, gin.H{
"success": false, "success": false,
"message": "API Token无效", "message": "API Token无效",
@@ -77,7 +79,18 @@ func PublicAPIAuth() gin.HandlerFunc {
} }
// 检查维护模式 // 检查维护模式
if config.MaintenanceMode { maintenanceMode, err := repoManager.SystemConfigRepository.GetConfigBool(entity.ConfigKeyMaintenanceMode)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "系统配置获取失败",
"code": 500,
})
c.Abort()
return
}
if maintenanceMode {
c.JSON(http.StatusServiceUnavailable, gin.H{ c.JSON(http.StatusServiceUnavailable, gin.H{
"success": false, "success": false,
"message": "系统维护中,请稍后再试", "message": "系统维护中,请稍后再试",

View File

@@ -290,10 +290,9 @@ func (s *Scheduler) StartReadyResourceScheduler() {
go func() { go func() {
// 获取系统配置中的间隔时间 // 获取系统配置中的间隔时间
config, err := s.systemConfigRepo.GetOrCreateDefault() interval := 3 * time.Minute // 默认3分钟
interval := 3 * time.Minute // 默认5分钟 if autoProcessInterval, err := s.systemConfigRepo.GetConfigInt(entity.ConfigKeyAutoProcessInterval); err == nil && autoProcessInterval > 0 {
if err == nil && config.AutoProcessInterval > 0 { interval = time.Duration(autoProcessInterval) * time.Minute
interval = time.Duration(config.AutoProcessInterval) * time.Minute
} }
ticker := time.NewTicker(interval) ticker := time.NewTicker(interval)
@@ -341,13 +340,13 @@ func (s *Scheduler) processReadyResources() {
Info("开始处理待处理资源...") Info("开始处理待处理资源...")
// 检查系统配置,确认是否启用自动处理 // 检查系统配置,确认是否启用自动处理
config, err := s.systemConfigRepo.GetOrCreateDefault() autoProcess, err := s.systemConfigRepo.GetConfigBool(entity.ConfigKeyAutoProcessReadyResources)
if err != nil { if err != nil {
Error("获取系统配置失败: %v", err) Error("获取系统配置失败: %v", err)
return return
} }
if !config.AutoProcessReadyResources { if !autoProcess {
Info("自动处理待处理资源功能已禁用") Info("自动处理待处理资源功能已禁用")
return return
} }
@@ -641,10 +640,9 @@ func (s *Scheduler) StartAutoTransferScheduler() {
go func() { go func() {
// 获取系统配置中的间隔时间 // 获取系统配置中的间隔时间
config, err := s.systemConfigRepo.GetOrCreateDefault()
interval := 5 * time.Minute // 默认5分钟 interval := 5 * time.Minute // 默认5分钟
if err == nil && config.AutoProcessInterval > 0 { if autoProcessInterval, err := s.systemConfigRepo.GetConfigInt(entity.ConfigKeyAutoProcessInterval); err == nil && autoProcessInterval > 0 {
interval = time.Duration(config.AutoProcessInterval) * time.Minute interval = time.Duration(autoProcessInterval) * time.Minute
} }
ticker := time.NewTicker(interval) ticker := time.NewTicker(interval)
@@ -697,13 +695,13 @@ func (s *Scheduler) processAutoTransfer() {
Info("开始处理自动转存...") Info("开始处理自动转存...")
// 检查系统配置,确认是否启用自动转存 // 检查系统配置,确认是否启用自动转存
config, err := s.systemConfigRepo.GetOrCreateDefault() autoTransferEnabled, err := s.systemConfigRepo.GetConfigBool(entity.ConfigKeyAutoTransferEnabled)
if err != nil { if err != nil {
Error("获取系统配置失败: %v", err) Error("获取系统配置失败: %v", err)
return return
} }
if !config.AutoTransferEnabled { if !autoTransferEnabled {
Info("自动转存功能已禁用") Info("自动转存功能已禁用")
return return
} }
@@ -729,8 +727,15 @@ func (s *Scheduler) processAutoTransfer() {
return return
} }
// 获取最小存储空间配置
autoTransferMinSpace, err := s.systemConfigRepo.GetConfigInt(entity.ConfigKeyAutoTransferMinSpace)
if err != nil {
Error("获取最小存储空间配置失败: %v", err)
return
}
// 过滤只保留已激活、quark平台、剩余空间足够的账号 // 过滤只保留已激活、quark平台、剩余空间足够的账号
minSpaceBytes := int64(config.AutoTransferMinSpace) * 1024 * 1024 * 1024 minSpaceBytes := int64(autoTransferMinSpace) * 1024 * 1024 * 1024
var validAccounts []entity.Cks var validAccounts []entity.Cks
for _, acc := range accounts { for _, acc := range accounts {
if acc.IsValid && acc.PanID == quarkPanID && acc.LeftSpace >= minSpaceBytes { if acc.IsValid && acc.PanID == quarkPanID && acc.LeftSpace >= minSpaceBytes {
@@ -746,7 +751,7 @@ func (s *Scheduler) processAutoTransfer() {
Info("找到 %d 个可用quark网盘账号开始自动转存处理...", len(validAccounts)) Info("找到 %d 个可用quark网盘账号开始自动转存处理...", len(validAccounts))
// 获取需要转存的资源 // 获取需要转存的资源
resources, err := s.getResourcesForTransfer(config, quarkPanID) resources, err := s.getResourcesForTransfer(quarkPanID)
if err != nil { if err != nil {
Error("获取需要转存的资源失败: %v", err) Error("获取需要转存的资源失败: %v", err)
return return
@@ -773,7 +778,7 @@ func (s *Scheduler) processAutoTransfer() {
defer wg.Done() defer wg.Done()
factory := panutils.GetInstance() // 使用单例模式 factory := panutils.GetInstance() // 使用单例模式
for res := range resourceCh { for res := range resourceCh {
if err := s.transferResource(res, []entity.Cks{acc}, config, factory); err != nil { if err := s.transferResource(res, []entity.Cks{acc}, factory); err != nil {
Error("转存资源失败 (ID: %d): %v", res.ID, err) Error("转存资源失败 (ID: %d): %v", res.ID, err)
} else { } else {
Info("成功转存资源: %s", res.Title) Info("成功转存资源: %s", res.Title)
@@ -789,8 +794,15 @@ func (s *Scheduler) processAutoTransfer() {
} }
// getResourcesForTransfer 获取需要转存的资源 // getResourcesForTransfer 获取需要转存的资源
func (s *Scheduler) getResourcesForTransfer(config *entity.SystemConfig, quarkPanID uint) ([]*entity.Resource, error) { func (s *Scheduler) getResourcesForTransfer(quarkPanID uint) ([]*entity.Resource, error) {
days := config.AutoTransferLimitDays // 获取自动转存限制天数配置
autoTransferLimitDays, err := s.systemConfigRepo.GetConfigInt(entity.ConfigKeyAutoTransferLimitDays)
if err != nil {
Error("获取自动转存限制天数配置失败: %v", err)
return nil, err
}
days := autoTransferLimitDays
var sinceTime time.Time var sinceTime time.Time
if days > 0 { if days > 0 {
sinceTime = GetCurrentTime().AddDate(0, 0, -days) sinceTime = GetCurrentTime().AddDate(0, 0, -days)
@@ -808,7 +820,7 @@ func (s *Scheduler) getResourcesForTransfer(config *entity.SystemConfig, quarkPa
var resourceUpdateMutex sync.Mutex // 全局互斥锁,保证多协程安全 var resourceUpdateMutex sync.Mutex // 全局互斥锁,保证多协程安全
// transferResource 转存单个资源 // transferResource 转存单个资源
func (s *Scheduler) transferResource(resource *entity.Resource, accounts []entity.Cks, config *entity.SystemConfig, factory *panutils.PanFactory) error { func (s *Scheduler) transferResource(resource *entity.Resource, accounts []entity.Cks, factory *panutils.PanFactory) error {
if len(accounts) == 0 { if len(accounts) == 0 {
return fmt.Errorf("没有可用的网盘账号") return fmt.Errorf("没有可用的网盘账号")
} }
@@ -824,7 +836,23 @@ func (s *Scheduler) transferResource(resource *entity.Resource, accounts []entit
return fmt.Errorf("创建网盘服务失败: %v", err) return fmt.Errorf("创建网盘服务失败: %v", err)
} }
// 获取最小存储空间配置
autoTransferMinSpace, err := s.systemConfigRepo.GetConfigInt(entity.ConfigKeyAutoTransferMinSpace)
if err != nil {
Error("获取最小存储空间配置失败: %v", err)
return err
}
// 检查账号剩余空间
minSpaceBytes := int64(autoTransferMinSpace) * 1024 * 1024 * 1024
if account.LeftSpace < minSpaceBytes {
return fmt.Errorf("账号剩余空间不足,需要 %d GB当前剩余 %d GB", autoTransferMinSpace, account.LeftSpace/1024/1024/1024)
}
// 提取分享ID
shareID, _ := commonutils.ExtractShareIdString(resource.URL) shareID, _ := commonutils.ExtractShareIdString(resource.URL)
// 转存资源
result, err := service.Transfer(shareID) result, err := service.Transfer(shareID)
if err != nil { if err != nil {
resourceUpdateMutex.Lock() resourceUpdateMutex.Lock()
@@ -880,35 +908,34 @@ func (s *Scheduler) transferResource(resource *entity.Resource, accounts []entit
return nil return nil
} }
// selectBestAccount 选择最佳网盘账号 // selectBestAccount 选择最佳账号
func (s *Scheduler) selectBestAccount(accounts []entity.Cks, config *entity.SystemConfig) *entity.Cks { func (s *Scheduler) selectBestAccount(accounts []entity.Cks) *entity.Cks {
// TODO: 实现账号选择逻辑 if len(accounts) == 0 {
// 1. 过滤出有效的账号 return nil
// 2. 检查剩余空间是否满足最小要求 }
// 3. 优先选择VIP账号
// 4. 优先选择剩余空间大的账号
// 5. 考虑账号的使用频率(避免单个账号过度使用)
minSpaceBytes := int64(config.AutoTransferMinSpace) * 1024 * 1024 * 1024 // 转换为字节 // 获取最小存储空间配置
autoTransferMinSpace, err := s.systemConfigRepo.GetConfigInt(entity.ConfigKeyAutoTransferMinSpace)
if err != nil {
Error("获取最小存储空间配置失败: %v", err)
return &accounts[0] // 返回第一个账号
}
minSpaceBytes := int64(autoTransferMinSpace) * 1024 * 1024 * 1024
var bestAccount *entity.Cks var bestAccount *entity.Cks
var maxScore int64 = -1 var bestScore int64 = -1
for _, account := range accounts { for i := range accounts {
if !account.IsValid { account := &accounts[i]
continue
}
// 检查剩余空间
if account.LeftSpace < minSpaceBytes { if account.LeftSpace < minSpaceBytes {
continue continue // 跳过空间不足的账号
} }
// 计算账号评分 score := s.calculateAccountScore(account)
score := s.calculateAccountScore(&account) if score > bestScore {
if score > maxScore { bestScore = score
maxScore = score bestAccount = account
bestAccount = &account
} }
} }