/
codespawn
/
tgstream
Обзор
Документация
Войти
/
codespawn
/
tgstream
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
16
CI/CD
Аналитика
Безопасность
master
internal/dsl/loader.go
92 строки
3 KB
codespawn
Запрос на слияние 'feat/websource-edge-docs' (
#3
) из feat/websource-edge-docs в master
16 июл 2026, 07:24
Верифицирован
16 июл 2026, 07:24
fb8bdd6
Код
Авторство
О чём код?
package dsl import ( "encoding/json" "fmt" "os" "path/filepath" "strings" "gopkg.in/yaml.v3" ) // LoadDir читает все *.yaml/*.yml/*.json-файлы из dir, декодирует каждый в Config // и возвращает карту feedID → *Config. // // Поведение: // - Файлы с другими расширениями (*.txt, *.md) игнорируются. // - Дублирующийся feedID (поле Config.ID) в разных файлах → ошибка (fail-fast): // неоднозначная конфигурация, оператор должен разрешить коллизию. // - Ошибка чтения/декодирования/валидации любого файла → возврат с ошибкой; // частичный результат не отдаётся (атомарность: либо все конфиги, либо никто). // // Формат определяется расширением: .yaml/.yml → YAML, .json → JSON. JSON — // канонический (для визуального редактора), YAML — sugar; декодируются в одну // структуру Config. // // Пустая/несуществующая директория → ошибка (конфиги обязательны для работы // адаптера websource; это проверяется на старте, а не в рантайме). func LoadDir(dir string) (map[string]*Config, error) { entries, err := os.ReadDir(dir) if err != nil { return nil, fmt.Errorf("dsl: read config dir %q: %w", dir, err) } out := make(map[string]*Config) for _, e := range entries { if e.IsDir() { continue } name := e.Name() if !isConfigFile(name) { continue } path := filepath.Join(dir, name) cfg, err := loadFile(path) if err != nil { return nil, fmt.Errorf("dsl: config %q: %w", name, err) } if err := cfg.Validate(); err != nil { return nil, fmt.Errorf("dsl: config %q: %w", name, err) } if _, dup := out[cfg.ID]; dup { return nil, fmt.Errorf("dsl: duplicate feed id %q (in %q)", cfg.ID, name) } out[cfg.ID] = cfg } if len(out) == 0 { return nil, fmt.Errorf("dsl: no config files found in %q (expected *.yaml/*.yml/*.json)", dir) } return out, nil } // isConfigFile — поддерживаемые расширения конфигов. func isConfigFile(name string) bool { ext := strings.ToLower(filepath.Ext(name)) return ext == ".yaml" || ext == ".yml" || ext == ".json" } // loadFile читает и декодирует один файл по его расширению. func loadFile(path string) (*Config, error) { raw, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("read: %w", err) } var cfg Config switch ext := strings.ToLower(filepath.Ext(path)); ext { case ".yaml", ".yml": if err := yaml.Unmarshal(raw, &cfg); err != nil { return nil, fmt.Errorf("yaml decode: %w", err) } case ".json": if err := json.Unmarshal(raw, &cfg); err != nil { return nil, fmt.Errorf("json decode: %w", err) } default: return nil, fmt.Errorf("unsupported extension %q", ext) } return &cfg, nil }