Prepare release 2.5.1

This commit is contained in:
Divarion_D
2026-09-11 20:12:09 +03:00
parent 3757bd97a9
commit dbdab9b050
7 changed files with 213 additions and 103 deletions
+29 -30
View File
@@ -1,34 +1,33 @@
{
"version": "2.5.0",
"version": "2.5.1",
"changes": [
"Completed the large-scale migration of the admin interface to Bootstrap 5",
"Rebuilt the admin shell with a modern responsive layout",
"Migrated administration tables to clean JSON-based data endpoints",
"Migrated streams, VOD, series, episodes, users, devices, servers, EPG, backups, security, logs and other management pages to Bootstrap 5",
"Added Bootstrap 5 modal and tabbed form layouts",
"Migrated the reseller panel to the Bootstrap 5 interface",
"Redesigned admin and reseller login pages with a sci-fi HUD-style interface",
"Rebuilt the admin dashboard using Bootstrap 5 statistics cards",
"Added a world map visualization of active connections",
"Added per-user UI customization persisted in users.ui_prefs",
"Added global quick search with structured JSON results",
"Reorganized the admin sidebar and navigation",
"Added xcToast notifications to replace native browser alerts",
"Added module provider contracts for topbar, tables, permissions and quick tools",
"Improved module controller and REST integration",
"Added configurable xc_fanout source backend",
"Added per-repository update channels (Stable/Beta) for the panel, binaries and the xc_fanout daemon",
"Added xc_fanout version tracking and integrity probing",
"Improved HLS MEDIA-SEQUENCE handling across off-air and live transitions",
"Improved stream entry point readability and stability",
"Added synthetic input-free test patterns to the stream generator",
"Improved VOD analyzer stability under PHP 8",
"Added Playwright end-to-end smoke testing for the Bootstrap 5 admin",
"Expanded test coverage for migrated admin tables",
"Improved GeoIP release synchronization",
"Fixed numerous admin UI, PHP 8, null-safety and streaming issues",
"Updated contributor, module, FFmpeg and architecture documentation",
"Removed obsolete DTS/AC3 testing helpers",
"Updated PHPStan and other dependencies"
"Added a complete Smart Activation Codes system with pre-generated voucher codes, delayed first-use activation, automatic subscriber line creation, batch management, mass editing, exports, admin/reseller interfaces, an activation portal and a public activation API.",
"Added transactional activation-code generation with reseller credit validation, balance deductions and audit logging.",
"Added configurable xc_fanout encoder supervision so live stream encoders can be managed and monitored by the streaming daemon instead of a separate PHP watchdog process.",
"Added the fanout_supervise setting with a safe disabled default for existing installations and synchronized the setting into the daemon configuration.",
"Added supervision reconciliation, health policies, source forcing and daemon-aware process management.",
"Added reliable IngestFeeder support for PHP-based producers feeding MPEG-TS data into xc_fanout.",
"Fixed short non-blocking socket writes, preventing incomplete TS packets from being silently discarded.",
"Added daemon reconnect and re-registration handling with packet-aligned recovery after connection failures or daemon restarts.",
"Added bounded ingest buffering with whole-packet shedding to prevent producers from blocking indefinitely.",
"Added HLS key and IV propagation for encrypted streams handled through the fanout ingest path.",
"Moved live encoder supervision and stream ownership handling further into the xc_fanout architecture.",
"Improved on-demand stream startup by using the configured on_demand_wait_time and clearing stale PID and monitor files before restarting a stream.",
"Fixed asynchronous file-operation caching and inotify timeout behavior, including stale cache invalidation when files appear.",
"Improved stream monitoring with FPS-drop restarts, better backup-source priority handling and failed-probe recovery.",
"Fixed catch-up routing, proxy-only checks and adaptive stream variant authentication behavior.",
"Corrected VOD and catch-up byte ranges to provide proper seeking and delivery behavior.",
"Fixed live HLS playlist sequence handling so playlists are not unnecessarily renumbered when segment durations exceed 10 seconds.",
"Improved daemon viewer connection-limit enforcement and viewer kick handling.",
"Added producer, CPU and memory information to the admin streams page.",
"Improved stream supervision metadata so the panel correctly records which producer and process path owns a stream.",
"Added version-at-error-time information to panel logs for more accurate troubleshooting of historical errors.",
"Added new streaming documentation covering daemon feeds, kicks, HLS keys, byte ranges, stream supervision and the native remuxer.",
"Added a shared synthetic test-stream generator with a TS encoder, keyframe-aligned joins and launcher support.",
"Added and expanded fanout supervision and ingest tests.",
"Added the database migration required for fanout_supervise and updated related settings handling.",
"Fixed duplicate page selectors on mass operation pages.",
"Added safeguards preventing update and rollback operations from being executed without root privileges.",
"Simplified sourceContext value retrieval and integrated upstream/community changes from pull requests #186 and #187."
]
}
+51 -46
View File
@@ -20,8 +20,11 @@ git log --pretty=format:"- %s (%h)" "$PREV_TAG"..main > dist/changes.md
```json
{
"version": "X.Y.Z",
"changes": ["Description of change 1", "Description of change 2"]
"version": "X.Y.Z",
"changes": [
"Description of change 1",
"Description of change 2"
]
}
```
@@ -60,15 +63,15 @@ make docs-build # strict build — fails on any broken link/anchor
```
- `make docs-translate` повторно переводятся только те файлы на английском языке, содержимое которых
изменен (для каждого файлового кэша), так что при постепенном выпуске это происходит быстро.
изменен (для каждого файлового кэша), так что при постепенном выпуске это происходит быстро.
- **Review and commit the regenerated `docs/ru`** — он включен в единый
снимите фиксацию (шаг 5). Никогда не редактируйте вручную `docs/ru`.
- Документация публикуется **на каждый релиз, а не на каждый push**: `pages.yml`
запускается при пуше версионного **тега** (шаг 7) и публикует документы этого выпуска
как версионный снимок (`X.Y.Z` + псевдоним `latest`) в ветку `gh-pages` через
`mike`. Правки, влитые в `main` между релизами, попадают в публикацию на следующем
помеченном тегом релизе (тогда же регенерируется `docs/ru`). Селектор версий в шапке
Material позволяет читателям переключаться между выпущенными версиями.
снимите фиксацию (шаг 5). Никогда не редактируйте вручную `docs/ru`.
- Documentation is published **per release, not per push**: `pages.yml` runs when
будет запущена версия **метка** (шаг 7), и документы этого выпуска будут опубликованы в виде
версионный снимок (`X.Y.Z` + псевдоним `latest`) в ветвь `gh-pages` через
`mike`. Правки, объединенные в `main` между выпусками, будут опубликованы на следующем помеченном
высвобождение (которое также происходит при регенерации `docs/ru`). Заголовок материала
селектор версий позволяет читателям переключаться между выпущенными версиями.
---
@@ -131,6 +134,7 @@ cat src/migrations/deleted_files.txt
> любой, кто доберется до панели. Этот шаг является мерой усиления безопасности — разблокировка никогда не должна
> выходи на улицу в нем.
```text
src/Core/Config/AppConfig.php
```
@@ -171,12 +175,12 @@ make main
После построения `dist/` должно содержать:
| Файл | Описание |
| --------------------- | ------------------------------------------------------ |
| `XC_VM.zip` | ОСНОВНОЙ установщик (установить скрипт + xc_vm.tar.gz) |
| `xc_vm.tar.gz` | ОСНОВНОЙ архив (установка и обновление) |
| `loadbalancer.tar.gz` | Архив LB (установка и обновление) |
| `hashes.md5` | Контрольные суммы MD5 |
|Файл|Описание|
| --- | --- |
| `XC_VM.zip` |ОСНОВНОЙ установщик (установить скрипт + xc_vm.tar.gz)|
| `xc_vm.tar.gz` |ОСНОВНОЙ архив (установка и обновление)|
| `loadbalancer.tar.gz` |Архив LB (установка и обновление)|
| `hashes.md5` |Контрольные суммы MD5|
> Один и тот же архив используется как для чистой установки, так и для обновлений.
> Скрипт обновления (`src/update`) отфильтровывает двоичные/конфигурационные каталоги во время выполнения, используя жестко заданный список `UPDATE_EXCLUDE_DIRS` внутри самого скрипта Python.
@@ -213,7 +217,7 @@ bash tools/test-install/test_release.sh
- Прикрепите их к фиксатору
- Отправьте уведомление в Telegram через `release-notifier.yml`
- Опубликуйте документацию по этой версии на страницах GitHub через `pages.yml` (mike):
моментальный снимок `X.Y.Z` плюс псевдоним `latest`, который можно выбрать из заголовка документа
моментальный снимок `X.Y.Z` плюс псевдоним `latest`, который можно выбрать из заголовка документа
> ✅ Дождитесь завершения рабочего процесса действий, затем убедитесь, что все файлы доступны для загрузки.
@@ -226,6 +230,7 @@ bash tools/test-install/test_release.sh
> в **та же версия** — LBs считывается база данных MAIN, и может возникнуть перекос в схеме/поведении
> потоковый. Не оставляйте LBs без внимания.
- [ ] Убедитесь, что все 4 ресурса присоединены к релизу
- [ ] Выполнить `md5sum -c hashes.md5` для загруженных файлов
- [ ] Проверьте, отправлено ли уведомление Telegram
@@ -236,14 +241,14 @@ bash tools/test-install/test_release.sh
## Если что-то пойдет не так
- **После публикации не удалось выполнить построение действий** — в релизе отсутствуют (или частично) ресурсы. Повторно запустите
сбой рабочего процесса на вкладке Действия; если сам тег неверен, удалите выпуск **и**, который
пометьте (`git push --delete origin vX.Y.Z`), исправьте и пометьте повторно. Не оставляйте опубликованный релиз с
отсутствующие ресурсы — панели извлекают из него `hashes.md5` / архивы.
сбой рабочего процесса на вкладке Действия; если сам тег неверен, удалите выпуск **и**, который
пометьте (`git push --delete origin vX.Y.Z`), исправьте и пометьте повторно. Не оставляйте опубликованный релиз с
отсутствующие ресурсы — панели извлекают из него `hashes.md5` / архивы.
- **Выпущенный актив поврежден** — опубликовать выпуск исправления **заплатка** (новый тег) вместо редактирования
опубликованный файл; клиенты прикрепляют его к тегу.
опубликованный файл; клиенты прикрепляют его к тегу.
- **Плохой релиз уже достиг серверов** — операторы могут понизить рейтинг каждого сервера с помощью панели управления
(**Серверы → Откат версии**, см. [Механизм обновления → Откат](../administration/update-system.md#rollback-downgrade)); в MAIN сначала автоматически создается резервная копия базы данных. Миграции выполняются
доступна только переадресация, поэтому, если исправление небольшое, предпочитайте исправление с переадресацией.
(**Серверы → Откат версии**, см. [Механизм обновления → Откат](../administration/update-system.md#rollback-downgrade)); в MAIN сначала автоматически создается резервная копия базы данных. Миграции выполняются
доступна только переадресация, поэтому, если исправление небольшое, предпочитайте исправление с переадресацией.
---
@@ -253,32 +258,32 @@ bash tools/test-install/test_release.sh
**Проверка качества** — сначала запустите `make dev-tools`, затем `make dev-clean`, когда закончите:
| Команда | Цель |
| ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `make dev-tools` | Установите инструменты разработки (PHPStan, phpcs) через `composer install` |
| `make phpstan` | Статический анализ (также выявляет синтаксические ошибки) |
| `make phpstan-baseline` | Восстановите базовую линию PHPStan |
| `make cs` | Проверка стиля кода - импорт/гигиена пространства имен (phpcs + Slevomat) |
| `make cs-fix` | Примените исправления в стиле кода на месте |
| `make gates` | PSR-4 регрессионные шлюзы (для процедурного использования, для LB-архива, только для продукта поставщика) |
| `make dev-clean` | Снова удалите инструменты разработки, восстановив только производственную версию `vendor/`. |
| `php tools/.bin/phpunit.phar -c tests/phpunit.xml.dist` | Модульные тесты |
|Команда|Цель|
| --- | --- |
| `make dev-tools` |Установите инструменты разработки (PHPStan, phpcs) через `composer install`|
| `make phpstan` |Статический анализ (также выявляет синтаксические ошибки)|
| `make phpstan-baseline` |Восстановите базовую линию PHPStan|
| `make cs` |Проверка стиля кода - импорт/гигиена пространства имен (phpcs + Slevomat)|
| `make cs-fix` |Примените исправления в стиле кода на месте|
| `make gates` |PSR-4 регрессионные шлюзы (для процедурного использования, для LB-архива, только для продукта поставщика)|
| `make dev-clean` |Снова удалите инструменты разработки, восстановив только производственную версию `vendor/`.|
| `php tools/.bin/phpunit.phar -c tests/phpunit.xml.dist` |Модульные тесты|
**Release prep & build:**
| Команда | Цель |
| ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `make generate_deleted_files` | Регенерировать `src/migrations/deleted_files.txt` |
| `make new` | Wipe + recreate `dist/` — запускается ОДИН раз в начале (шаг 1), перед записью `dist/changes.md`; никогда больше перед созданием |
| `make lb` | Создайте архив LoadBalancer в виде `dist/` |
| `make main` | Соберите ОСНОВНОЙ архив в `dist/` |
| `bash tools/test-install/test_release.sh` | Установочный тест Docker для встроенного выпуска |
|Команда|Цель|
| --- | --- |
| `make generate_deleted_files` |Регенерировать `src/migrations/deleted_files.txt`|
| `make new` |Wipe + recreate `dist/` — запускается ОДИН раз в начале (шаг 1), перед записью `dist/changes.md`; никогда больше перед созданием|
| `make lb` |Создайте архив LoadBalancer в виде `dist/`|
| `make main` |Соберите ОСНОВНОЙ архив в `dist/`|
| `bash tools/test-install/test_release.sh` |Установочный тест Docker для встроенного выпуска|
**Документация** (английский источник в `docs/en`; `docs/ru` сгенерирован + зафиксирован):
| Команда | Цель |
| --------------------- | ----------------------------------------------------------------------------------------- |
| `make docs-venv` | Одноразовый: локальный venv (сборка + переводы) |
| `make docs-translate` | Восстановить `docs/ru` из `docs/en` (перед выпуском) |
| `make docs-build` | Строгая сборка MkDocs в `./build/site` (что запускает CI) |
| `make docs-serve` | Предварительный просмотр документов в режиме реального времени на `http://127.0.0.1:8000` |
|Команда|Цель|
| --- | --- |
| `make docs-venv` |Одноразовый: локальный venv (сборка + переводы)|
| `make docs-translate` |Восстановить `docs/ru` из `docs/en` (перед выпуском)|
| `make docs-build` |Строгая сборка MkDocs в `./build/site` (что запускает CI)|
| `make docs-serve` |Предварительный просмотр документов в режиме реального времени на `http://127.0.0.1:8000`|
+92 -16
View File
@@ -189,11 +189,11 @@ Alt-Svc: h3-29, h3-T051, h3-Q050 (HTTP/3 hints)
### VOD (vod.php)
Тот же процесс аутентификации, что и в live. Считывается из `VOD_PATH` вместо `STREAMS_PATH`.
Тот же процесс аутентификации, что и в live. Считывается из `VOD_PATH` вместо `STREAMS_PATH`. Диапазоны байтов (поиск) разрешаются с помощью `Streaming\Delivery\HttpRange` (одиночные диапазоны RFC 7233, включая диапазоны суффиксов). Видеофильм с прямым подключением передается с помощью cURL, запрашивая у источника точно запрошенный диапазон.
### Временной сдвиг (timeshift.php)
Обслуживает архивированные сегменты (timeshift / catch-up) из пути к архиву.
Обслуживает архивированные сегменты (timeshift / catch-up) из пути к архиву. Запрос TS передает в потоковом режиме несколько файлов подряд; им сопоставляется диапазон байт (поиск) — файлы перед началом пропускаются, первый вводится с правильным смещением, и доставка прекращается в конце диапазона.
### Доставка демона — `xc_fanout`
@@ -203,23 +203,93 @@ PHP-FPM работник, отвечающий за жизнедеятельно
- **Расходимся веером.** `xc_fanout` (встроенный демон Go) извлекает каждый источник **однажды** и
предоставляет его каждому пользователю через сокет unix с помощью встроенного в оперативную память сегментатора HLS.
PHP находится вне байтового пути для каждого зрителя: рабочий процесс чтения для каждого зрителя
цикл обслуживания и путь `HLSGenerator::generateHLS()` для обслуживания клиентов не являются
больше не используется для оперативной доставки (`generateHLS()` сохраняется в классе, но имеет
абонентов нет). `AsyncFileOperations::awaitFileExists()` — это **нет** удалено - это
по-прежнему используется для ожидания запуска потока и пути в байтах VOD/timeshift (см.
Таблица показателей).
PHP не соответствует байтовому пути для каждого зрителя: рабочий процесс чтения для каждого зрителя
цикл обслуживания и путь к клиенту на диске `generateHLS()` исчезли.
`AsyncFileOperations::awaitFileExists()` по-прежнему используется для запуска потока
ожидания и путь в байтах VOD/timeshift (см. таблицу производительности).
- **Кто кормит демона.** Поскольку демон является единственным путем к клиенту, каждый живой
продюсер должен включить его, иначе канал нельзя будет смотреть:
поток ffmpeg переходит в свой принимающий сокет (`buildLive()`; обратная петля
включая дочерних), создатели супервизора-демона делают то же самое, PHP
производители — сегментатор LLOD (`LlodCommand`) и ретранслятор с обратной связью
(`LoopbackCommand`) — протолкнуть через `Streaming\Fanout\IngestFeeder`, и
поток **отложенный** подается через `DelayCommand`, который перемещает каждый задержанный сегмент
по мере того, как он публикует его, в зависимости от продолжительности сегмента (его выходные данные с кодировщика являются
отложенный, поэтому тройник для него не используется). `IngestFeeder` буферизует то, что
не удалось отправить неблокирующую запись (короткая запись больше не разрывает пакеты),
выполняет повторную регистрацию и набор номера после перезапуска демона и содержит ключ HLS.
- **Две розетки.** Клиентский сокет (ориентированный на nginx) обслуживает `/live/<id>` и
`/hls/...`; управляющий сокет, предназначенный только для PHP, регистрирует источники
(`PUT /streams/<id>` / `/ingest/<id>`), отвечает на вопросы о статусе выхода в эфир
(`GET /streams/<id>`, `GET /probe/<id>`) и предоставляет доступ к телеметрии.
- **Телеметрия / согласование данных.** `fanout_sync` опросы `GET /rates` (для каждого uuid
КБИТ/с`lines_divergence`) и `GET /connections` (согласовывает `lines_live`
строк, поскольку PHP не может видеть разъединение в `X-Accel`).
КБИТ/с`lines_divergence`) и сверяет `GET /connections` с данными
`lines_live` строк в обоих направлениях: строка, просмотрщик которой покинул демон, называется
закрыто (PHP не удается увидеть отключение при `X-Accel`), и демон-просмотрщик, чей
пропущенная строка — собранная, с истекшим сроком действия или запрещенная строка — удаляется по истечении 20 секунд
(`DELETE /connections/<uuid>`).
- **Удары и ограничения по подключению.** Строка TS viewer, обслуживаемая демоном, содержит `pid = 0`:
здесь нет рабочего, которого можно было бы убить. `ConnectionLimiter` / `ConnectionTracker::closeConnection()`
завершите его с помощью `ConnectionTracker::dropDaemonViewer()``FanoutClient::dropConnection()`
на этом узле, или сигнал `drop_con` о том, что узел зрителя превращается в
тот же вызов. Ограничитель никогда не отключает запрашивающее соединение сам по себе (это
идентифицируется по uuid, поскольку каждая строка демона имеет общий pid 0).
- **Вне эфира.** Если демон сообщает об отсутствии данных (`has_data=false` / устаревшие), PHP
показывает страницу "не в эфире" вместо того, чтобы позволить зрителю зависнуть.
- **Сохранено на диске HLS** только для timeshift / миниатюр / `.analyse` /
`MonitorCommand` — не для доставки клиенту.
дочерние элементы loopback / проверки запуска по требованию — не для доставки клиенту.
#### Управление потоковой передачей и встроенный ремультиплексор
При включенном **Контроль разветвленного энкодера** (`fanout_supervise`, миграция 018, по умолчанию включено),
прямая трансляция не получает PHP watchdog. `StreamProcess::startMonitor()` строит свои команды и раздает
их супервизору демона (`FanoutClient::supervise``PUT /monitor/<id>`), который запускает,
отслеживает и перезапускает их — отработка отказа, приоритетное резервное копирование, принудительный источник, сбой вывода, потеря звука,
включая снижение частоты кадров и перезапуск по расписанию. PHP продолжает создавать каждую команду и выполнять все
запись в базу данных; демон выполняет то, что ему передают.
- **Передача** — `StreamProcess::superviseStream()` сначала запрашивает у демона
(`GET /monitors/state`: доступно, `accepting`), создает спецификацию
(`StreamProcess::buildSupervisorSpec()`: одна команда для каждого источника, политики и работоспособности, сопоставленных с
соблюдены настройки `MonitorCommand`), записывает pid демона как `monitor_pid`, затем передает его
over. Without a restart a running encoder is **adopted**, not replaced; `cron:streams` moves
PHP-отслеживает потоки таким образом при следующем проходе.
- **Команды** — прямая трансляция, доступная только для копирования, запускает собственный ремуксор демона, `xc_fanout remux`,
построенный с помощью `StreamProcess::buildNativeLive()` рядом с `buildLive()`: он считывает исходный код изначально
(MPEG-TS по протоколу http(s), HLS с сегментами TS, udp/rtp) и записывает то же самое на диск HLS и демон
подача в виде строки ffmpeg `-f tee` без ffmpeg. Какие потоки соответствуют требованиям, это
`StreamProcess::nativeRefusal()` / `isNativeSource()`; `fanout_source_backend` решает:
`auto` = повторный мультиплексор с командой ffmpeg в виде `fallback_cmd` (используется при выходе из режима 3,
"не удается обслуживать этот источник"), `native` = только для ремультиплексора, `ffmpeg` = только для ffmpeg. Только панель
записывает команду ремультиплексора, когда демон узла объявляет об этом (`features` в
`GET /monitors/state`, `FanoutClient::supportsRemux()`) — более старый двоичный файл неправильно разобрал бы его.
- **Какой продюсер баллотировался и почему** — переданная команда записывается рядом с записью потока.
файлы, подобные пути к самопроизвольному запуску `<id>_.ffmpeg`: `<id>_.fanout` для ремультиплексора,
`<id>_.ffmpeg` для ffmpeg (в `auto` - оба). Когда включен собственный сервер и выполняется поток
ffmpeg в любом случае, причина `StreamProcess::nativeRefusal()` добавляется к `<id>.errors`
(`[panel] ffmpeg runs this stream: transcoding is enabled`), тот же файл, что и у производителя.
stderr переходит в. Соответствующий тип `streams_types.type_key` = `live`; `gen_timestamps` и
`read_native` намеренно не являются отказами (оба значения по умолчанию равны 1, поэтому они ничего не говорят о
канал — смотрите программу запуска демона).
- **Reconcile** — the daemon cannot write the database, so `StreamProcess::reconcileSupervised()`
копирует его состояние в `streams_servers` (статус, pid, текущий источник, кодеки, разрешение,
измеренный битрейт): каждый проход `cron:streams` и каждые 5 секунд от демона `signals`. A
контролируемый поток, строка которого пропущена или помечена как остановленная, освобождается. Кодеки и размер изображения
записываются в `stream_info` JSON, а также в плоские столбцы — этот JSON - это то, что
отображает список потоков, из которого адаптивный мастер-плейлист берет `BANDWIDTH`/`RESOLUTION` и
где `stream/auth.php` считывает видеокодек зрителя, и контролируемый поток никогда не запускается
ffprobe чтобы заполнить его.
- **Остановка** — `StreamProcess::stopStream()` освобождает первый (`DELETE /monitor/<id>`, который убивает
продюсер); сначала супервизор перезапускает процесс, убивая продюсера.
- **Возврат к PHP** — демон, который отключен или не принимает, и поток указывает, что он не принимает
берем (задержка, созданные каналы, `yt-dlp` исходники платформы), запускаем `MonitorCommand`, как и раньше;
`MonitorCommand` отключается для потока, который контролирует демон.
- **"За этим следят?"** — для контролируемого потока `monitor_pid` - это pid демона, поэтому вызывающие абоненты используют
`StreamProcess::isWatched()` (PHP монитор активен или находится под наблюдением), а не
`ProcessManager::isMonitorAlive()` один.
Runbook на стороне демона - включение, проверка, откат кодов завершения работы ремультиплексора — это
`docs/en/09-encoder-supervision.md` в репозитории `XC_VM_Fanout`.
#### Наложение отправленного сообщения
@@ -349,7 +419,11 @@ IP-блокировка на основе файлов. Файлы блоков
### 3. Ограничитель подключений (для каждого пользователя)
Применяется после проверки токена. Ограничивает одновременные потоки для каждого пользователя на основе `max_connections`.
Применяется после проверки токена. Ограничивает одновременные потоки для каждого пользователя на основе `max_connections`, закрывая сначала самые старые соединения (более старые соединения самого запрашивающего устройства перед другими). Средства просмотра, обслуживаемые демонами, отключаются с помощью демона — см. [Daemon delivery](#daemon-delivery-xc_fanout).
### 4. Серверы, работающие только через прокси
Сервер с параметром `enable_proxy` принимает только запросы, поступающие через один из его прокси-серверов. `auth.php` проверяет одноранговый узел TCP nginx saw — `XC_PEER_ADDR`, значение которого равно `$realip_remote_addr` в расположении потока `nginx.conf`, а не заголовок запроса, которым управляет клиент.
---
@@ -357,12 +431,12 @@ IP-блокировка на основе файлов. Файлы блоков
Клиент HLS обслуживается демоном `xc_fanout` (см. [Доставка демоном](#daemon-delivery-xc_fanout)), поэтому происходит шифрование **сторона демона**:
1. `StreamProcess` записывает ключ AES-128 потока/IV в `content/streams/<id>_.key` / `_.iv`.
2. At ingest registration (`FanoutClient::registerIngest`), when `encrypt_hls` is on, the key/IV are handed to the daemon, which encrypts the HLS segments it serves and emits a matching `#EXT-X-KEY`.
3. `HLSGenerator::tokenizeDaemonPlaylist()` переписывает URL-адреса сегментов плейлиста демона в ссылки с авторизацией для каждого сегмента `/hls/<token>`, которые `segment.php` передаются через прокси-сервер демона.
1. `StreamProcess` записывает ключ AES-128 потока/IV в `content/streams/<id>_.key` / `_.iv` — перед тем, как он создаст PHP производителя, который регистрируется демоном через несколько мгновений после запуска.
2. При регистрации приема (`FanoutClient::registerIngest`), когда включено `encrypt_hls`, ключ/IV передается демону, который шифрует HLS сегмента, которые он обслуживает. Каждый производитель передает их — ffmpeg потоков (включая дочерние циклы), контролируемые потоки и PHP производителей через `IngestFeeder::forStream()` — потому что плейлист всегда объявляет ключ: демон, запущенный без него, подавал простые сегменты, которые ни один игрок не смог бы расшифровать.
3. `HLSGenerator::tokenizeDaemonPlaylist()` переписывает URL-адреса сегментов плейлиста демона в ссылки с авторизацией для каждого сегмента `/hls/<token>`, которые `segment.php` проксируются от демона, и добавляет строку `#EXT-X-KEY`.
4. Ключ AES доставляется игрокам с помощью `key.php` (`src/Public/stream/key.php`) с использованием того же механизма токенов.
> Устаревший `HLSGenerator::generateHLS()` (который создал и зашифровал плейлист на диске HLS для использования PHP) сохраняется в классе, но становится **больше не находится на пути к клиенту** после отключения демона.
Значение `#EXT-X-MEDIA-SEQUENCE` в плейлисте live повторно привязывается к значению `HlsSequence`, поэтому он никогда не возвращается назад при переходе из прямого эфира в прямой эфир без изменения нумерации воспроизводимого потока (его состояние сохраняется в виде `tmp/signals/hlsseq_<id>`, поэтому оно сохраняется после перезапуска потока).
---
@@ -431,5 +505,7 @@ SIGNALS_PATH = /home/xc_vm/signals/
| `src/Streaming/AsyncFileOperations.php` |неблокирующие утилиты для файловой системы|
| `src/Streaming/Lifecycle/ShutdownHandler.php` |очистка соединения при выходе|
| `src/Domain/Stream/ConnectionTracker.php` |состояние соединения в Redis/MySQL|
| `src/Domain/Stream/StreamProcess.php` |формирование команды (`buildLive` / `buildNativeLive`), передача контроля и согласование|
| `src/Streaming/Fanout/FanoutClient.php` |API управления демонами (прием, контроль, принудительный источник)|
| `src/Core/Init/LegacyInitializer.php` |настройка глобальной переменной для потоковой передачи|
| `tools/stream-check/stream_check.py` |проверка целостности очереди + пакет плейлистов + панель мониторинга живого буфера + графический редактор SVG|
+7 -7
View File
@@ -46,7 +46,7 @@
| `xcvm_core` | `XcvmCoreCommand` |Установите/обновите расширение `xcvm_core` PHP из хранилища двоичных файлов|корень|
| `ytdlp` | `YtDlpCommand` |Установите/обновите `yt-dlp` из своей предыдущей версии на GitHub|корень|
| `startup` | `StartupCommand` |Инициализация системы: daemons.sh, crontab, кэш|корень|
| `monitor` | `MonitorCommand` |Отслеживайте поток по идентификатору (запуск/перезапуск/отслеживание)|xc_vm|
| `monitor` | `MonitorCommand` |Отслеживайте поток по идентификатору (start/restart/track). Только для потоков, которые не выполняет супервизор xc_fanout — он заменяет контролируемый поток|xc_vm|
| `thumbnail` | `ThumbnailCommand` |Создание рамок миниатюр для потока|xc_vm|
| `plex_item` | `PlexItemCommand` |Обработать один элемент Plex (фильм/сериал)|xc_vm|
| `watch_item` | `WatchItemCommand` |Обработать один элемент наблюдения (поиск/обновление в базе данных TMDB)|xc_vm|
@@ -127,7 +127,7 @@
| `cron:plex` | `PlexCronJob` |сплетение|Обрабатывать обновления Plex|
| `cron:watch` | `WatchCronJob` |часы|Обрабатывать обновления библиотеки отслеживания|
> "Необязательные" задания cron регистрируются **нет** условно — регистрируется каждый обнаруженный класс `CronJob`. "Необязательно" означает, что задание не выполняется, если не включена его функция/настройка (например, `cron:epg`, `cron:series`, `cron:update`), или если задание не удалено из сборки LB.
> "Необязательные" задания cron регистрируются **нет** условно — регистрируется каждый обнаруженный `CronJob` класс. "Необязательно" означает, что задание не выполняется, если не включена его функция/настройка (например, `cron:epg`, `cron:series`, `cron:update`), или если задание не удалено из сборки LB.
---
@@ -138,12 +138,12 @@
старая сборка, никогда не сходилась бы). `cron:root_signals` (root, каждую минуту) сохраняет
они становятся текущими путем опроса их идемпотентных команд обновления для каждого двоичного файла на
расписание с ограниченным использованием штампов - каждая загрузка выполняется только при несоответствии версии, проверяется
контрольная сумма, запуск-тестирует новый двоичный файл, затем заменяет его атомарно (неработающая загрузка
контрольная сумма, запуск-тестирует новый двоичный файл, затем атомарно заменяет его (неработающая загрузка
никогда не заменяет рабочий). Выполняется на каждом узле (main **и** LB).
|Двоичный|Команда|Источник|Проверить|Опрос|
| --- | --- | --- | --- | --- |
|`xc_fanout` демон| `fanout_binary` |`XC_VM_Fanout` освободить актив| `SHA256SUMS` |~ежечасно|
|`xc_fanout` демон| `fanout_binary` |`XC_VM_Fanout` высвободить актив| `SHA256SUMS` |~ежечасно|
|`xcvm_core` расширение| `xcvm_core` |`XC_VM_Binaries` дерево репозиториев (`bin/xcvm_core/`)|`SHA256SUMS` + нагрузочный тест|~ежечасно|
| `yt-dlp` | `ytdlp` |вышестоящий `yt-dlp/yt-dlp` релиз|`SHA2-256SUMS` + `--version`|ежедневный|
@@ -321,7 +321,7 @@ su - xc_vm -c '/home/xc_vm/console.php tools bouquets'
## Обновления / миграции баз данных
Файловая система обновления базы данных (создание шага `.sql`, таблицы `migrations`, потока выполнения `db:migrate`) теперь доступна на отдельной странице см. [Обновления / миграции баз данных](database-migrations.md).
Файловая система обновления базы данных (создание шага `.sql`, таблицы `migrations`, потока выполнения `db:migrate`) теперь размещена на отдельной странице - см. [Обновления / миграции баз данных](database-migrations.md).
---
@@ -333,7 +333,7 @@ su - xc_vm -c '/home/xc_vm/console.php tools bouquets'
sudo /home/xc_vm/console.php status
```
Проверяет, запущен ли XC_VM, подключается к базе данных, выполняет ожидающие обновления шаги, исправляет разрешения и проверяет конфигурацию nginx. Требуется после установки или восстановления.
Проверяет, запущен ли параметр XC_VM, подключается к базе данных, выполняет ожидающие обновления шаги, исправляет разрешения и проверяет конфигурацию nginx. Требуется после установки или восстановления.
С аргументом `first-run` пропускает текущую проверку, используемую для начальной настройки:
@@ -373,7 +373,7 @@ sudo /home/xc_vm/console.php server:diagnose <server_id>
sudo /home/xc_vm/console.php server:diagnose
```
Обнаруживает **почему?** прокси—сервер/LB—узел, отображаемый в автономном режиме на панели: проверяет частоту сердечных сокращений, доступность (ICMP/TCP/HTTP `/api`), перекос часов, очередь сигналов и - локально на узле - выполняет ли узел брандмауэр на главном IP-адресе в своем собственном iptables, запущена ли служба `xc_vm`/nginx, запущен ли демон сердцебиения `watchdog` и находится ли `cron:servers` в crontab `xc_vm`. Доступно только для чтения; код выхода `0` = проблем не обнаружено, `2` = указаны вероятные причины. Более подробную информацию смотрите в [Руководстве по диагностике сервера](../administration/server-diagnostics.md).
Обнаруживает **почему?** прокси—сервер/LB—узел, отображаемый в автономном режиме на панели: проверяет частоту сердечных сокращений, доступность (ICMP/TCP/HTTP `/api`), смещение тактовых импульсов, очередь сигналов и - локально на узле - выполняет ли узел брандмауэр на главном IP-адресе в своем собственном iptables, запущена ли служба `xc_vm`/nginx, запущен ли демон сердцебиения `watchdog` и находится ли `cron:servers` в crontab `xc_vm`. Доступно только для чтения; код завершения `0` = проблем не обнаружено, `2` = указаны вероятные причины. Подробности см. в [Руководстве по диагностике сервера](../administration/server-diagnostics.md).
### SSL-сертификат
+2
View File
@@ -58,6 +58,8 @@ define('DEV_MODE', false); // master development-mode flag
| `recaptcha_enable` | `bool` |включите reCAPTCHA v2 при входе в систему|
| `verify_host` | `bool` |принудительная проверка списка разрешений хоста|
| `save_login_logs` | `bool` |постоянные попытки входа в систему в `login_logs`|
| `fanout_supervise` | `bool` |передача прямых трансляций супервизору xc_fanout вместо монитора PHP (по умолчанию включен)|
| `fanout_source_backend` |`auto` / `ffmpeg` / `native`|как преобразуются исходные тексты в MPEG-TS; под наблюдением, будут ли потоки, предназначенные только для копирования, запускать собственный ремиксер (`auto`: с резервным копированием ffmpeg)|
Эти значения загружаются из `CACHE_TMP_PATH/settings` защитниками запросов.
+31 -3
View File
@@ -36,8 +36,14 @@ ProcessManager::isStreamRunning(int $pid, int $streamId): bool
```
- `ffmpeg`: проверяет шаблон вывода для конкретного потока в командной строке
- `xc_fanout`: только собственный ремультиплексор (`xc_fanout remux … /<id>_.m3u8`) — демонический процесс
сам по себе использует исполняемый файл, но не называет список воспроизведения потока
- `php`: считается активным для контекста stream worker
Для запроса "есть ли что-нибудь **наблюдающий** в этом потоке" используйте `StreamProcess::isWatched($streamId, $monitorPid)`:
`monitor_pid` контролируемого потока принадлежит демону xc_fanout, который `isMonitorAlive()` (an
`XC_VM[<id>]` PHP процесс) справедливо отклоняется.
---
## Больше проверок и помощников
@@ -61,6 +67,28 @@ ProcessManager::isAnyProcessRunning(array $terms): bool
---
## Процессор и память для каждого потока
```php
ProcessManager::resourceSample($pid): ?array // ['ticks' => CPU ticks so far, 'rss' => bytes, 'at' => microtime]
ProcessManager::cpuPercent(array $now, array $prev): ?float // percent of ONE core between two samples
ProcessManager::producerKind($pid): ?string // 'fanout' (xc_fanout remux) | 'ffmpeg' | 'php'
```
Считывается непосредственно из `/proc/PID/stat` (поля 14/15 для CPU, 24 для RSS; размер страницы является производным
из собственного значения этого процесса `statm` против `status`, поскольку 64 КБ страниц являются нормальными для arm64). Процессор в `/proc`
is cumulative, so a percentage needs **two** samples: `cpuPercent()` returns `null` when the pair
ничего не говорит — ни о предыдущих показаниях, ни о двух показаниях за один и тот же момент, ни о счетчике, который сработал.
в обратном направлении, потому что производитель перезапустился в том же потоке.
`cron:streams` производит выборку каждого запущенного потока один раз за проход и сводит результат к этому
JSON-файл потока `progress_info` (`cpu`, `mem`, `producer`, плюс `cpu_t` / `cpu_at`, несущие
чтение следующего прохода вычитается из). Только узел, на котором запущен поток, может считывать свой собственный `/proc`, поэтому
выборка происходит там и перемещается на панель в строке, которую cron уже записывает; администратор
список потоков отображает его в виде столбца **Ресурсы** (значок производителя, процент процессора, оперативная память).
---
## Завершение процесса
```php
@@ -93,10 +121,10 @@ ProcessManager::acquireCronLock(string $pidFile, int $maxAge = 1800): bool
## `/proc` Проверить кэш
`isRunning()` использует короткий TTL-кэш для `/proc` проверок (1 секунда), чтобы уменьшить количество повторных операций ввода-вывода в узких циклах.
`isRunning()` использует короткий TTL-кэш для `/proc` проверок (1 секунда), чтобы уменьшить количество повторяющихся операций ввода-вывода в узких циклах.
> **Ловушка.** Поскольку результат кэшируется в течение ~1 секунды, процесс, который завершается (или запускается) внутри этого
> окно по—прежнему считывается в своем предыдущем состоянии - жесткий цикл может воздействовать на устаревшее "запущенное"/ "мертвое" окно.
> "окно" по—прежнему считывается в своем предыдущем состоянии - жесткий цикл может воздействовать на устаревшее "запущенное"/ "мертвое" окно.
> ответ. Вызовите `ProcessManager::clearCache()`, чтобы удалить кэш, когда вам понадобится новое чтение
> (например, сразу после удаления pid и перед его повторной проверкой).
@@ -122,7 +150,7 @@ ProcessManager::acquireCronLock(string $pidFile, int $maxAge = 1800): bool
- `Thread` (`src/Core/Process/Thread.php`) — тонкая оболочка `proc_open` вокруг одного
фоновая команда (запустите ее, опросите/дождитесь ее, прочитайте ее выходные данные).
- `Multithread` (`src/Core/Process/Multithread.php`) — выполняет несколько команд оболочки.
- `Multithread` (`src/Core/Process/Multithread.php`) — запускает несколько команд оболочки.
одновременно и собирает выходные данные каждого из них; используйте его для разветвленной работы (например, для проверки многих
исходники сразу), а не ручной цикл `proc_open`.
+1 -1
View File
@@ -30,7 +30,7 @@ define('DEV_MODE', false);
// ── Version & Git Configuration ────────────────────────────────
define('XC_VM_VERSION', '2.5.0');
define('XC_VM_VERSION', '2.5.1');
define('GIT_OWNER', 'Vateron-Media');
define('GIT_REPO_MAIN', 'XC_VM');