package tmpls import ( "embed" _ "embed" "errors" "fmt" "io/fs" "path/filepath" "strings" ) // 核心: // 1. 从嵌入的文件系统中读取指定目录下的单个配置文件内容 // 2. 检查文件是否存在 // 3. 读取文件内容 // 通配符说明: // - db/*/*.yaml : 匹配data/一级子目录下的所有yaml文件. // - 如需递归匹配子目录(如data/db/sub/*.yaml),用 data/**/*.yaml(Go.18+) // //go:embed frontend/*.yaml firewall/*.yaml var ConfigFS embed.FS // GetConfigFile 获取指定目录下的的单个配置文件内容 // // 参数: // - dir : 目录名(db/services/firewall...) // - name: 文件名(如base.yaml) // // 返回值: // - []byte: YAML 文件的内容 // - error: 如果读取文件失败,返回错误信息 func GetConfigFile(dir, name string) ([]byte, error) { // 拼接完整路径(基于tmpls.go所在的 data 目录) fullPath := filepath.Join(dir, name) // 检查文件是否存在(避免ReadFile直接报错) _, err := fs.Stat(ConfigFS, fullPath) if err != nil { if errors.Is(err, fs.ErrNotExist) { return nil, fmt.Errorf("配置文件不存在: %s", fullPath) } return nil, fmt.Errorf("读取配置文件失败: %w", err) } // 读取文件内容 content, err := ConfigFS.ReadFile(fullPath) if err != nil { return nil, fmt.Errorf("读取配置文件内容失败: %w", err) } return content, nil } // GetConfigDir 获取指定目录下的所有配置文件内容 // // 参数: // - dir : 目录名(db/services/firewall...) // // 返回值: // - map[string][]byte: 键为文件名(如base.yaml), 值为文件内容 // - error: 如果读取文件失败,返回错误信息 func GetConfigDir(dir string) (map[string][]byte, error) { // 存储结果: key=文件名 value=文件内容 configMap := make(map[string][]byte) // 遍历指定目录下的所有文件 err := fs.WalkDir(ConfigFS, dir, func(path string, d fs.DirEntry, err error) error { if err != nil { return fmt.Errorf("遍历目录失败: %w", err) } // 跳过目录,只处理文件 if d.IsDir() { return nil } // 只处理yaml文件(双重效验,避免非yaml文件) if !strings.HasSuffix(d.Name(), ".yaml") { return nil } // 读取文件内容 content, err := ConfigFS.ReadFile(path) if err != nil { return fmt.Errorf("读取文件内容失败: %w", err) } // 存储: key用文件名(如base.yaml),而非完整路径. configMap[d.Name()] = content return nil }) if err != nil { return nil, err } return configMap, nil } // GetAllConfigDirs 获取所有嵌入目录(db/services/firewall...)的配置 // // 返回值: // - map[目录名]map[文件名]文件内容 // - error: 如果读取文件失败,返回错误信息 func GetAllConfigDirs() (map[string]map[string][]byte, error) { allConfigs := make(map[string]map[string][]byte) // 动态获取所有一级子目录(如db/services/firewall) dirs, err := GetAllSubDirs() if err != nil { return nil, err } // 遍历所有嵌入目录 for _, dir := range dirs { dirConfigs, err := GetConfigDir(dir) if err != nil { // 可选: 忽略空目录、错误目录,继续处理其他目录 // 如不需要、直接返回错误、return nil, err continue } allConfigs[dir] = dirConfigs } return allConfigs, nil } // GetAllSubDirs 动态获取data/下的所有一级子目录 // // 返回值: // - []string: 所有一级子目录名(如db/services/firewall) // - error: 如果读取目录失败,返回错误信息 func GetAllSubDirs() ([]string, error) { var subDirs []string // 遍历data/目录下的所有一级子目录 err := fs.WalkDir(ConfigFS, "", func(path string, d fs.DirEntry, err error) error { if err != nil { return fmt.Errorf("遍历目录失败: %w", err) } // 过滤条件: // 1. 是目录(d.IsDir()) // 2. 是一级子目录(path不含/,排除嵌套子目录如db/sub) // 3. 排除根目录本身(path != "") if d.IsDir() && !strings.Contains(path, "/") && path != "" { subDirs = append(subDirs, path) // 跳过该目录的子目录遍历(提升性能) return fs.SkipDir } return nil }) if err != nil { return nil, err } return subDirs, nil }