package config import ( "fmt" "os" "path/filepath" "github.com/pelletier/go-toml/v2" "go.uber.org/zap/zapcore" ) // AppConfig 应用配置结构 type AppConfig struct { Server ServerConfig `toml:"server"` Log LogConfig `toml:"log"` Audit AuditConfig `toml:"audit"` Storage StorageConfig `toml:"storage"` } // ServerConfig 服务器配置 type ServerConfig struct { Ip string `toml:"ip"` Port int `toml:"port"` } // LogConfig 日志配置 type LogConfig struct { Level string `toml:"level"` // 日志级别: debug, info, warn, error, fatal Development bool `toml:"development"` // 开发模式 Encoding string `toml:"encoding"` // 编码格式: json, console OutputPaths []string `toml:"output_paths"` // 输出路径 LogDir string `toml:"log_dir"` // 日志目录 } // AuditConfig 审计配置 type AuditConfig struct { Enabled bool `toml:"enabled"` // 是否启用审计 DatabasePath string `toml:"database_path"` // 数据库路径 RetentionDays int `toml:"retention_days"` // 保留天数 BufferSize int `toml:"buffer_size"` // 缓冲区大小 } // StorageConfig 存储配置 type StorageConfig struct { // 存储类型: "file" 或 "db" Type string `toml:"type"` // 文件存储配置 ConfigPath string `toml:"config_path"` // 配置文件路径 (用于文件存储) SQLBaseDir string `toml:"sql_base_dir"` // 脚本(Script)基础目录 (用于文件存储) // 数据库存储配置 DatabasePath string `toml:"database_path"` // 数据库文件路径 (用于数据库存储) // 通用配置 DataFile string `toml:"data_file"` // 数据文件路径 (向后兼容) } // LoadConfig 加载配置文件 func LoadConfig(path string) (*AppConfig, error) { // 检查文件是否存在 if _, err := os.Stat(path); os.IsNotExist(err) { // 如果配置文件不存在,创建默认配置 if err := CreateDefaultConfig(path); err != nil { return nil, fmt.Errorf("创建默认配置文件失败: %w", err) } } // 使用 os.ReadFile (Go 1.16+) data, err := os.ReadFile(path) if err != nil { return nil, err } var cfg AppConfig if err := toml.Unmarshal(data, &cfg); err != nil { return nil, err } return &cfg, nil } // CreateDefaultConfig 创建默认配置文件 func CreateDefaultConfig(configPath string) error { // 创建默认配置 defaultConfig := &AppConfig{ Server: ServerConfig{ Ip: "127.0.0.1", Port: 8080, }, Log: LogConfig{ Level: "info", Development: false, Encoding: "json", OutputPaths: []string{"stdout", "app.log"}, LogDir: "./DBconfig/logs", }, Audit: AuditConfig{ Enabled: true, DatabasePath: "./DBconfig/audit.db", RetentionDays: 90, BufferSize: 1000, }, Storage: StorageConfig{ Type: "db", ConfigPath: "./DBconfig/data.toml", SQLBaseDir: "./DBconfig/sqlfiles", DatabasePath: "./DBconfig/storage.db", DataFile: "./DBconfig/data.toml", }, } // 确保配置目录存在 configDir := filepath.Dir(configPath) if err := os.MkdirAll(configDir, 0755); err != nil { return fmt.Errorf("创建配置目录失败: %w", err) } // 创建必要的目录 if err := defaultConfig.CreateDirectories(); err != nil { return fmt.Errorf("创建必要目录失败: %w", err) } // 将配置序列化为TOML格式 data, err := toml.Marshal(defaultConfig) if err != nil { return fmt.Errorf("序列化配置失败: %w", err) } // 写入配置文件 if err := os.WriteFile(configPath, data, 0644); err != nil { return fmt.Errorf("写入配置文件失败: %w", err) } return nil } // LoadConfigFromFile 从文件句柄加载配置 func LoadConfigFromFile(file *os.File) (*AppConfig, error) { var cfg AppConfig if err := toml.NewDecoder(file).Decode(&cfg); err != nil { return nil, err } return &cfg, nil } // SetDefaults 设置默认值 func (cfg *AppConfig) SetDefaults() { // 服务器默认值 if cfg.Server.Port == 0 { cfg.Server.Port = 8080 } // 日志默认值 if cfg.Log.Level == "" { cfg.Log.Level = "info" } if cfg.Log.Encoding == "" { cfg.Log.Encoding = "json" } if len(cfg.Log.OutputPaths) == 0 { cfg.Log.OutputPaths = []string{"stdout"} } if cfg.Log.LogDir == "" { cfg.Log.LogDir = "./DBconfig/logs" } // 审计默认值 if cfg.Audit.DatabasePath == "" { cfg.Audit.DatabasePath = "./DBconfig/audit.db" } if cfg.Audit.RetentionDays == 0 { cfg.Audit.RetentionDays = 90 } if cfg.Audit.BufferSize == 0 { cfg.Audit.BufferSize = 1000 } // 注意:Audit.Enabled 默认为 false,需要明确启用 // 存储默认值 if cfg.Storage.Type == "" { cfg.Storage.Type = "db" // 默认使用数据库存储 } if cfg.Storage.ConfigPath == "" { cfg.Storage.ConfigPath = "./DBconfig/data.toml" } if cfg.Storage.SQLBaseDir == "" { cfg.Storage.SQLBaseDir = "./DBconfig/sqlfiles" } if cfg.Storage.DatabasePath == "" { cfg.Storage.DatabasePath = "./DBconfig/storage.db" } if cfg.Storage.DataFile == "" { cfg.Storage.DataFile = "./DBconfig/data.toml" // 向后兼容 } } // GetLogLevel 将字符串日志级别转换为 zapcore.Level func (lc *LogConfig) GetLogLevel() zapcore.Level { switch lc.Level { case "debug": return zapcore.DebugLevel case "info": return zapcore.InfoLevel case "warn", "warning": return zapcore.WarnLevel case "error": return zapcore.ErrorLevel case "fatal": return zapcore.FatalLevel default: return zapcore.InfoLevel } } // GetOutputPaths 获取完整的输出路径列表 func (lc *LogConfig) GetOutputPaths() []string { paths := make([]string, 0, len(lc.OutputPaths)) for _, path := range lc.OutputPaths { if path == "stdout" { paths = append(paths, "stdout") } else if path == "stderr" { paths = append(paths, "stderr") } else { // 如果是相对路径,转换为绝对路径 if !filepath.IsAbs(path) { absPath := filepath.Join(lc.LogDir, path) paths = append(paths, absPath) } else { paths = append(paths, path) } } } return paths } // Validate 验证配置的有效性 func (cfg *AppConfig) Validate() error { // 验证服务器配置 if cfg.Server.Port <= 0 || cfg.Server.Port > 65535 { return fmt.Errorf("invalid server port: %d", cfg.Server.Port) } // 验证日志配置 validLevels := map[string]bool{ "debug": true, "info": true, "warn": true, "warning": true, "error": true, "fatal": true, } if !validLevels[cfg.Log.Level] { return fmt.Errorf("invalid log level: %s", cfg.Log.Level) } validEncodings := map[string]bool{ "json": true, "console": true, } if !validEncodings[cfg.Log.Encoding] { return fmt.Errorf("invalid log encoding: %s", cfg.Log.Encoding) } // 验证审计配置 if cfg.Audit.RetentionDays < 0 { return fmt.Errorf("invalid audit retention days: %d", cfg.Audit.RetentionDays) } if cfg.Audit.BufferSize < 0 { return fmt.Errorf("invalid audit buffer size: %d", cfg.Audit.BufferSize) } // 验证存储配置 validStorageTypes := map[string]bool{ "file": true, "db": true, } if !validStorageTypes[cfg.Storage.Type] { return fmt.Errorf("invalid storage type: %s", cfg.Storage.Type) } return nil } // CreateDirectories 创建必要的目录 func (cfg *AppConfig) CreateDirectories() error { dirs := []string{ cfg.Log.LogDir, filepath.Dir(cfg.Audit.DatabasePath), cfg.Storage.SQLBaseDir, filepath.Dir(cfg.Storage.DataFile), } // 根据存储类型添加额外的目录 if cfg.Storage.Type == "db" { dirs = append(dirs, filepath.Dir(cfg.Storage.DatabasePath)) } for _, dir := range dirs { if dir == "" { continue } if err := os.MkdirAll(dir, 0755); err != nil { return fmt.Errorf("failed to create directory %s: %w", dir, err) } } return nil } // GetStorageManager 根据配置创建存储管理器 func (sc *StorageConfig) GetStorageManager() (interface{}, error) { switch sc.Type { case "file": // 这里需要导入storage包,但为了避免循环依赖,我们返回配置信息 return map[string]string{ "type": "file", "config_path": sc.ConfigPath, "sql_base_dir": sc.SQLBaseDir, }, nil case "db": return map[string]string{ "type": "db", "database_path": sc.DatabasePath, }, nil default: return nil, fmt.Errorf("unsupported storage type: %s", sc.Type) } } // IsFileStorage 是否使用文件存储 func (sc *StorageConfig) IsFileStorage() bool { return sc.Type == "file" } // IsDBStorage 是否使用数据库存储 func (sc *StorageConfig) IsDBStorage() bool { return sc.Type == "db" }