package config import ( "os" "path/filepath" "sync" "gopkg.in/yaml.v3" ) type Config struct { Site SiteConfig `yaml:"site" json:"site"` // 站点设置 Security SecurityConfig `yaml:"security" json:"security"` // 安全设置 Upload UploadConfig `yaml:"upload" json:"upload"` // 上传设置 Storage StorageConfig `yaml:"storage" json:"storage"` // 存储设置 APIToken APITokenConfig `yaml:"api_token" json:"api_token"` // API Token 设置 Database DatabaseConfig `yaml:"database" json:"database"` // 数据库设置 Web WebConfig `yaml:"web" json:"web"` // Web 前端设置 } type WebConfig struct { Path string `yaml:"path" json:"path"` // Web 前端资源路径 } type SiteConfig struct { Name string `yaml:"name" json:"name"` // 站点名称 Description string `yaml:"description" json:"description"` // 站点描述 Logo string `yaml:"logo" json:"logo"` // 站点 Logo URL } type SecurityConfig struct { AdminPasswordHash string `yaml:"admin_password_hash" json:"admin_password_hash"` // 管理员密码哈希 (bcrypt) AdminPassword string `yaml:"-" json:"admin_password,omitempty"` // 管理员密码明文 (仅用于更新请求,不保存到文件) PickupCodeLength int `yaml:"pickup_code_length" json:"pickup_code_length"` // 取件码长度 (变更后将自动通过右侧补零或截取调整存量数据) PickupFailLimit int `yaml:"pickup_fail_limit" json:"pickup_fail_limit"` // 取件失败尝试限制 JWTSecret string `yaml:"jwt_secret" json:"jwt_secret"` // JWT 签名密钥 } type UploadConfig struct { MaxFileSizeMB int64 `yaml:"max_file_size_mb" json:"max_file_size_mb"` // 单个文件最大大小 (MB) MaxBatchFiles int `yaml:"max_batch_files" json:"max_batch_files"` // 每个批次最大文件数 MaxRetentionDays int `yaml:"max_retention_days" json:"max_retention_days"` // 最大保留天数 RequireToken bool `yaml:"require_token" json:"require_token"` // 是否强制要求上传 Token } type StorageConfig struct { Type string `yaml:"type" json:"type"` // 存储类型: local, webdav, s3 Local struct { Path string `yaml:"path" json:"path"` // 本地存储路径 } `yaml:"local" json:"local"` WebDAV struct { URL string `yaml:"url" json:"url"` // WebDAV 地址 Username string `yaml:"username" json:"username"` // WebDAV 用户名 Password string `yaml:"password" json:"password"` // WebDAV 密码 Root string `yaml:"root" json:"root"` // WebDAV 根目录 } `yaml:"webdav" json:"webdav"` S3 struct { Endpoint string `yaml:"endpoint" json:"endpoint"` // S3 端点 Region string `yaml:"region" json:"region"` // S3 区域 AccessKey string `yaml:"access_key" json:"access_key"` // S3 Access Key SecretKey string `yaml:"secret_key" json:"secret_key"` // S3 Secret Key Bucket string `yaml:"bucket" json:"bucket"` // S3 Bucket UseSSL bool `yaml:"use_ssl" json:"use_ssl"` // 是否使用 SSL } `yaml:"s3" json:"s3"` } type APITokenConfig struct { Enabled bool `yaml:"enabled" json:"enabled"` // 是否启用 API Token AllowAdminAPI bool `yaml:"allow_admin_api" json:"allow_admin_api"` // 是否允许 API Token 访问管理接口 MaxTokens int `yaml:"max_tokens" json:"max_tokens"` // 最大 Token 数量 } type DatabaseConfig struct { Path string `yaml:"path" json:"path"` // 数据库文件路径 } var ( GlobalConfig *Config ConfigPath string configLock sync.RWMutex ) func LoadConfig(path string) error { configLock.Lock() defer configLock.Unlock() // 检查文件是否存在 if _, err := os.Stat(path); os.IsNotExist(err) { // 创建默认配置 cfg := GetDefaultConfig() data, err := yaml.Marshal(cfg) if err != nil { return err } // 确保目录存在 if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { return err } if err := os.WriteFile(path, data, 0644); err != nil { return err } GlobalConfig = cfg ConfigPath = path return nil } data, err := os.ReadFile(path) if err != nil { return err } var cfg Config if err := yaml.Unmarshal(data, &cfg); err != nil { return err } GlobalConfig = &cfg ConfigPath = path return nil } func GetDefaultConfig() *Config { return &Config{ Site: SiteConfig{ Name: "文件暂存柜", Description: "临时文件中转服务", Logo: "https://www.hxuanyu.com/upload/favicon.png", }, Security: SecurityConfig{ AdminPasswordHash: "$2a$10$Bm0TEmU4uj.bVHYiIPFBheUkcdg6XHpsanLvmpoAtgU1UnKbo9.vy", // 默认密码: admin123 PickupCodeLength: 6, PickupFailLimit: 5, JWTSecret: "file-relay-secret", }, Upload: UploadConfig{ MaxFileSizeMB: 100, MaxBatchFiles: 20, MaxRetentionDays: 30, RequireToken: false, }, Storage: StorageConfig{ Type: "local", Local: struct { Path string `yaml:"path" json:"path"` }{ Path: "storage_data", }, }, APIToken: APITokenConfig{ Enabled: true, AllowAdminAPI: true, MaxTokens: 20, }, Database: DatabaseConfig{ Path: "file_relay.db", }, Web: WebConfig{ Path: "web", }, } } func SaveConfig() error { configLock.RLock() defer configLock.RUnlock() data, err := yaml.Marshal(GlobalConfig) if err != nil { return err } return os.WriteFile(ConfigPath, data, 0644) } func UpdateGlobalConfig(cfg *Config) { configLock.Lock() defer configLock.Unlock() GlobalConfig = cfg }