Files
FileRelay/internal/config/config.go

180 lines
5.5 KiB
Go

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
}