Files
v-hono/config.v
T

312 lines
8.3 KiB
V

module hono
import os
import json
// 服务器配置结构
pub struct ServerConfig {
pub mut:
host string = '127.0.0.1'
port int = 8080
read_timeout int = 30 // 秒
write_timeout int = 30 // 秒
max_request_size u64 = 10 * 1024 * 1024 // 10MB
enable_cors bool = true
enable_gzip bool = true
}
// 静态文件配置
pub struct StaticConfig {
pub mut:
enabled bool = true
root_dir string = './static'
index_files []string = ['index.html', 'index.htm']
cache_max_age int = 3600 // 秒
enable_directory_listing bool
allowed_extensions []string = ['.html', '.css', '.js', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.ico', '.txt', '.pdf']
}
// 上传配置
pub struct UploadConfig {
pub mut:
enabled bool = true
upload_dir string = './uploads'
max_file_size u64 = 100 * 1024 * 1024 // 100MB
max_chunk_size u64 = 5 * 1024 * 1024 // 5MB
merge_buffer_size int = 8192 // 8KB
allowed_types []string = ['.txt', '.pdf', '.doc', '.docx', '.jpg', '.jpeg', '.png', '.gif']
cleanup_timeout int = 3600 // 秒,清理未完成上传的超时时间
}
// 缓存配置
pub struct CacheConfig {
pub mut:
enabled bool = true
max_size int = 1000
default_ttl int = 300 // 秒
cleanup_interval int = 60 // 秒
}
// 安全配置
pub struct SecurityConfig {
pub mut:
enable_path_validation bool = true
enable_file_type_check bool = true
enable_size_limits bool = true
max_path_length int = 255
blocked_extensions []string = ['.exe', '.bat', '.cmd', '.sh', '.php', '.asp', '.jsp']
enable_xss_protection bool = true
enable_csrf_protection bool
}
// 日志配置
pub struct LogConfig {
pub mut:
enabled bool = true
level string = 'info' // debug, info, warn, error
output string = 'console' // console, file, both
file_path string = './logs/app.log'
max_file_size u64 = 10 * 1024 * 1024 // 10MB
max_backup_files int = 5
enable_request_log bool = true
}
// 应用配置主结构
pub struct AppConfig {
pub mut:
server ServerConfig
static StaticConfig
upload UploadConfig
cache CacheConfig
security SecurityConfig
log LogConfig
debug bool
env string = 'development' // development, production, test
}
// 默认配置
pub fn default_config() AppConfig {
return AppConfig{
server: ServerConfig{}
static: StaticConfig{}
upload: UploadConfig{}
cache: CacheConfig{}
security: SecurityConfig{}
log: LogConfig{}
}
}
// 从文件加载配置
pub fn load_config(config_path string) !AppConfig {
if !os.exists(config_path) {
println('配置文件不存在: ${config_path},使用默认配置')
return default_config()
}
config_content := os.read_file(config_path) or {
return error('无法读取配置文件: ${err}')
}
config := json.decode(AppConfig, config_content) or {
return error('配置文件格式错误: ${err}')
}
// 验证配置
validate_config(config) or {
return error('配置验证失败: ${err}')
}
println('成功加载配置文件: ${config_path}')
return config
}
// 保存配置到文件
pub fn save_config(config AppConfig, config_path string) ! {
config_json := json.encode_pretty(config)
// 确保目录存在
config_dir := os.dir(config_path)
if !os.exists(config_dir) {
os.mkdir_all(config_dir) or {
return error('无法创建配置目录: ${err}')
}
}
os.write_file(config_path, config_json) or {
return error('无法保存配置文件: ${err}')
}
println('配置已保存到: ${config_path}')
}
// 从环境变量加载配置
pub fn load_config_from_env() AppConfig {
mut config := default_config()
// 服务器配置
host := os.getenv('HONO_HOST')
if host != '' {
config.server.host = host
}
port_str := os.getenv('HONO_PORT')
if port_str != '' {
config.server.port = port_str.int()
}
env := os.getenv('HONO_ENV')
if env != '' {
config.env = env
}
debug_str := os.getenv('HONO_DEBUG')
if debug_str != '' {
config.debug = debug_str.to_lower() in ['true', '1', 'yes']
}
// 上传配置
upload_dir := os.getenv('HONO_UPLOAD_DIR')
if upload_dir != '' {
config.upload.upload_dir = upload_dir
}
static_dir := os.getenv('HONO_STATIC_DIR')
if static_dir != '' {
config.static.root_dir = static_dir
}
// 日志配置
log_level := os.getenv('HONO_LOG_LEVEL')
if log_level != '' {
config.log.level = log_level
}
log_file := os.getenv('HONO_LOG_FILE')
if log_file != '' {
config.log.file_path = log_file
}
return config
}
// 验证配置
pub fn validate_config(config AppConfig) ! {
// 验证端口范围
if config.server.port < 1 || config.server.port > 65535 {
return error('端口号必须在 1-65535 范围内')
}
// 验证超时设置
if config.server.read_timeout < 1 || config.server.write_timeout < 1 {
return error('超时时间必须大于0')
}
// 验证文件大小限制
if config.server.max_request_size < 1024 {
return error('最大请求大小不能小于1KB')
}
if config.upload.max_file_size < 1024 {
return error('最大文件大小不能小于1KB')
}
if config.upload.max_chunk_size < 1024 {
return error('最大分片大小不能小于1KB')
}
// 验证缓存配置
if config.cache.max_size < 1 {
return error('缓存最大大小必须大于0')
}
// 验证日志级别
if config.log.level !in ['debug', 'info', 'warn', 'error'] {
return error('日志级别必须是: debug, info, warn, error 之一')
}
// 验证环境
if config.env !in ['development', 'production', 'test'] {
return error('环境必须是: development, production, test 之一')
}
// 验证目录路径
if config.static.enabled && config.static.root_dir == '' {
return error('静态文件目录不能为空')
}
if config.upload.enabled && config.upload.upload_dir == '' {
return error('上传目录不能为空')
}
}
// 创建示例配置文件
pub fn create_example_config(config_path string) ! {
config := default_config()
save_config(config, config_path) or {
return error('无法创建示例配置文件: ${err}')
}
println('示例配置文件已创建: ${config_path}')
}
// 获取配置摘要信息
pub fn get_config_summary(config AppConfig) string {
mut summary := []string{}
summary << '=== 应用配置摘要 ==='
summary << '环境: ${config.env}'
summary << '调试模式: ${config.debug}'
summary << ''
summary << '服务器:'
summary << ' 地址: ${config.server.host}:${config.server.port}'
summary << ' 最大请求大小: ${config.server.max_request_size / 1024 / 1024}MB'
summary << ' CORS: ${config.server.enable_cors}'
summary << ' GZIP: ${config.server.enable_gzip}'
summary << ''
summary << '静态文件:'
summary << ' 启用: ${config.static.enabled}'
summary << ' 目录: ${config.static.root_dir}'
summary << ' 缓存时间: ${config.static.cache_max_age}秒'
summary << ''
summary << '文件上传:'
summary << ' 启用: ${config.upload.enabled}'
summary << ' 目录: ${config.upload.upload_dir}'
summary << ' 最大文件大小: ${config.upload.max_file_size / 1024 / 1024}MB'
summary << ' 最大分片大小: ${config.upload.max_chunk_size / 1024 / 1024}MB'
summary << ''
summary << '缓存:'
summary << ' 启用: ${config.cache.enabled}'
summary << ' 最大条目: ${config.cache.max_size}'
summary << ' 默认TTL: ${config.cache.default_ttl}秒'
summary << ''
summary << '安全:'
summary << ' 路径验证: ${config.security.enable_path_validation}'
summary << ' 文件类型检查: ${config.security.enable_file_type_check}'
summary << ' XSS保护: ${config.security.enable_xss_protection}'
summary << ''
summary << '日志:'
summary << ' 启用: ${config.log.enabled}'
summary << ' 级别: ${config.log.level}'
summary << ' 输出: ${config.log.output}'
summary << ' 请求日志: ${config.log.enable_request_log}'
return summary.join('\n')
}
// 合并配置(用于配置覆盖)
pub fn merge_config(base AppConfig, override AppConfig) AppConfig {
mut merged := base
// 这里可以实现更复杂的合并逻辑
// 目前简单地用override覆盖base的非零值
if override.server.host != '' {
merged.server.host = override.server.host
}
if override.server.port != 0 {
merged.server.port = override.server.port
}
if override.env != '' {
merged.env = override.env
}
return merged
}