config.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. package config
  2. import (
  3. "fmt"
  4. "os"
  5. "path/filepath"
  6. "github.com/pelletier/go-toml/v2"
  7. "go.uber.org/zap/zapcore"
  8. )
  9. // AppConfig 应用配置结构
  10. type AppConfig struct {
  11. Server ServerConfig `toml:"server"`
  12. Log LogConfig `toml:"log"`
  13. Audit AuditConfig `toml:"audit"`
  14. Storage StorageConfig `toml:"storage"`
  15. }
  16. // ServerConfig 服务器配置
  17. type ServerConfig struct {
  18. Ip string `toml:"ip"`
  19. Port int `toml:"port"`
  20. }
  21. // LogConfig 日志配置
  22. type LogConfig struct {
  23. Level string `toml:"level"` // 日志级别: debug, info, warn, error, fatal
  24. Development bool `toml:"development"` // 开发模式
  25. Encoding string `toml:"encoding"` // 编码格式: json, console
  26. OutputPaths []string `toml:"output_paths"` // 输出路径
  27. LogDir string `toml:"log_dir"` // 日志目录
  28. }
  29. // AuditConfig 审计配置
  30. type AuditConfig struct {
  31. Enabled bool `toml:"enabled"` // 是否启用审计
  32. DatabasePath string `toml:"database_path"` // 数据库路径
  33. RetentionDays int `toml:"retention_days"` // 保留天数
  34. BufferSize int `toml:"buffer_size"` // 缓冲区大小
  35. }
  36. // StorageConfig 存储配置
  37. type StorageConfig struct {
  38. // 存储类型: "file" 或 "db"
  39. Type string `toml:"type"`
  40. // 文件存储配置
  41. ConfigPath string `toml:"config_path"` // 配置文件路径 (用于文件存储)
  42. SQLBaseDir string `toml:"sql_base_dir"` // 脚本(Script)基础目录 (用于文件存储)
  43. // 数据库存储配置
  44. DatabasePath string `toml:"database_path"` // 数据库文件路径 (用于数据库存储)
  45. // 通用配置
  46. DataFile string `toml:"data_file"` // 数据文件路径 (向后兼容)
  47. }
  48. // LoadConfig 加载配置文件
  49. func LoadConfig(path string) (*AppConfig, error) {
  50. // 检查文件是否存在
  51. if _, err := os.Stat(path); os.IsNotExist(err) {
  52. // 如果配置文件不存在,创建默认配置
  53. if err := CreateDefaultConfig(path); err != nil {
  54. return nil, fmt.Errorf("创建默认配置文件失败: %w", err)
  55. }
  56. }
  57. // 使用 os.ReadFile (Go 1.16+)
  58. data, err := os.ReadFile(path)
  59. if err != nil {
  60. return nil, err
  61. }
  62. var cfg AppConfig
  63. if err := toml.Unmarshal(data, &cfg); err != nil {
  64. return nil, err
  65. }
  66. return &cfg, nil
  67. }
  68. // CreateDefaultConfig 创建默认配置文件
  69. func CreateDefaultConfig(configPath string) error {
  70. // 创建默认配置
  71. defaultConfig := &AppConfig{
  72. Server: ServerConfig{
  73. Ip: "127.0.0.1",
  74. Port: 8080,
  75. },
  76. Log: LogConfig{
  77. Level: "info",
  78. Development: false,
  79. Encoding: "json",
  80. OutputPaths: []string{"stdout", "app.log"},
  81. LogDir: "./DBconfig/logs",
  82. },
  83. Audit: AuditConfig{
  84. Enabled: true,
  85. DatabasePath: "./DBconfig/audit.db",
  86. RetentionDays: 90,
  87. BufferSize: 1000,
  88. },
  89. Storage: StorageConfig{
  90. Type: "db",
  91. ConfigPath: "./DBconfig/data.toml",
  92. SQLBaseDir: "./DBconfig/sqlfiles",
  93. DatabasePath: "./DBconfig/storage.db",
  94. DataFile: "./DBconfig/data.toml",
  95. },
  96. }
  97. // 确保配置目录存在
  98. configDir := filepath.Dir(configPath)
  99. if err := os.MkdirAll(configDir, 0755); err != nil {
  100. return fmt.Errorf("创建配置目录失败: %w", err)
  101. }
  102. // 创建必要的目录
  103. if err := defaultConfig.CreateDirectories(); err != nil {
  104. return fmt.Errorf("创建必要目录失败: %w", err)
  105. }
  106. // 将配置序列化为TOML格式
  107. data, err := toml.Marshal(defaultConfig)
  108. if err != nil {
  109. return fmt.Errorf("序列化配置失败: %w", err)
  110. }
  111. // 写入配置文件
  112. if err := os.WriteFile(configPath, data, 0644); err != nil {
  113. return fmt.Errorf("写入配置文件失败: %w", err)
  114. }
  115. return nil
  116. }
  117. // LoadConfigFromFile 从文件句柄加载配置
  118. func LoadConfigFromFile(file *os.File) (*AppConfig, error) {
  119. var cfg AppConfig
  120. if err := toml.NewDecoder(file).Decode(&cfg); err != nil {
  121. return nil, err
  122. }
  123. return &cfg, nil
  124. }
  125. // SetDefaults 设置默认值
  126. func (cfg *AppConfig) SetDefaults() {
  127. // 服务器默认值
  128. if cfg.Server.Port == 0 {
  129. cfg.Server.Port = 8080
  130. }
  131. // 日志默认值
  132. if cfg.Log.Level == "" {
  133. cfg.Log.Level = "info"
  134. }
  135. if cfg.Log.Encoding == "" {
  136. cfg.Log.Encoding = "json"
  137. }
  138. if len(cfg.Log.OutputPaths) == 0 {
  139. cfg.Log.OutputPaths = []string{"stdout"}
  140. }
  141. if cfg.Log.LogDir == "" {
  142. cfg.Log.LogDir = "./DBconfig/logs"
  143. }
  144. // 审计默认值
  145. if cfg.Audit.DatabasePath == "" {
  146. cfg.Audit.DatabasePath = "./DBconfig/audit.db"
  147. }
  148. if cfg.Audit.RetentionDays == 0 {
  149. cfg.Audit.RetentionDays = 90
  150. }
  151. if cfg.Audit.BufferSize == 0 {
  152. cfg.Audit.BufferSize = 1000
  153. }
  154. // 注意:Audit.Enabled 默认为 false,需要明确启用
  155. // 存储默认值
  156. if cfg.Storage.Type == "" {
  157. cfg.Storage.Type = "db" // 默认使用数据库存储
  158. }
  159. if cfg.Storage.ConfigPath == "" {
  160. cfg.Storage.ConfigPath = "./DBconfig/data.toml"
  161. }
  162. if cfg.Storage.SQLBaseDir == "" {
  163. cfg.Storage.SQLBaseDir = "./DBconfig/sqlfiles"
  164. }
  165. if cfg.Storage.DatabasePath == "" {
  166. cfg.Storage.DatabasePath = "./DBconfig/storage.db"
  167. }
  168. if cfg.Storage.DataFile == "" {
  169. cfg.Storage.DataFile = "./DBconfig/data.toml" // 向后兼容
  170. }
  171. }
  172. // GetLogLevel 将字符串日志级别转换为 zapcore.Level
  173. func (lc *LogConfig) GetLogLevel() zapcore.Level {
  174. switch lc.Level {
  175. case "debug":
  176. return zapcore.DebugLevel
  177. case "info":
  178. return zapcore.InfoLevel
  179. case "warn", "warning":
  180. return zapcore.WarnLevel
  181. case "error":
  182. return zapcore.ErrorLevel
  183. case "fatal":
  184. return zapcore.FatalLevel
  185. default:
  186. return zapcore.InfoLevel
  187. }
  188. }
  189. // GetOutputPaths 获取完整的输出路径列表
  190. func (lc *LogConfig) GetOutputPaths() []string {
  191. paths := make([]string, 0, len(lc.OutputPaths))
  192. for _, path := range lc.OutputPaths {
  193. if path == "stdout" {
  194. paths = append(paths, "stdout")
  195. } else if path == "stderr" {
  196. paths = append(paths, "stderr")
  197. } else {
  198. // 如果是相对路径,转换为绝对路径
  199. if !filepath.IsAbs(path) {
  200. absPath := filepath.Join(lc.LogDir, path)
  201. paths = append(paths, absPath)
  202. } else {
  203. paths = append(paths, path)
  204. }
  205. }
  206. }
  207. return paths
  208. }
  209. // Validate 验证配置的有效性
  210. func (cfg *AppConfig) Validate() error {
  211. // 验证服务器配置
  212. if cfg.Server.Port <= 0 || cfg.Server.Port > 65535 {
  213. return fmt.Errorf("invalid server port: %d", cfg.Server.Port)
  214. }
  215. // 验证日志配置
  216. validLevels := map[string]bool{
  217. "debug": true, "info": true, "warn": true, "warning": true,
  218. "error": true, "fatal": true,
  219. }
  220. if !validLevels[cfg.Log.Level] {
  221. return fmt.Errorf("invalid log level: %s", cfg.Log.Level)
  222. }
  223. validEncodings := map[string]bool{
  224. "json": true, "console": true,
  225. }
  226. if !validEncodings[cfg.Log.Encoding] {
  227. return fmt.Errorf("invalid log encoding: %s", cfg.Log.Encoding)
  228. }
  229. // 验证审计配置
  230. if cfg.Audit.RetentionDays < 0 {
  231. return fmt.Errorf("invalid audit retention days: %d", cfg.Audit.RetentionDays)
  232. }
  233. if cfg.Audit.BufferSize < 0 {
  234. return fmt.Errorf("invalid audit buffer size: %d", cfg.Audit.BufferSize)
  235. }
  236. // 验证存储配置
  237. validStorageTypes := map[string]bool{
  238. "file": true, "db": true,
  239. }
  240. if !validStorageTypes[cfg.Storage.Type] {
  241. return fmt.Errorf("invalid storage type: %s", cfg.Storage.Type)
  242. }
  243. return nil
  244. }
  245. // CreateDirectories 创建必要的目录
  246. func (cfg *AppConfig) CreateDirectories() error {
  247. dirs := []string{
  248. cfg.Log.LogDir,
  249. filepath.Dir(cfg.Audit.DatabasePath),
  250. cfg.Storage.SQLBaseDir,
  251. filepath.Dir(cfg.Storage.DataFile),
  252. }
  253. // 根据存储类型添加额外的目录
  254. if cfg.Storage.Type == "db" {
  255. dirs = append(dirs, filepath.Dir(cfg.Storage.DatabasePath))
  256. }
  257. for _, dir := range dirs {
  258. if dir == "" {
  259. continue
  260. }
  261. if err := os.MkdirAll(dir, 0755); err != nil {
  262. return fmt.Errorf("failed to create directory %s: %w", dir, err)
  263. }
  264. }
  265. return nil
  266. }
  267. // GetStorageManager 根据配置创建存储管理器
  268. func (sc *StorageConfig) GetStorageManager() (interface{}, error) {
  269. switch sc.Type {
  270. case "file":
  271. // 这里需要导入storage包,但为了避免循环依赖,我们返回配置信息
  272. return map[string]string{
  273. "type": "file",
  274. "config_path": sc.ConfigPath,
  275. "sql_base_dir": sc.SQLBaseDir,
  276. }, nil
  277. case "db":
  278. return map[string]string{
  279. "type": "db",
  280. "database_path": sc.DatabasePath,
  281. }, nil
  282. default:
  283. return nil, fmt.Errorf("unsupported storage type: %s", sc.Type)
  284. }
  285. }
  286. // IsFileStorage 是否使用文件存储
  287. func (sc *StorageConfig) IsFileStorage() bool {
  288. return sc.Type == "file"
  289. }
  290. // IsDBStorage 是否使用数据库存储
  291. func (sc *StorageConfig) IsDBStorage() bool {
  292. return sc.Type == "db"
  293. }