// Package config 负责加载服务端启动配置。 package config import ( "fmt" "log/slog" "os" "strings" "gopkg.in/yaml.v3" ) // Config 是 config.yaml 的映射。 type Config struct { Server Server `yaml:"server"` DataDir string `yaml:"dataDir"` Backup Backup `yaml:"backup"` Log Log `yaml:"log"` } // Backup 是自动备份配置。 type Backup struct { // IntervalMinutes 是自动备份间隔(分钟);<=0 表示关闭自动备份。 IntervalMinutes int `yaml:"intervalMinutes"` // Keep 是每个库滚动保留的份数;<=0 时用 export.DefaultBackupKeep。 Keep int `yaml:"keep"` } // Server 是 HTTP 监听配置。 type Server struct { Host string `yaml:"host"` Port int `yaml:"port"` // AllowedOrigins 是 WebSocket 跨站 Origin 白名单;为空时只放行同源与不带 Origin 的客户端。 AllowedOrigins []string `yaml:"allowedOrigins"` } // Log 是日志配置。 type Log struct { Level string `yaml:"level"` } // Default 返回一份可直接使用的默认配置。 func Default() *Config { return &Config{ Server: Server{Host: "0.0.0.0", Port: 19540}, DataDir: "data", Backup: Backup{IntervalMinutes: 5, Keep: 20}, Log: Log{Level: "info"}, } } // Load 读取配置文件;文件不存在时返回默认配置。 func Load(path string) (*Config, error) { cfg := Default() raw, err := os.ReadFile(path) switch { case err == nil: if err := yaml.Unmarshal(raw, cfg); err != nil { return nil, fmt.Errorf("解析配置文件 %s: %w", path, err) } case os.IsNotExist(err): // 没有配置文件时使用默认值 default: return nil, fmt.Errorf("读取配置文件 %s: %w", path, err) } if err := cfg.validate(); err != nil { return nil, err } return cfg, nil } func (c *Config) validate() error { if c.Server.Port <= 0 || c.Server.Port > 65535 { return fmt.Errorf("server.port 非法: %d", c.Server.Port) } if strings.TrimSpace(c.DataDir) == "" { return fmt.Errorf("dataDir 不能为空") } return nil } // Addr 返回 http.Server 使用的监听地址。 func (s Server) Addr() string { return fmt.Sprintf("%s:%d", s.Host, s.Port) } // SlogLevel 把配置里的日志级别映射为 slog 级别。 func (l Log) SlogLevel() slog.Level { switch strings.ToLower(strings.TrimSpace(l.Level)) { case "debug": return slog.LevelDebug case "warn", "warning": return slog.LevelWarn case "error": return slog.LevelError default: return slog.LevelInfo } }