package middleware import ( "fmt" "os" "path/filepath" "regexp" "sort" "xg_dba/internal/models" "github.com/mitchellh/mapstructure" "github.com/spf13/viper" ) // InitCache 初始化缓存,从指定目录中读取 TOML 文件内容并存储到 packageModels 映射中。 func InitCache(folderPath string) { packageModels := make(map[string]models.Cache) err := filepath.Walk(folderPath, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() { listenFilePath := filepath.Join(path, "listen.toml") var connectInfo models.ConnectInfo var systemMetaInfo models.SystemMetaInfo // 如果 listen.toml 文件存在,解析它到 connectInfo 结构体中 if fileExists(listenFilePath) { if err := parseTomlFile(listenFilePath, &connectInfo); err != nil { return err } } // 获取目录中最新的 os_info.toml 文件 latestOsInfoFilePath, err := getLatestOsInfoFile(path) if err != nil { return err } // 如果找到最新的 os_info.toml 文件,解析它到 systemMetaInfo 结构体中 if latestOsInfoFilePath != "" { if err := parseTomlFile(latestOsInfoFilePath, &systemMetaInfo); err != nil { return err } } // 使用主机地址作为键,将解析的信息存储到 packageModels 映射中 host := connectInfo.Ssh.Host if host != "" { packageModels[host] = models.Cache{ ConnectInfo: connectInfo, SystemMetaInfo: systemMetaInfo, } } } return nil }) if err != nil { fmt.Printf("遍历路径 %q 时出错: %v\n", folderPath, err) return } // 打印每个主机的缓存数据 for host, cache := range packageModels { fmt.Printf("主机: %s, 缓存: %+v\n", host, cache) } } // fileExists 检查给定路径的文件是否存在。 func fileExists(filename string) bool { info, err := os.Stat(filename) if os.IsNotExist(err) { return false } return !info.IsDir() } // parseTomlFile 使用 viper 解析 TOML 文件到提供的结构体中。 func parseTomlFile(filePath string, v interface{}) error { // 为了防止 viper 的全局状态干扰解析结果,使用新的 viper 实例 vp := viper.New() vp.SetConfigFile(filePath) vp.SetConfigType("toml") if err := vp.ReadInConfig(); err != nil { return err } // 使用 `vp.AllSettings()` 将配置映射到提供的结构体 settings := vp.AllSettings() if err := decodeSettings(settings, v); err != nil { return err } return nil } // decodeSettings 将 viper 的设置映射解码到目标结构体。 func decodeSettings(settings map[string]interface{}, v interface{}) error { decoderConfig := &mapstructure.DecoderConfig{ Result: v, TagName: "toml", WeaklyTypedInput: true, } decoder, err := mapstructure.NewDecoder(decoderConfig) if err != nil { return err } return decoder.Decode(settings) } // getLatestOsInfoFile 在给定目录中查找最新的 os_info TOML 文件。 // 它查找匹配模式 "os_info_.toml" 的文件,并返回最新的一个。 func getLatestOsInfoFile(dirPath string) (string, error) { pattern := regexp.MustCompile(`^os_info(?:_\d{8}_\d{6})?\.toml$`) files, err := os.ReadDir(dirPath) if err != nil { return "", err } var matchingFiles []string for _, file := range files { if !file.IsDir() && pattern.MatchString(file.Name()) { matchingFiles = append(matchingFiles, filepath.Join(dirPath, file.Name())) } } // 如果没有找到匹配的文件,返回空字符串 if len(matchingFiles) == 0 { return "", nil } // 将匹配的文件按降序排序,以获取最新的文件 sort.Slice(matchingFiles, func(i, j int) bool { return matchingFiles[i] > matchingFiles[j] }) return matchingFiles[0], nil }