This commit is contained in:
2026-07-13 12:30:05 +08:00
parent 7d61aadc5d
commit f25e128299
2023 changed files with 9042 additions and 922 deletions
+223
View File
@@ -0,0 +1,223 @@
---
# icon: material/architecture
tags: ["iptvc", "разработка", "архитектура"]
---
# Архитектура iptvc
Внутреннее устройство программы для разработчиков.
## Стек технологий
- **Go 1.22+** — язык программирования;
- `net/http` — HTTP-сервер (Go 1.22 routing patterns);
- `html/template` — шаблоны HTML;
- `//go:embed` — встраивание шаблонов в бинарник;
- `github.com/spf13/cobra` — CLI-фреймворк;
- `gopkg.in/yaml.v3` — парсинг `config.yml`;
- `github.com/joho/godotenv` — загрузка `.env`;
- `github.com/redis/go-redis/v9` — клиент KeyDB/Redis.
## Структура проекта
```
iptvc/
├── main.go # точка входа
├── config.yml # конфигурация
├── .env # переменные окружения (опционально)
├── cmd/ # CLI-команды (Cobra)
│ ├── root.go # корневая команда, глобальные флаги
│ ├── check.go # команда check
│ ├── serve.go # команда serve
│ ├── flags.go # общие флаги check/serve
│ └── version.go # команда version
├── app/
│ ├── app.go # глобальные переменные: Args, Config, Cache
│ ├── config/
│ │ └── config.go # Config, Init(), validate(), IntRange, UserAgents
│ ├── checker/
│ │ └── checker.go # CheckPlaylists(), CheckChannels(), OnPlaylistChecked
│ ├── playlist/
│ │ └── playlist.go # Playlist, Channel, Parse(), Download()
│ ├── inifile/
│ │ └── inifile.go # чтение playlists.ini
│ ├── tagfile/
│ │ └── tagfile.go # чтение channels.json, назначение тегов
│ ├── cache/
│ │ └── cache.go # подключение к KeyDB/Redis
│ ├── logger/
│ │ └── logger.go # настройка логирования
│ ├── utils/
│ │ └── utils.go # Fetch(), ExpandPath(), ArrayUnique(), Md5str()
│ └── web/
│ ├── server.go # Server, Start(), StartBackgroundChecker()
│ ├── handlers.go # HTTP-обработчики
│ ├── templates.go # TemplateManager, //go:embed
│ └── views/ # HTML-шаблоны
│ ├── base.html
│ ├── list.html
│ ├── details.html
│ └── notfound.html
└── go.mod
```
## Пакеты
### `app`
Глобальный контейнер: `Args` (CLI-флаги), `Config` (конфигурация), `Cache` (Redis-клиент).
`Init()` загружает конфигурацию, инициализирует логгер и подключение к кешу.
### `app.config`
Структуры: `Config``AppConfig`, `ServerConfig`, `CheckConfig`, `CacheConfig`.
Кастомные YAML-типы:
- **`IntRange`** — скаляр или `[min, max]`. Метод `Value()` возвращает константу или случайное значение.
- **`UserAgents`** — строка или массив строк. Метод `Pick()` возвращает случайный элемент.
`Init(configPath)` — загружает `config.yml`, применяет env, валидирует.
`validate()` — проверяет все значения, исправляет некорректные с логированием.
### `app.checker`
Содержит логику проверки:
- **`PrepareListsToCheck(files, urls, codes)`** — формирует список плейлистов из файлов, URL и кодов ini-файла.
- **`CheckPlaylists(lists)`** — параллельная проверка плейлистов (семфор `per-routine`), загрузка, парсинг, вызов `CheckChannels` для каждого.
- **`CheckChannels(pls)`** — параллельная проверка каналов (семфор `per-routine`), HTTP-запрос с `Range` header.
- **`OnPlaylistChecked`** — глобальный callback, вызывается после проверки каждого плейлиста. Используется веб-сервером для обновления in-memory кеша.
- **`cachePlaylist(pls)`** — сохранение результата в Redis (если включён).
Параметры проверки берутся из `app.Config.Check.Playlists` и `app.Config.Check.Channels`.
### `app.playlist`
- **`Playlist`** — плейлист: код, URL, контент, каналы, статус.
- **`Channel`** — канал: ID, название, URL, статус, теги.
- **`Download(userAgent, timeout)`** — загрузка по URL.
- **`ReadFromFs()`** — чтение из файла.
- **`Parse()`** — парсинг m3u/m3u8 контента.
### `app.web`
Веб-сервер на `net/http` (Go 1.22 routing).
- **`Server`** — структура: конфиг, кеш, шаблоны, in-memory кеш (`memCache` с `sync.RWMutex`).
- **`Start()`** — запуск HTTP-сервера.
- **`StartBackgroundChecker(opts)`** — фоновая проверка в отдельной горутине.
- **`CheckOptions`** — параметры: Every, Repeat, Random, Files, Urls, Codes.
Маршруты (Go 1.22 patterns):
```
GET /api/playlists/{code} — JSON плейлиста
GET /api/version — версия
GET /api/health — здоровье сервиса
GET /api/stats — статистика
GET /{$} — главная (catch-all root)
GET /{path...} — все остальные маршруты (catch-all)
```
Catch-all `/{path...}` используется для избежания конфликтов паттернов в Go 1.22 mux.
In-memory кеш (`memCache`) обновляется через `OnPlaylistChecked` callback.
Это позволяет отображать результаты проверки в реальном времени без ожидания завершения цикла и без Redis.
ini-файл кешируется на 30 секунд, кеш сбрасывается при каждом обновлении `memCache`.
## Жизненный цикл `serve --check`
```
main → app.Init() → web.NewServer() → go StartBackgroundChecker() → server.Start()
StartBackgroundChecker:
loop:
runCheckerOnce()
→ checker.PrepareListsToCheck()
→ checker.CheckPlaylists()
→ for each playlist (parallel, per-routine):
→ Download() / ReadFromFs()
→ Parse()
→ CheckChannels()
→ for each channel (parallel, per-routine):
→ HTTP GET with Range header
→ check status + content type
→ OnPlaylistChecked(pls) → memCache update
→ one-cooldown sleep
→ all-cooldown sleep
sleep(every)
if repeat > 0 && iteration >= repeat: stop
```
## CLI-флаги
### Общие (`cmd/flags.go`)
Используются командами `check` и `serve --check`:
| Флаг | Поле | Описание |
| -------------------------- | -------------------- | ---------------------------------- |
| `-i, --ini` | `Args.IniPath` | Путь к playlists.ini |
| `-t, --tags` | `Args.TagsPath` | Путь к channels.json |
| `-r, --random` | `Args.RandomCount` | Случайные N плейлистов |
| `--repeat` | `Args.RepeatCount` | Количество циклов (0 = бесконечно) |
| `--playlists-all-cooldown` | `Args.PlAllCooldown` | Миллисекунд между циклами |
### Только `check` (`addCheckOnlyFlags`)
| Флаг | Поле | Описание |
| ------------- | ---------------- | ------------------- |
| `-j, --json` | `Args.NeedJson` | Вывод в JSON |
| `-q, --quiet` | `Args.NeedQuiet` | Подавить логи |
| `-f, --file` | `Args.Files` | Локальные m3u файлы |
| `-u, --url` | `Args.Urls` | URL плейлистов |
| `-c, --code` | `Args.Codes` | Коды из ini-файла |
### Только `serve`
| Флаг | Поле | Описание |
| ------------ | ----------------- | ------------------------- |
| `-p, --port` | `Args.ServerPort` | Порт веб-сервера |
| `--host` | `Args.ServerHost` | Хост привязки |
| `--check` | `Args.NeedCheck` | Включить фоновую проверку |
### Глобальные (`cmd/root.go`)
| Флаг | Поле | Описание |
| --------------- | ----------------- | ----------------- |
| `--config` | `Args.ConfigPath` | Путь к config.yml |
| `-v, --verbose` | `Args.Verbose` | Подробный лог |
## Конфигурация
Подробное описание параметров — в разделе [config.yml](../../common/config/config.md).
Приоритет: Defaults < `config.yml` < Env < CLI-флаги.
CLI-флаги переопределяют конфигурацию только если переданы явно (`cmd.Flags().Changed()`).
Для этого в Cobra используются zero-value defaults (0, "", false), чтобы отличить «не передан» от «передан со значением по умолчанию».
## Шаблоны
HTML-шаблоны встроены через `//go:embed`:
- `base.html` — общий каркас (header, footer);
- `list.html` — список плейлистов с пагинацией;
- `details.html` — детали плейлиста и список каналов;
- `notfound.html` — страница 404.
SVG-логотипы каналов передаются через `encodeURIComponent` в data-URI для корректной работы с кавычками в HTML.
При отсутствии `playlists.ini` рендерится пустое состояние с alert-блоком.
## Кеширование
Два уровня кеша:
1. **Redis/KeyDB** (опционально) — постоянный кеш результатов проверки. TTL из `cache.ttl`.
2. **In-memory** (`memCache`) — только при `serve --check`. Обновляется в реальном времени через callback. Не требует Redis.
In-memory кеш приоритетнее Redis при отображении в веб-интерфейсе.