Files
XC_VM/ARCHITECTURE.md
T

81 KiB
Raw Blame History

XC_VM — Архитектурный план реорганизации /src

Содержание

  1. Диагноз текущего состояния
  2. Принципы целевой архитектуры
  3. Целевая структура /src
  4. Описание компонентов
  5. Карта миграции: откуда → куда
  6. Система модулей
  7. Границы ядра и модулей
  8. Варианты сборки: MAIN vs LoadBalancer
  9. Порядок миграции

1. Диагноз текущего состояния

Масштаб: 382 PHP-файла, ~199 000 строк

Критические проблемы

# Проблема Где проявляется Влияние
1 God-объекты CoreUtilities (4847 стр.), admin_api.php (6981 стр.), admin.php (4448 стр.) Невозможно изменить одну подсистему без риска сломать другую
2 Дублирование bootstrap www/constants.php vs www/stream/init.php — одни и те же ~70 define(), функции ошибок, flood-check Каждое изменение нужно делать в двух местах
3 Fork-дублирование CoreUtilities vs StreamingUtilities — идентичные свойства, init(), cleanGlobals() Баги исправляются в одном классе и остаются в другом
4 Глобальные переменные как шина данных global $db, $rSettings, $rServers, $rUserInfo в каждом файле Невозможно тестировать, невозможно изолировать
5 SQL в presentation-слое Каждая admin-страница делает $db->query() прямо в HTML Бизнес-логика неразделима от отображения
6 Один include = побочные эффекты require admin.php запускает сессию, создаёт БД, init 3 классов, определяет 50 констант Нет возможности подключить часть системы без всей
7 Admin = Reseller copy-paste reseller/ — упрощённый клон admin/ с тем же header/footer/session Правки в одном не попадают в другой
8 Goto-лейблы includes/cli/monitor.php содержит goto label235, label592 Следы обфускации, нечитаемый control flow
9 Inline data Массивы стран/MAC-типов/разрешений по 150+ строк прямо в admin.php Данные переплетены с логикой инициализации
10 God-cron crons/servers.php — мониторинг, перезапуск демонов, статистика, очистка Разные по частоте и природе задачи в одном файле

Граф зависимостей (текущий)

admin/*.php ──────┐
reseller/*.php ───┤
crons/*.php ──────┤──→ includes/admin.php ──→ CoreUtilities (4847)
includes/api/ ────┘         │                     ├── Database
                            │                     ├── Redis
                            ├──→ admin_api.php (6981)
                            ├──→ reseller_api.php (1204)
                            └──→ constants.php (~70 define())

www/stream/*.php ──→ www/stream/init.php ──→ StreamingUtilities (1992)
                          │                     ├── Database (тот же)
                          │                     └── Redis (тот же)
                          └── constants (ДУБЛИКАТ)

Центральная точка отказа: includes/admin.php — каждый контекст исполнения (admin, reseller, crons, API) проходит через этот один файл 4448 строк.


2. Принципы целевой архитектуры

2.1. Инверсия зависимостей

Код верхнего уровня (UI, CLI, HTTP endpoints) зависит от абстракций ядра, а не от конкретных реализаций. Ядро не знает о существовании модулей.

2.2. Единая точка bootstrap — множественные контексты

Вместо дублированных init.php / constants.php / stream/init.php — один bootstrap с конфигурируемым набором загружаемых сервисов.

2.3. Границы через интерфейсы, а не через global

Каждый сервис получает зависимости через конструктор или контейнер. Ни один компонент не использует global.

2.4. Модуль = изолированная директория

Модуль — это директория с известным контрактом. Его можно удалить, и система продолжит работать (деградируя в функциональности, но не падая).

2.5. Open-core без лицензионных ограничений в ядре

Ядро (core/) полностью свободно. Модули (modules/) могут быть как open-source, так и коммерческими. Ядро не содержит проверок лицензий, шифрования, или скрытых ограничений. Лицензирование — это задача отдельного опционального модуля расширений.


3. Целевая структура /src

src/
├── bootstrap.php                    # Единый bootstrap: require_once подключения, DI container, config
├── constants.php                    # Все path/version/status константы (один файл)
│
├── core/                            # ═══ ЯДРО (стабильный, свободный, минимальный) ═══
│   ├── Config/
│   │   ├── ConfigLoader.php         # .ini → массив, кэширование, env-override
│   │   └── PathResolver.php         # Все пути системы (заменяет 70 define())
│   │
│   ├── Database/
│   │   ├── Database.php              # Базовая PDO-обёртка (перемещён из includes/)
│   │   ├── DatabaseHandler.php      # Менеджер БД — расширенная обёртка с reconnect, bulk ops
│   │   ├── QueryBuilder.php         # Конструктор запросов вместо raw SQL в UI
│   │   └── Migration.php            # Миграции (извлечено из `status`)
│   │
│   ├── Cache/
│   │   ├── CacheInterface.php       # Контракт для любого кэш-драйвера
│   │   ├── FileCache.php            # Текущий igbinary file cache
│   │   └── RedisCache.php           # Redis-обёртка
│   │
│   ├── Auth/
│   │   ├── SessionManager.php       # Единый менеджер сессий (admin + reseller)
│   │   ├── Authenticator.php        # Логин/пароль/api_key
│   │   └── Authorization.php        # Проверка прав ($rPermissions → RBAC)
│   │
│   ├── Http/
│   │   ├── Request.php              # Обёртка над $_GET/$_POST (заменяет cleanGlobals)
│   │   ├── Response.php             # JSON/HTML ответ
│   │   ├── Router.php               # Маршрутизация вместо switch($rAction)
│   │   └── Middleware/
│   │       ├── FloodProtection.php  # Rate limiting (извлечено из constants.php)
│   │       ├── IpWhitelist.php      # IP-фильтрация
│   │       └── CorsMiddleware.php
│   │
│   ├── Process/
│   │   ├── ProcessManager.php       # Управление процессами (kill, ps, isRunning)
│   │   ├── DaemonRunner.php         # Запуск PHP-демонов с PID-файлами
│   │   └── CronLock.php             # Файловые блокировки кронов (checkCron)
│   │
│   ├── Logging/
│   │   ├── LoggerInterface.php       # Контракт
│   │   ├── FileLogger.php           # Файловое логирование
│   │   └── DatabaseLogger.php       # panel_logs / login_logs / activity
│   │
│   ├── Events/
│   │   ├── EventDispatcher.php      # Простой event bus
│   │   └── EventInterface.php       # Контракт события
│   │
│   ├── Container/
│   │   └── ServiceContainer.php     # Минимальный DI-контейнер
│   │
│   └── Util/
│       ├── GeoIP.php                # Извлечено из CoreUtilities
│       ├── NetworkUtils.php         # IP-операции, CIDR, subnet matching
│       ├── TimeUtils.php            # secondsToTime(), timezone helper
│       ├── Encryption.php           # AES, token generation
│       └── ImageUtils.php           # Resize, thumbnail, upload
│
├── domain/                          # ═══ БИЗНЕС-ЛОГИКА (сущности и сервисы) ═══
│   ├── Stream/
│   │   ├── StreamEntity.php         # Модель потока (поля, валидация)
│   │   ├── StreamRepository.php     # SQL-запросы для потоков (из admin_api.php)
│   │   ├── StreamService.php        # Бизнес-логика: create, update, reorder
│   │   ├── StreamMonitor.php        # Мониторинг потока (из cli/monitor.php)
│   │   ├── CategoryEntity.php
│   │   └── CategoryRepository.php
│   │
│   ├── Vod/
│   │   ├── MovieEntity.php
│   │   ├── MovieRepository.php
│   │   ├── MovieService.php
│   │   ├── SeriesEntity.php
│   │   ├── SeriesRepository.php
│   │   ├── SeriesService.php
│   │   ├── EpisodeEntity.php
│   │   └── EpisodeRepository.php
│   │
│   ├── Line/
│   │   ├── LineEntity.php           # Подписка/линия
│   │   ├── LineRepository.php
│   │   ├── LineService.php
│   │   ├── PackageEntity.php
│   │   └── PackageRepository.php
│   │
│   ├── Device/
│   │   ├── MagEntity.php
│   │   ├── MagRepository.php
│   │   ├── EnigmaEntity.php
│   │   └── EnigmaRepository.php
│   │
│   ├── User/
│   │   ├── UserEntity.php           # Админ/реselлер
│   │   ├── UserRepository.php
│   │   ├── GroupEntity.php
│   │   └── GroupRepository.php
│   │
│   ├── Server/
│   │   ├── ServerEntity.php
│   │   ├── ServerRepository.php
│   │   ├── ServerService.php        # Мониторинг, health-check
│   │   └── ServerStats.php
│   │
│   ├── Bouquet/
│   │   ├── BouquetEntity.php
│   │   ├── BouquetRepository.php
│   │   └── BouquetService.php       # Ordering, mapping
│   │
│   ├── Epg/
│   │   ├── EpgSource.php
│   │   ├── EpgRepository.php
│   │   └── EpgService.php
│   │
│   └── Ticket/
│       ├── TicketEntity.php
│       └── TicketRepository.php
│
├── streaming/                       # ═══ СТРИМИНГ-ДВИЖОК (hot path) ═══
│   ├── StreamingBootstrap.php       # Лёгкий init для стриминг-контекста
│   ├── Auth/
│   │   ├── TokenAuth.php            # HMAC/token парсинг (из auth.php)
│   │   ├── StreamAuth.php           # Проверка доступа к потоку
│   │   └── DeviceLock.php           # Привязка к устройству
│   │
│   ├── Delivery/
│   │   ├── LiveDelivery.php         # Раздача live (из live.php)
│   │   ├── VodDelivery.php          # Раздача VOD (из stream/vod.php)
│   │   ├── TimeshiftDelivery.php    # Timeshift
│   │   └── SegmentReader.php        # Чтение TS-сегментов
│   │
│   ├── Balancer/
│   │   ├── LoadBalancer.php         # Серверное распределение
│   │   └── RedirectStrategy.php
│   │
│   ├── Protection/
│   │   ├── RestreamDetector.php     # Антипиратская защита
│   │   ├── ConnectionLimiter.php    # Лимит подключений
│   │   └── GeoBlock.php            # Блокировка по стране/ISP/IP/UA
│   │
│   ├── Codec/
│   │   ├── FFmpegCommand.php        # Построение FFmpeg-команд (из CoreUtilities)
│   │   ├── TranscodeProfile.php     # Профили транскодирования
│   │   └── TsParser.php            # Парсер MPEG-TS (текущий ts.php)
│   │
│   └── Health/
│       ├── DivergenceDetector.php   # Мониторинг качества
│       └── BitrateTracker.php       # Отслеживание bitrate/FPS
│
├── interfaces/                      # ═══ ТОЧКИ ВХОДА (UI, API, CLI) ═══
│   ├── Http/
│   │   ├── public/                  # Web root (nginx document root)
│   │   │   ├── index.php            # Единая точка входа (front controller)
│   │   │   ├── stream.php           # Точка входа для стриминга
│   │   │   └── assets/              # CSS/JS/images/fonts
│   │   │       ├── admin/
│   │   │       └── player/
│   │   │
│   │   ├── Controllers/
│   │   │   ├── Admin/
│   │   │   │   ├── DashboardController.php
│   │   │   │   ├── StreamController.php
│   │   │   │   ├── LineController.php
│   │   │   │   ├── VodController.php
│   │   │   │   ├── ServerController.php
│   │   │   │   ├── SettingsController.php
│   │   │   │   ├── UserController.php
│   │   │   │   ├── BouquetController.php
│   │   │   │   ├── EpgController.php
│   │   │   │   └── ... (по одному на доменную область)
│   │   │   │
│   │   │   ├── Reseller/
│   │   │   │   ├── DashboardController.php
│   │   │   │   ├── LineController.php
│   │   │   │   └── ... (только разрешённые действия)
│   │   │   │
│   │   │   └── Api/
│   │   │       ├── AdminApiController.php
│   │   │       ├── ResellerApiController.php
│   │   │       ├── PlayerApiController.php   # Публичный player API
│   │   │       └── InternalApiController.php  # Межсерверный API (текущий www/api.php)
│   │   │
│   │   └── Views/
│   │       ├── layouts/
│   │       │   ├── admin.php        # Header + footer шаблон для admin
│   │       │   └── reseller.php     # Header + footer шаблон для reseller
│   │       │
│   │       ├── admin/
│   │       │   ├── dashboard.php
│   │       │   ├── streams/
│   │       │   │   ├── list.php
│   │       │   │   ├── edit.php
│   │       │   │   └── view.php
│   │       │   ├── lines/
│   │       │   ├── vod/
│   │       │   ├── servers/
│   │       │   └── settings/
│   │       │
│   │       ├── reseller/
│   │       │   ├── dashboard.php
│   │       │   └── ...
│   │       │
│   │       └── partials/
│   │           ├── modals.php
│   │           ├── topbar.php
│   │           └── table.php
│   │
│   ├── Cli/
│   │   ├── Commands/
│   │   │   ├── StartupCommand.php       # cli/startup.php
│   │   │   ├── WatchdogCommand.php      # cli/watchdog.php
│   │   │   ├── MonitorCommand.php       # cli/monitor.php
│   │   │   ├── CacheHandlerCommand.php  # cli/cache_handler.php
│   │   │   ├── QueueCommand.php         # cli/queue.php
│   │   │   ├── SignalsCommand.php       # cli/signals.php
│   │   │   ├── ScannerCommand.php       # cli/scanner.php
│   │   │   ├── MigrateCommand.php       # Из status
│   │   │   └── ToolsCommand.php         # Из tools (rescue, access, ports и т.д.)
│   │   └── CronJobs/
│   │       ├── StreamsCron.php
│   │       ├── ServersCron.php
│   │       ├── CacheCron.php
│   │       ├── EpgCron.php
│   │       ├── CleanupCron.php
│   │       ├── BackupsCron.php
│   │       ├── StatsCron.php
│   │       ├── LogsCron.php            # lines_logs + streams_logs
│   │       ├── VodCron.php
│   │       └── TmdbCron.php
│   │
│   └── Player/                         # Встроенный web-плеер
│       ├── PlayerController.php
│       └── views/
│           └── ... (текущий player/)
│
├── modules/                         # ═══ ОПЦИОНАЛЬНЫЕ МОДУЛИ ═══
│   ├── ministra/                    # Ministra/Stalker middleware (текущий ministra/)
│   │   ├── module.json              # Manifest: name, version, dependencies
│   │   ├── MinistraModule.php       # Точка входа модуля (implements ModuleInterface)
│   │   ├── PortalHandler.php        # Диспетчер type+action (15 обработчиков)
│   │   ├── PortalHelpers.php        # Хелперы портала (19 статических методов)
│   │   └── assets/
│   │
│   ├── plex/                        # Plex integration (текущий settings_plex, plex_add)
│   │   ├── module.json
│   │   ├── PlexModule.php
│   │   ├── PlexService.php
│   │   └── config/
│   │
│   ├── tmdb/                        # TMDB Integration
│   │   ├── module.json
│   │   ├── TmdbModule.php
│   │   ├── TmdbService.php
│   │   ├── TmdbCron.php
│   │   ├── TmdbPopularCron.php
│   │   └── lib.php                  # proxy → includes/libs/tmdb.php
│   │
│   ├── watch/                       # Watch/Recording (текущие watch, record файлы)
│   │   ├── module.json
│   │   ├── WatchModule.php
│   │   ├── WatchService.php
│   │   ├── RecordingService.php
│   │   ├── WatchController.php
│   │   ├── WatchCron.php
│   │   ├── WatchItem.php
│   │   └── views/
│   │       ├── watch.php
│   │       ├── watch_scripts.php
│   │       ├── watch_add.php
│   │       ├── watch_add_scripts.php
│   │       ├── settings_watch.php
│   │       ├── settings_watch_scripts.php
│   │       ├── watch_output.php
│   │       ├── watch_output_scripts.php
│   │       ├── record.php
│   │       └── record_scripts.php
│   │
│   ├── fingerprint/                 # Fingerprint watermarking
│   │   ├── module.json
│   │   └── FingerprintModule.php
│   │
│   ├── theft-detection/             # Anti-theft/restream detection
│   │   ├── module.json
│   │   └── TheftDetectionModule.php
│   │
│   └── magscan/                     # MAG device scanning
│       ├── module.json
│       └── MagscanModule.php
│
├── infrastructure/                  # ═══ СИСТЕМНАЯ ИНФРАСТРУКТУРА ═══
│   ├── nginx/
│   │   ├── NginxConfigGenerator.php # Генерация nginx.conf (из CoreUtilities)
│   │   ├── templates/
│   │   │   ├── main.conf.tpl
│   │   │   ├── rtmp.conf.tpl
│   │   │   └── vhost.conf.tpl
│   │   └── NginxReloader.php
│   │
│   ├── redis/
│   │   └── RedisManager.php         # Подключение, pipeline, pub/sub
│   │
│   ├── service/
│   │   ├── ServiceManager.sh        # Текущий файл `service` (bash)
│   │   └── daemons.sh               # Список демонов
│   │
│   ├── install/
│   │   ├── database.sql             # Начальная схема
│   │   └── proxy.tar.gz
│   │
│   └── bin/                         # Внешние бинарники (FFmpeg, certbot, yt-dlp и т.д.)
│       ├── ffmpeg_bin/
│       ├── certbot/
│       ├── maxmind/
│       ├── guess
│       ├── yt-dlp
│       └── network.py
│
├── data/                            # ═══ ДАННЫЕ ВРЕМЕНИ ВЫПОЛНЕНИЯ ═══
│   ├── cache/                       # Файловый кэш (igbinary)
│   ├── logs/                        # Логи приложения
│   ├── tmp/                         # Временные файлы (текущий tmp/)
│   ├── content/                     # Медиа-контент (текущий content/)
│   │   ├── archive/
│   │   ├── epg/
│   │   ├── playlists/
│   │   ├── streams/
│   │   ├── video/
│   │   └── vod/
│   ├── backups/                     # Резервные копии
│   └── signals/                     # Сигнальные файлы (.gitkeep)
│
├── config/                          # ═══ КОНФИГУРАЦИЯ ═══
│   ├── config.ini                   # Основной конфиг (DB, Redis, пути)
│   ├── modules.php                  # Список включённых модулей
│   ├── routes.php                   # Таблица маршрутов
│   ├── plex/
│   └── rclone.conf
│
└── resources/                       # ═══ РЕСУРСЫ ═══
    ├── langs/                       # Переводы (текущие .ini файлы)
    │   ├── en.ini
    │   ├── ru.ini
    │   ├── de.ini
    │   ├── es.ini
    │   ├── fr.ini
    │   ├── bg.ini
    │   └── pt.ini
    ├── data/
    │   ├── countries.php            # Массивы стран (извлечены из admin.php)
    │   ├── timezones.php
    │   ├── mac_types.php
    │   └── error_codes.php          # $rErrorCodes (извлечены из constants.php)
    └── libs/                        # Сторонние PHP-библиотеки
        ├── MobileDetect.php
        ├── XmlStringStreamer.php
        ├── m3u/
        └── Dropbox.php

4. Описание компонентов

4.1. core/ — Ядро системы

Ответственность: Инфраструктурные сервисы, которые нужны любому контексту исполнения. Не содержит бизнес-логики.

Подкаталог Что даёт Что заменяет
Config/ Загрузка конфигурации, резолв путей 70 define() из constants.php и stream/init.php
Database/ PDO-обёртка (Database + DatabaseHandler), query builder, миграции Database.php + SQL-запросы из status
Cache/ Унифицированный кэш с двумя драйверами Разбросанные igbinary_serialize + ad-hoc Redis
Auth/ Единая авторизация для admin и reseller session.php × 2, API::processLogin(), ResellerAPI::processLogin()
Http/ Абстракция запросов, роутинг, middleware cleanGlobals() × 2, switch($rAction), flood-check в constants.php
Process/ Управление PID, демонами, блокировками shell_exec('ps aux'), posix_kill(), checkCron() разбросанные по файлам
Logging/ Унифицированное логирование CoreUtilities::saveLog(), StreamingUtilities::clientLog(), Logger::init()
Events/ Event bus для связи без жёстких зависимостей Прямые вызовы между компонентами
Container/ DI-контейнер global $db, статические CoreUtilities::$rSettings
Util/ Утилиты без состояния Функции разбросанные по CoreUtilities, admin.php

Ключевое правило: core/ не знает о существовании domain/, streaming/, modules/, interfaces/. Зависимости направлены только внутрь ядра.

4.2. domain/ — Бизнес-логика

Ответственность: Сущности, репозитории, бизнес-сервисы. Каждый поддомен — отдельная директория.

Паттерн для каждого поддомена:

domain/Stream/
  ├── StreamEntity.php       # Данные сущности + валидация полей
  ├── StreamRepository.php   # SQL-запросы (SELECT/INSERT/UPDATE/DELETE)
  └── StreamService.php      # Бизнес-логика (create с проверками, mass-edit и т.д.)

Откуда берётся код:

  • admin_api.php (6981 строк) → разбивается на ~10 Repository + 10 Service файлов
  • reseller_api.php (1204 строк) → те же Repository, но ограниченные Service-методы
  • admin.php → процедурные getUserInfo(), getSeriesList(), updateSeries() → в соответствующие Repository

Зависимости: domain/ зависит от core/ (Database, Cache, Events). Не зависит от interfaces/ или modules/.

4.3. streaming/ — Стриминг-движок

Ответственность: Весь hot path доставки видео. Выделен отдельно от domain/ потому что:

  • Критичен к производительности (нельзя загружать всю бизнес-логику)
  • Имеет собственный лёгкий bootstrap
  • Работает на уровне байтов/сегментов, а не сущностей

Откуда берётся код:

  • StreamingUtilities.php (1992 стр.) → распределяется по подкаталогам
  • www/stream/auth.php (800 стр.) → Auth/TokenAuth.php + Auth/StreamAuth.php + Protection/
  • www/stream/live.php (708 стр.) → Delivery/LiveDelivery.php
  • includes/cli/monitor.php (565 стр.) → domain/Stream/StreamMonitor.php (с рефакторингом goto)
  • CoreUtilities методы FFmpeg → Codec/FFmpegCommand.php
  • ts.php → Codec/TsParser.php

4.4. interfaces/ — Точки входа

Ответственность: Получение запроса, вызов доменных сервисов, формирование ответа. Никакой бизнес-логики.

HTTP:

  • Один front controller public/index.php + Router
  • Контроллеры только маршрутизируют вызовы к domain/ сервисам
  • Шаблоны (Views/) — чистый HTML с минимумом PHP-вставок
  • Admin и Reseller — разные контроллеры, общие шаблоны

CLI:

  • Каждый демон/крон — отдельный Command-класс
  • Общая инициализация через bootstrap.php + ServiceContainer
  • Файл service (bash) → infrastructure/service/ServiceManager.sh

Откуда берётся код:

  • Каждый admin/*.php (100+ файлов) → Controller + View. Пример: admin/streams.php → Controllers/Admin/StreamController.php + Views/admin/streams/list.php
  • admin/header.php (675 стр.) + admin/footer.php (805 стр.) → Views/layouts/admin.php + выделение JS в файлы assets/
  • admin/post.php (1946 стр.) → обработчики форм распределяются по контроллерам
  • crons/*.php → Cli/CronJobs/, каждый крон — один файл
  • includes/cli/*.php → Cli/Commands/

4.5. modules/ — Опциональные модули

Ответственность: Дополнительные функции, которые не являются частью ядра. Каждый модуль — самодостаточная директория.

Контракт модуля:

interface ModuleInterface {
    public function getName(): string;
    public function getVersion(): string;
    public function boot(ServiceContainer $container): void;   // Регистрация сервисов
    public function registerRoutes(Router $router): void;      // Свои маршруты
    public function registerCrons(): array;                     // Свои кроны
    public function getEventSubscribers(): array;              // Подписки на события
}
// module.json
{
    "name": "ministra",
    "version": "1.0.0",
    "description": "Ministra/Stalker Portal middleware",
    "requires_core": ">=2.0",
    "dependencies": []
}

Текущий код → модули:

Модуль Источник Почему модуль, а не ядро
ministra/ src/ministra/ (2155+ строк, десятки JS-файлов) Сторонний портал, не всем нужен
plex/ settings_plex.php, plex_add.php, crons/plex.php, config/plex/ Интеграция с внешним сервисом
tmdb/ includes/libs/TMDb/, crons/tmdb.php, crons/tmdb_popular.php Внешний API для метаданных
watch/ watch.php, watch_add.php, watch_output.php, settings_watch.php, crons/watch.php Запись/DVR — расширенная функция
fingerprint/ admin/fingerprint.php Водяные знаки — enterprise-функция
theft-detection/ admin/theft_detection.php Антипиратство — enterprise-функция
magscan/ admin/magscan_settings.php Сканирование устройств

4.6. infrastructure/ — Системный слой

Ответственность: Взаимодействие с ОС: nginx, redis, bash-скрипты, внешние бинарники.

Откуда берётся код:

  • CoreUtilities → генерация nginx-конфигурации → nginx/NginxConfigGenerator.php
  • bin/nginx/, bin/php/, bin/redis/ → bin/ (бинарники как есть)
  • bin/daemons.sh → service/daemons.sh
  • service → service/ServiceManager.sh
  • bin/install/database.sql → install/database.sql

4.7. data/ — Runtime-данные

Ответственность: Всё, что генерируется при эксплуатации и не является кодом.

Заменяет текущие: tmp/, content/, backups/, signals/.

4.8. config/ — Конфигурация

Ответственность: Всё, что администратор может изменить без правки кода.

4.9. resources/ — Статические ресурсы и данные

Ответственность: Переводы, данные-справочники (страны, таймзоны), сторонние PHP-библиотеки.

Откуда берётся код:

  • includes/langs/*.ini → langs/
  • Inline-массивы стран из admin.php → data/countries.php
  • $rErrorCodes из constants.php → data/error_codes.php
  • includes/libs/* → libs/

5. Карта миграции: откуда → куда

5.1. God-объект CoreUtilities.php (4847 строк)

Метод/блок Целевой файл
init(), config loading core/Config/ConfigLoader.php
$db, getDatabase() core/Database/DatabaseHandler.php
getCache(), setCache() core/Cache/FileCache.php
Redis operations core/Cache/RedisCache.php, infrastructure/redis/RedisManager.php
cleanGlobals(), parseIncomingRecursively() core/Http/Request.php
startMonitor(), stopStream(), startMovie() domain/Stream/StreamService.php
isStreamRunning(), isMonitorRunning() core/Process/ProcessManager.php
FFmpeg command building streaming/Codec/FFmpegCommand.php
GeoIP lookup core/Util/GeoIP.php
Nginx config generation infrastructure/nginx/NginxConfigGenerator.php
Image resize/upload core/Util/ImageUtils.php
Encryption (AES/token) core/Util/Encryption.php
saveLog() core/Logging/FileLogger.php

5.2. God-объект admin_api.php (6981 строк)

Метод/блок Целевой файл
processStream() domain/Stream/StreamService.php
processMovie() domain/Vod/MovieService.php
processSerie() domain/Vod/SeriesService.php
processEpisode() domain/Vod/EpisodeService.php
processLine() domain/Line/LineService.php
processMAG() domain/Device/MagService.php
processEnigma() domain/Device/EnigmaService.php
processServer() domain/Server/ServerService.php
processBouquet() domain/Bouquet/BouquetService.php
processUser() domain/User/UserService.php
processGroup() domain/User/GroupService.php
processLogin() core/Auth/Authenticator.php
massEditStreams() domain/Stream/StreamService::massEdit()
checkMinimumRequirements() Валидация в каждом Entity

5.3. God-bootstrap admin.php (4448 строк)

Блок Целевой файл
session_start(), session config core/Auth/SessionManager.php
50+ define() статусов constants.php
Database creation core/Container/ServiceContainer.php
CoreUtilities::init() bootstrap.php
$rCountryCodes, $rCountries resources/data/countries.php
$rPermissions resources/data/permissions.php → core/Auth/Authorization.php
getUserInfo() domain/User/UserRepository.php
getSeriesList(), updateSeries() domain/Vod/SeriesRepository.php
secondsToTime() core/Util/TimeUtils.php
hasPermissions() core/Auth/Authorization.php
Mobile detect init core/Http/Middleware/ (если нужно)
Translator init bootstrap.php → ServiceContainer

5.4. Страницы admin/ (100+ файлов)

Паттерн трансформации:

БЫЛО:
  admin/streams.php (один файл = SQL + HTML + JS)

СТАЛО:
  interfaces/Http/Controllers/Admin/StreamController.php  — маршрутизация
  domain/Stream/StreamRepository.php                       — данные
  interfaces/Http/Views/admin/streams/list.php             — шаблон

5.5. Дублирование admin/ ↔ reseller/

БЫЛО:
  admin/header.php (675 строк)    +  reseller/header.php (284 строки)
  admin/footer.php (805 строк)    +  reseller/footer.php
  admin/session.php               +  reseller/session.php
  admin/functions.php             +  reseller/functions.php

СТАЛО:
  interfaces/Http/Views/layouts/admin.php      — единый layout
  interfaces/Http/Views/layouts/reseller.php   — наследует admin layout с ограничениями
  core/Auth/SessionManager.php                 — единый менеджер сессий
  core/Auth/Authorization.php                  — RBAC определяет, что видит пользователь

5.6. Стриминг-путь

БЫЛО:
  www/stream/init.php (дублированный bootstrap)
  www/stream/auth.php (800 строк: auth + block + token + balance)
  www/stream/live.php (708 строк: token + ondemand + delivery + heartbeat)
  StreamingUtilities.php (1992 строки: форк CoreUtilities)

СТАЛО:
  streaming/StreamingBootstrap.php   — лёгкий init без дублирования
  streaming/Auth/TokenAuth.php       — парсинг токенов
  streaming/Auth/StreamAuth.php      — проверка доступа
  streaming/Protection/GeoBlock.php  — блокировки (IP/ISP/UA/Country)
  streaming/Delivery/LiveDelivery.php — раздача контента
  streaming/Health/BitrateTracker.php — мониторинг качества
  core/Cache/*                       — общий кэш (не дублируется)
  core/Database/DatabaseHandler.php   — общая БД (не дублируется)

6. Система модулей

6.1. Жизненный цикл модуля

1. Модуль размещается в modules/{name}/
2. Добавляется в config/modules.php
3. При bootstrap: ServiceContainer сканирует modules.php
4. Для каждого модуля: require module.json → проверка зависимостей → boot()
5. Модуль регистрирует: сервисы, маршруты, кроны, event-подписки
6. Удаление: убрать из modules.php → (опционально) удалить папку

6.2. Правила изоляции

✅ Модуль МОЖЕТ:
   - Использовать любые сервисы из core/ через ServiceContainer
   - Использовать Repository/Service из domain/ (read-only или через интерфейсы)
   - Регистрировать свои маршруты, команды, кроны
   - Подписываться на события ядра
   - Иметь свои assets, views, конфиги

❌ Модуль НЕ МОЖЕТ:
   - Модифицировать файлы core/ или domain/
   - Напрямую обращаться к базе данных мимо Repository
   - Зависеть от другого модуля без явной декларации в module.json
   - Переопределять маршруты или сервисы ядра
   - Добавлять ограничения лицензирования в ядро

6.3. Расширяемость через события

// Ядро публикует события:
$dispatcher->dispatch(new StreamStartedEvent($streamId));
$dispatcher->dispatch(new LineCreatedEvent($lineId));
$dispatcher->dispatch(new UserLoginEvent($userId));

// Модуль подписывается:
class FingerprintModule implements ModuleInterface {
    public function getEventSubscribers(): array {
        return [
            StreamStartedEvent::class => [FingerprintApplier::class, 'onStreamStarted'],
        ];
    }
}

6.4. Коммерческие модули (будущее)

Коммерческие модули — обычные модули в modules/, но:

  • Доставляются отдельно (не в основном репозитории)
  • Могут содержать собственную проверку лицензии внутри себя
  • Ядро не содержит кода проверки лицензии — если модуль удалён, система работает
modules/
├── ministra/          ← open-source, в основном репо
├── plex/              ← open-source, в основном репо
├── enterprise-analytics/  ← коммерческий, отдельный репо
│   ├── module.json
│   ├── License.php        ← проверка лицензии ВНУТРИ модуля
│   └── AnalyticsModule.php
└── advanced-security/     ← коммерческий, отдельный репо

7. Границы ядра и модулей

7.1. Пакетная диаграмма зависимостей

                    ┌──────────────┐
                    │  interfaces/ │   ← HTTP, CLI, Player
                    └──────┬───────┘
                           │ depends on
              ┌────────────┼────────────┐
              ▼            ▼            ▼
        ┌──────────┐ ┌──────────┐ ┌──────────┐
        │ domain/  │ │streaming/│ │ modules/ │
        └────┬─────┘ └────┬─────┘ └────┬─────┘
             │            │            │
             │ depends on │ depends on │ depends on
             ▼            ▼            ▼
        ┌──────────────────────────────────┐
        │             core/                │   ← Config, DB, Cache, Auth, Process,
        │                                  │     Logging, Events, Container, Util
        └──────────────────────────────────┘
                       │
                       ▼
        ┌──────────────────────────────────┐
        │        infrastructure/           │   ← nginx, redis, bin, service
        └──────────────────────────────────┘

Стрелки всегда направлены вниз. Ни один нижний слой не знает о верхних.

7.2. Что входит в ядро, а что нет

В ядро (core/ + domain/) В модули (modules/)
Управление потоками (CRUD, запуск, остановка) Ministra portal
Управление подписками (линии, пакеты) Plex integration
Управление VOD (фильмы, сериалы) TMDb metadata fetching
Авторизация и RBAC Fingerprint watermarking
Серверная инфраструктура Theft detection
EPG (базовый импорт) MAG device scanning
Bouquet management Watch/DVR recording
Стриминг-движок Advanced analytics (будущее)
API (admin, reseller, player) White-label theming (будущее)

8. Варианты сборки: MAIN vs LoadBalancer

8.1. Два артефакта из одной кодовой базы

Система собирается в два варианта из одного src/:

Артефакт Назначение Что включает Что исключает
MAIN Основной сервер (admin + streaming) Всё содержимое src/ Ничего
LoadBalancer (LB) Стриминг-сервер без управления Только стриминг + инфраструктура Админ-панель, реселлер, player, ministra, admin-only модули

Ключевой принцип: LB — это подмножество MAIN. Код не форкается, а фильтруется при сборке.

8.2. Текущая проблема (до миграции Makefile)

Makefile собирает LB из фиксированного списка директорий (LB_FILES):

# ТЕКУЩИЙ (устаревший) список:
LB_FILES := bin config content crons includes signals tmp www status update service

Эти новые директории НЕ входят в LB_FILES и НЕ копируются в LB:

Директория / файл Нужен LB? Статус
autoload.php ✅ ДА — без него новые классы не загружаются ⚠ Отсутствует в LB
bootstrap.php ✅ ДА — единая точка инициализации (CONTEXT_STREAM) ⚠ Отсутствует в LB
core/ ✅ ДА — Database, Cache, Auth, Config, Process, Http, Logging, Container, Util ⚠ Отсутствует в LB
domain/ ⚠ ЧАСТИЧНО — Stream/, Server/, Bouquet/ нужны; User/, Ticket/, Device/ — нет ⚠ Отсутствует в LB
streaming/ ✅ ДА — весь стриминг-движок ⚠ Отсутствует в LB
infrastructure/ ✅ ДА — redis/, nginx/ ⚠ Отсутствует в LB
resources/ ⚠ ЧАСТИЧНО — data/error_codes.php нужен; langs/ — нет ⚠ Отсутствует в LB
data/ ⚠ ЧАСТИЧНО — runtime-данные создаются динамически ⚠ Отсутствует в LB
interfaces/ ⚠ ЧАСТИЧНО — Cli/ частично нужен ⚠ Отсутствует в LB
modules/ ❌ НЕТ — все текущие модули admin-only ⚠ Отсутствует в LB
admin/ ❌ НЕТ ✅ Корректно отсутствует
ministra/ ❌ НЕТ ✅ Корректно отсутствует
player/ ❌ НЕТ ✅ Корректно отсутствует
reseller/ ❌ НЕТ ✅ Корректно отсутствует

Последствие: Proxy-методы в CoreUtilities.php (который IS копируется в LB через includes/) вызывают классы из core/ и domain/, но эти директории отсутствуют → LB-сборка ломается при вызове мигрированного кода.

8.3. Целевая конфигурация Makefile

Обновлённый LB_FILES

# ЦЕЛЕВОЙ (обновлённый) список:
LB_FILES := autoload.php bootstrap.php \
    bin config content core crons data domain includes infrastructure \
    interfaces resources signals streaming tmp www status update service

Обновлённый LB_DIRS_TO_REMOVE

LB_DIRS_TO_REMOVE := \
    # Существующие исключения:
    bin/install \
    bin/redis \
    includes/langs \
    includes/api \
    includes/libs/resources \
    bin/nginx/conf/codes \
    # Новые исключения для целевой архитектуры:
    admin \
    ministra \
    player \
    reseller \
    domain/User \
    domain/Ticket \
    domain/Device \
    interfaces/Http/Controllers/Admin \
    interfaces/Http/Controllers/Reseller \
    interfaces/Http/Views \
    interfaces/Player \
    modules/fingerprint \
    modules/magscan \
    modules/ministra \
    modules/plex \
    modules/theft-detection \
    modules/tmdb \
    modules/watch \
    resources/langs

Обновлённый LB_FILES_TO_REMOVE

LB_FILES_TO_REMOVE := \
    # Существующие (пока admin.php/admin_api.php живут в includes/):
    includes/admin_api.php \
    includes/admin.php \
    includes/reseller_api.php \
    # ... остальные существующие исключения ...
    # Новые:
    includes/cli/migrate.php \
    includes/cli/cache_handler.php \
    includes/cli/balancer.php \
    crons/backups.php \
    crons/cache_engine.php \
    crons/epg.php \
    crons/update.php \
    crons/providers.php \
    crons/root_mysql.php \
    crons/series.php \
    crons/tmdb.php \
    crons/tmdb_popular.php

8.4. Что LB использует — карта зависимостей

www/stream/*.php ──→ bootstrap.php (CONTEXT_STREAM)
                         │
                         ├──→ autoload.php (class map)
                         ├──→ core/Config/         (пути, конфигурация)
                         ├──→ core/Database/       (PDO-обёртка)
                         ├──→ core/Cache/          (Redis + File кэш)
                         ├──→ core/Auth/           (BruteforceGuard)
                         ├──→ core/Http/           (Request, RequestGuard)
                         ├──→ core/Process/        (ProcessManager)
                         ├──→ core/Logging/        (FileLogger, DatabaseLogger)
                         ├──→ core/Util/           (GeoIP, NetworkUtils, Encryption)
                         ├──→ core/Error/          (ErrorHandler, ErrorCodes)
                         │
                         ├──→ streaming/Auth/      (TokenAuth, StreamAuth, DeviceLock)
                         ├──→ streaming/Delivery/  (LiveDelivery, VodDelivery, SegmentReader)
                         ├──→ streaming/Balancer/  (LoadBalancer, RedirectStrategy)
                         ├──→ streaming/Protection/(RestreamDetector, ConnectionLimiter, GeoBlock)
                         ├──→ streaming/Codec/     (FFmpegCommand, TsParser)
                         │
                         ├──→ domain/Stream/       (StreamProcess, ConnectionTracker, StreamSorter)
                         ├──→ domain/Server/       (ServerRepository)
                         ├──→ domain/Bouquet/      (BouquetMapper — для плейлистов)
                         ├──→ domain/Vod/          (для VOD-доставки)
                         │
                         ├──→ infrastructure/redis/(RedisManager)
                         └──→ resources/data/      (error_codes.php)

crons/*.php (на LB) ──→ bootstrap.php (CONTEXT_CLI)
                         └──→ те же зависимости + domain/Stream/*

8.5. Правила для разработки с учётом LB

  1. Proxy-методы в CoreUtilities/StreamingUtilities должны быть безопасны для LB. Пока autoload.php и core//domain/ не добавлены в LB-сборку, proxy-вызовы сломают LB.

  2. Makefile должен обновляться синхронно с миграцией, конкретно при добавлении новых LB_FILES каждый раз, когда код из includes/ мигрирует в новые директории.

  3. Тестирование LB-сборки — после каждой фазы миграции нужно проверять:

    make new && make lb
    # Убедиться, что все нужные файлы присутствуют
    # Убедиться, что admin-only файлы отсутствуют
    
  4. domain/ частично нужен LB — нельзя целиком исключать domain/. Исключаются только admin-specific поддомены (User/, Ticket/, Device/).

  5. modules/ полностью исключается из LB — все текущие модули (ministra, plex, tmdb, watch, fingerprint, theft-detection, magscan) — это admin-функциональность. В будущем, если появится LB-specific модуль, его нужно будет явно добавить.

8.6. Переходный период (сейчас)

Пока миграция идёт итеративно (фазы 1-3 в процессе), Makefile нужно обновить немедленно:

Минимально необходимое изменение (LB_FILES):

LB_FILES := bin config content core crons domain includes \
    infrastructure resources signals streaming tmp www status update service

Плюс два root-файла — autoload.php и bootstrap.php — нужно копировать отдельно, т.к. LB_FILES работает только с директориями:

lb_copy_files:
    # ... существующий код ...
    @echo "==> [LB] Copying root files"
    @for root_file in autoload.php bootstrap.php; do \
        if [ -f "$(MAIN_DIR)/$$root_file" ]; then \
            cp "$(MAIN_DIR)/$$root_file" "$(TEMP_DIR)/$$root_file"; \
        fi; \
    done

9. Порядок миграции

Принцип: извлечение → делегирование → замена

Каждый шаг миграции следует одному паттерну:

1. Создать новый класс в целевой директории
2. Перенести в него методы из god-объекта
3. В старом файле оставить proxy-метод:
     public static function oldMethod(...$args) {
         return NewClass::method(...$args);
     }
4. Зарегистрировать класс в autoloader
5. Проверить: система работает как раньше
6. (позже) Обновить вызывающий код → удалить proxy

Так каждый шаг безопасен и обратимо совместим.


Фаза 0: Подготовка ✅

  1. ✅ Автозагрузчик src/autoload.php — карта классов + fallback spl_autoload
  2. ✅ Скелет директорий (98 каталогов)
  3. ✅ bootstrap.php — XC_Bootstrap с 4 контекстами
  4. ✅ core/Container/ServiceContainer.php — DI-контейнер
  5. ✅ Разбиение www/constants.php → 7 core-файлов + тонкий фасад (74 строки)
    • ✅ core/Config/Paths.php, AppConfig.php, Binaries.php, ConfigLoader.php
    • ✅ core/Error/ErrorCodes.php, ErrorHandler.php
    • ✅ core/Http/RequestGuard.php
    • ✅ www/stream/init.php → подключён autoload.php

Фаза 1: Извлечение core/ (базовые компоненты)

1.1 ✅ Database

  • ✅ core/Database/DatabaseHandler.php (530 стр.) ← includes/Database.php
  • ✅ core/Database/Database.php (299 стр.) — перемещён из includes/
  • ✅ Все 20 файлов переключены на DatabaseHandler

1.2 ✅ Cache

  • ✅ core/Cache/CacheInterface.php (84 стр.)
  • ✅ core/Cache/FileCache.php (229 стр.) ← CoreUtilities::getCache/setCache
  • ✅ core/Cache/RedisCache.php (262 стр.)

1.3 ✅ Http / Request

  • ✅ core/Http/Request.php (449 стр.) ← cleanGlobals() + parseIncomingRecursively()
  • ✅ core/Http/Response.php (139 стр.)

1.4 ✅ Auth

  • ✅ core/Auth/SessionManager.php (305 стр.) ← из двух session.php

1.5 ✅ Process

  • ✅ core/Process/ProcessManager.php (366 стр.) ← shell_exec/posix_kill

1.6 ✅ Util

  • ✅ core/Util/GeoIP.php (159 стр.) ← CoreUtilities
  • ✅ core/Util/Encryption.php (137 стр.) ← CoreUtilities
  • ✅ core/Util/TimeUtils.php (114 стр.) ← CoreUtilities + admin.php::secondsToTime()
  • ✅ core/Util/NetworkUtils.php (129 стр.) ← IP/CIDR/subnet из CoreUtilities

Фаза 1.7: Оставшиеся извлечения core/

Из CoreUtilities.php (4847 строк) → новые классы:

Шаг 1.7.1 — Логирование ✅

  • ✅ Извлечь saveLog() (стр. 489–504) → FileLogger::log()
  • ✅ Извлечь clientLog() (StUtil стр. 1169–1177) → DatabaseLogger::log()
  • ✅ Написать LoggerInterface с методом log($type, $message, $extra)
  • ✅ Proxy: CoreUtilities::saveLog() → FileLogger::log()
  • ✅ Proxy: StreamingUtilities::clientLog() → DatabaseLogger::log()

Шаг 1.7.2 — Системная информация ✅

  • ✅ Извлечь 9 методов (стр. 534–671, 827–852, 1338–1344, 4621–4665) → SystemInfo
  • ✅ Proxy: каждый вызов CoreUtilities::getStats() → SystemInfo::getStats()

Шаг 1.7.3 — Защита от брутфорса (Flood/Bruteforce) ✅

  • ✅ Извлечь 4 метода из CoreUtilities (стр. 709–826) → BruteforceGuard
  • ✅ 4 дублированных метода в StreamingUtilities (стр. 215–394) → proxy на тот же BruteforceGuard
  • ✅ Первая дедупликация CoreUtilities ↔ StreamingUtilities

Шаг 1.7.4 — HTTP-клиент (cURL) ✅

  • ✅ Извлечь 3 метода (стр. 373–428, 1408–1442, 3568–3578) → CurlClient

Шаг 1.7.5 — Событийная система ✅

  • ✅ Написать простой EventDispatcher (publish/subscribe)
  • ✅ Пока без подписчиков — подготовка к модульной системе

Шаг 1.7.6 — RBAC / Авторизация ✅

  • ✅ Извлечь hasPermissions() (стр. 582–619) и hasResellerPermissions() (стр. 575–581)
  • ✅ Массив $rAdvPermissions → resources/data/permissions.php
  • ✅ Proxy: глобальные функции в admin.php → Authorization::check()

Шаг 1.7.7 — Аутентификация ✅

  • ✅ Извлечь processLogin() из admin_api.php (стр. 1399–1478) → Authenticator::login()
  • ✅ Извлечь processLogin() из reseller_api.php → Authenticator::resellerLogin()
  • ✅ Proxy: API::processLogin() → Authenticator::login()

Шаг 1.7.8 — Утилиты изображений ✅

  • ✅ Извлечь методы работы с изображениями (resize, thumbnail, URL-валидация)
  • ✅ StreamingUtilities::validateImage() (стр. 1355) → ImageUtils::validateURL()
  • ✅ admin.php::getAdminImage() (стр. 871–883) → ImageUtils::resize()

Фаза 2: Дедупликация CoreUtilities ↔ StreamingUtilities ✅

Форк устранён. 53 дублированных метода дедуплицированы.

Шаг 2.1 — Инвентаризация дубликатов ✅

Инвентаризация выполнена: 53 общих метода между CoreUtilities и StreamingUtilities. Все методы распределены по шагам 2.2–2.5 и успешно дедуплицированы.

Шаг 2.2 — Redis и сигналы ✅

  • ✅ Извлечь Redis-подключение в RedisManager (единый для обоих)
  • ✅ Proxy: оба класса вызывают RedisManager::connect()
  • ✅ getDomainName() → DomainResolver::resolve() (чистая утилита конфигурации)

Шаг 2.3 — Трекинг подключений (Redis) ✅

  • ✅ ~17 методов вынесены в ConnectionTracker (работа с Redis-ключами подключений)
  • ✅ Proxy: оба god-объекта делегируют в ConnectionTracker

Шаг 2.4 — Справочные данные и сортировки ✅

  • ✅ Сортировки и форматирование вынесены в StreamSorter
  • ✅ Данные-справочники вынесены в BouquetMapper / CategoryRepository / BouquetRepository / ServerRepository / SettingsRepository

Шаг 2.5 — Дедупликация init() ✅

  • ✅ Оба init() стали тонкими обёртками
  • ✅ Общая логика вынесена в core/Init/LegacyInitializer.php
  • ✅ Состояние init синхронизируется через ServiceContainer

Фаза 3: Извлечение domain/ — бизнес-логика ✅

Все entity/repository/service извлечены из god-объектов. Proxy-методы оставлены в исходных файлах.

Шаг 3.1 — domain/Stream/ ✅

  • StreamService.php — processStream, massEdit, massDelete, move, replaceDNS ← admin_api.php
  • ChannelService.php — processChannel, massEdit, setOrder ← admin_api.php
  • CategoryService.php — processCategory, orderCategories ← admin_api.php
  • StreamRepository.php — getStream, getStreamStats, getStreamErrors, getStreamPIDs, getStreamOptions, getStreamSys, getNextOrder ← admin.php
  • CategoryRepository.php — getCategories ← admin.php
  • M3UParser.php — parseM3U ← admin.php
  • StreamProcess.php — startMonitor, stopStream, startProxy, startThumbnail, queueChannel, createChannel, updateStream(s), createChannelItem, startMovie, stopMovie, startLoopback, queueMovie(s), refreshMovies, startStream, startLLOD ← CoreUtilities

Шаг 3.2 — domain/Vod/ ✅

  • MovieService.php — process, massEdit, massDelete, import ← admin_api.php
  • SeriesService.php — process, massEdit, massDelete, import ← admin_api.php
  • EpisodeService.php — process, massEdit, massDelete ← admin_api.php
  • SeriesRepository.php — getList, updateFromTMDB, queueRefresh, getSimilar, generatePlaylist ← admin.php
  • MovieRepository.php — getSimilar, deleteFile ← admin.php

Шаг 3.3 — domain/Line/ ✅

  • LineService.php — process, massEdit, massDelete, delete, update (одиночные и массовые) ← admin_api.php + CoreUtilities
  • LineRepository.php — deleteMany ← admin.php

Шаг 3.4 — domain/User/ ✅

  • UserService.php — process, massEdit, massDelete ← admin_api.php
  • GroupService.php — process ← admin_api.php
  • ProfileService.php — editAdminProfile ← admin_api.php
  • UserRepository.php — getUserInfo, getUser, getRegisteredUser(s), getResellers, getDirectReports, getSubUsers, getParent, getStreamingUserInfo ← admin.php + StreamingUtilities
  • GroupRepository.php — getAll, getById, deleteById ← admin.php

Шаг 3.5 — domain/Device/ ✅

  • MagService.php — process, massEdit, massDelete ← admin_api.php
  • EnigmaService.php — process, massEdit, massDelete ← admin_api.php
  • DeviceSync.php — syncLineDevices ← admin.php

Шаг 3.6 — domain/Server/ ✅

  • ServerService.php — process, processProxy, install, reorder ← admin_api.php
  • ServerRepository.php — getAllSimple, getStreamingSimple, getProxySimple, getFreeSpace, getStreamsRamdisk, killPID, getRTMPStats, deleteById, probeSource, getSSLLog, checkSource, freeTemp, freeStreams ← admin.php

Шаг 3.7 — domain/Bouquet/ ✅

  • BouquetService.php — process, reorder, sort, scan, scanOne ← admin_api.php + admin.php
  • BouquetRepository.php — getAllSimple, getOrder, getUserBouquets ← admin.php

Шаг 3.8 — domain/Epg/ ✅

  • EpgService.php — process, getChannelEpg ← admin_api.php + admin.php
  • EpgRepository.php — getById, findByName, getStreamEpg, getStreamsEpg, getProgramme, search ← admin.php + CoreUtilities

Шаг 3.9 — domain/Settings/ + domain/Ticket/ ✅

  • SettingsService.php — edit, editBackup, editCacheCron ← admin_api.php
  • TicketService.php — submit ← admin_api.php

Шаг 3.10 — domain/Security/ ✅

  • BlocklistService.php — processISP, processUA, blockIP, processRTMPIP, checkBlockedUAs, checkISP, checkServer ← admin_api.php + StreamingUtilities
  • BlocklistRepository.php — getBlockedIPsSimple, getRTMPIPsSimple, getBlockedUA, getBlockedIPs, getBlockedISP, getBlockedServers, getProxyIPs ← admin.php + CoreUtilities

Шаг 3.11 — domain/Auth/ ✅

  • CodeService.php — process ← admin_api.php
  • HMACService.php — process ← admin_api.php
  • PackageService.php — process ← admin_api.php (в domain/Line/)
  • CodeRepository.php — getActiveCodes, updateCodes, getCurrentCode ← admin.php
  • HMACRepository.php — getAll, getById ← admin.php
  • PackageRepository.php — deleteById ← admin.php (в domain/Line/)
  • HMACValidator.php — validate ← StreamingUtilities

Шаг 3.12 — Playlist-генератор ✅

  • PlaylistGenerator.php — generate ← CoreUtilities (самый длинный метод, live/vod/series/radio)
  • CronGenerator.php — generate ← CoreUtilities

Фаза 4: Извлечение streaming/ (hot path) ✅

Шаг 4.1 — streaming/Auth/ ✅

  • StreamAuth.php — checkAccess, validateConnections ← auth.php + StreamingUtilities
  • TokenAuth.php — парсинг токенов
  • DeviceLock.php — привязка к устройству
  • ConnectionLimiter.php — closeConnections, closeRTMP → Protection/

Шаг 4.2 — streaming/Delivery/ ✅

  • LiveDelivery.php ← www/stream/live.php
  • StreamRedirector.php — redirectStream, showVideoServer
  • OffAirHandler.php — getOffAirVideo
  • HLSGenerator.php — generateHLS
  • SegmentReader.php — getLLODSegments
  • SignalSender.php — sendSignal
  • ProxySelector.php → Balancer/

Шаг 4.3 — streaming/Codec/ ✅

  • FFprobeRunner.php — probeStream, parseFFProbe
  • FFmpegCommand.php — сборка FFmpeg-команд
  • SubtitleExtractor.php — extractSubtitle

Шаг 4.4 — streaming/Protection/ + Health/ ✅

  • ConnectionLimiter.php — closeConnections
  • HealthChecker.php — isRunning
  • ProcessChecker.php — isPIDRunning, isPIDsRunning, checkPID
  • WatchdogMonitor.php — getWatchdog

Шаг 4.5 — streaming/StreamingBootstrap.php ✅

  • Лёгкий bootstrap заменяет www/stream/init.php
  • Загружает: autoload → constants → Database → Redis

Фаза 5: Вынесение модулей

Каждый модуль извлекается атомарно — система продолжает работать без него.

Шаг 5.1 — modules/plex/ ⚡ (в процессе)

Завершено:

  • ✅ PlexAuth.php — аутентификация (getPlexToken, checkPlexToken, cachePlexToken и др.)
  • ✅ PlexRepository.php — данные (getPlexServers, getPlexSections)
  • ✅ PlexService.php — бизнес-логика (editPlexSettings, processPlexSync, forcePlex)
  • ✅ PlexCron.php — крон синхронизации (Thread, Multithread, PlexCron::run())
  • ✅ PlexItem.php — CLI обработка элементов (PlexItem::run())
  • ✅ crons/plex.php — тонкая обёртка → PlexCron::run()
  • ✅ includes/cli/plex_item.php — тонкая обёртка → PlexItem::run()
  • ✅ Все 5 классов зарегистрированы в autoload.php
  • ✅ admin/settings_plex.php → modules/plex/views/ (контроллер + вынесенный view/scripts)
  • ✅ admin/plex_add.php → modules/plex/views/ (контроллер + общие view/scripts)
  • ✅ admin/plex.php → modules/plex/views/ (контроллер + список вынесен в view)
  • ✅ config/plex/ → modules/plex/config/

Осталось: —

Шаг 5.2 — modules/watch/

  • ✅ API::editWatchSettings() → modules/watch/WatchService.php
  • ✅ API::processWatchFolder() → modules/watch/WatchService.php
  • ✅ API::scheduleRecording() → modules/watch/RecordingService.php
  • ✅ admin.php::getWatchFolders() → modules/watch/WatchController.php
  • ✅ admin.php::getWatchCategories() → modules/watch/WatchController.php
  • ✅ admin.php::forceWatch() → modules/watch/WatchController.php
  • ✅ admin.php::getRecordings() → modules/watch/WatchController.php
  • ✅ admin.php::deleteRecording() → modules/watch/WatchController.php
  • ✅ admin/settings_watch.php → modules/watch/views/ (thin wrapper + view/scripts)
  • ✅ admin/watch.php → modules/watch/views/ (thin wrapper + view/scripts)
  • ✅ admin/watch_add.php → modules/watch/views/ (thin wrapper + view/scripts)
  • ✅ admin/watch_output.php → modules/watch/views/ (thin wrapper + view/scripts)
  • ✅ admin/record.php → modules/watch/views/ (thin wrapper + view/scripts)
  • ✅ crons/watch.php → modules/watch/WatchCron.php (entry point + extracted class)
  • ✅ includes/cli/watch_item.php → modules/watch/WatchItem.php (entry point + extracted class)
  • ✅ WatchModule::registerCrons() wired to WatchCron

Осталось: —

Шаг 5.3 — modules/tmdb/

  • ✅ admin/api.php::tmdb_search → modules/tmdb/TmdbService.php (search)
  • ✅ admin/api.php::tmdb → modules/tmdb/TmdbService.php (getDetails)
  • ✅ crons/tmdb.php → modules/tmdb/TmdbCron.php (entry point + extracted class)
  • ✅ crons/tmdb_popular.php → modules/tmdb/TmdbPopularCron.php (entry point + extracted class)
  • ✅ TmdbModule.php — registerCrons() wired (TmdbCron + TmdbPopularCron)
  • ✅ includes/libs/TMDb/ → modules/tmdb/lib.php (proxy loader, lib stays in place)

Осталось: —

Шаг 5.4 — modules/ministra/

  • ✅ ministra/portal.php (2156 строк) → PortalHandler.php (15 статических обработчиков, ~1345 строк)
  • ✅ ministra/portal.php helper functions → PortalHelpers.php (19 статических методов, ~860 строк)
  • ✅ MinistraModule.php — точка входа модуля (standalone endpoint, без cron/routes)
  • ✅ ministra/portal.php → тонкая обёртка: init/auth → PortalHandler (269 строк + хелперы + комментированный оригинал)
  • 🔲 ministra/*.js → modules/ministra/assets/ (JS-файлы портала — отложено)

Осталось: JS-ассеты (отложено до Фазы 6)

Шаг 5.5 — modules/fingerprint/ + modules/theft-detection/ + modules/magscan/

  • ✅ FingerprintModule.php — модуль Fingerprint Stream (выбор потока + наложение текста + таблица активности)
  • ✅ TheftDetectionModule.php — модуль обнаружения кражи VOD (таблица просмотров, данные из cache_engine)
  • ✅ MagscanModule.php — модуль настроек MAGSCAN (белые/чёрные списки MAC + IP)
  • ✅ module.json × 3 — метаданные модулей
  • ✅ config/modules.php — все 3 модуля раскомментированы и включены

Источники:

admin/fingerprint.php (330 стр.) — UI-страница, API: fingerprint + line_activity
admin/theft_detection.php (239 стр.) — UI-страница, данные: CACHE_TMP_PATH/theft_detection
admin/magscan_settings.php (301 стр.) — UI-страница, POST: submit_magscan

Шаг 5.6 — ModuleInterface + загрузчик модулей

  • ✅ core/Module/ModuleInterface.php — контракт модуля (111 строк): getName, getVersion, boot, registerRoutes, registerCrons, getEventSubscribers
  • ✅ core/Module/ModuleLoader.php — загрузчик модулей (243 строки): loadAll, load, checkDependencies, isLoaded, getModule
  • ✅ config/modules.php — конфигурация модулей: plex, watch, fingerprint, theft-detection, magscan (enabled), tmdb, ministra (commented)

Аудит Фазы 5 ✅

Проведена полная проверка всех файлов Фазы 5. Найдено и исправлено:

  • КРИТИЧЕСКОЕ: Thread/Multithread дублировались в 3 файлах (PlexCron, WatchCron, cache_engine) → вынесены в core/Process/Thread.php + core/Process/Multithread.php, все 3 файла переведены на require_once
  • autoload.php: добавлены 14 отсутствующих записей (WatchCron, WatchItem, Tmdb*, Ministra*, Fingerprint*, TheftDetection*, Magscan*, Thread, Multithread)
  • module.json: созданы для tmdb и ministra (отсутствовали)
  • config/modules.php: tmdb и ministra раскомментированы и включены (были enabled => false)

Фаза 6: Контроллеры и Views (admin/reseller)

Выполняется ПОСЛЕ извлечения domain/ — контроллеры вызывают сервисы.

Шаг 6.1 — Единый layout

admin/header.php (675 стр.) + reseller/header.php (284 стр.)
                            → interfaces/Http/Views/layouts/admin.php

admin/footer.php (804 стр.) + reseller/footer.php (719 стр.)
                            → interfaces/Http/Views/layouts/footer.php
                            + assets/admin/js/*.js (вынесенный inline JS)

Шаг 6.2 — Router + Front Controller

Новый → core/Http/Router.php
Новый → interfaces/Http/public/index.php (front controller)

Шаг 6.3 — Конвертация admin-страниц (группами по 5–10)

Группа A (потоки):    admin/streams.php, stream.php, stream_view.php, created_channel.php, created_channels.php
Группа B (VOD):       admin/movies.php, movie.php, series.php, serie.php, episodes.php, episode.php
Группа C (линии):     admin/lines.php, line.php, mags.php, mag.php, enigmas.php, enigma.php
Группа D (серверы):   admin/servers.php, server.php, server_view.php, server_install.php
Группа E (букеты):    admin/bouquets.php, bouquet.php, bouquet_order.php, bouquet_sort.php
Группа F (настройки): admin/settings.php, database.php, profile.php, edit_profile.php
Группа G (остальное): admin/dashboard.php, epgs.php, epg.php, groups.php, group.php ...

Каждая группа: SQL → Repository (уже есть), логика → Controller, HTML → View.

Шаг 6.4 — Объединение admin/reseller

reseller/table.php (1836 стр.) → переиспользует admin-контроллеры с RBAC-фильтром
reseller/api.php (997 стр.)    → ResellerApiController (ограниченный AdminApiController)

Фаза 7: Миграция admin.php bootstrap

admin.php (4448 стр.) — после извлечения всех функций в domain/.

Шаг 7.1 — Вынос inline-данных

$rCountryCodes, $rCountries  → resources/data/countries.php
$rTimezones                  → resources/data/timezones.php
$rMacTypes                   → resources/data/mac_types.php

Шаг 7.2 — Замена процедурного bootstrap

admin.php::initDatabase()        → ServiceContainer::get('db')
admin.php::CoreUtilities::init() → bootstrap.php
admin.php::session_start()       → SessionManager::start()
admin.php::$rPermissions         → Authorization::getPermissions()
admin.php::Translator init       → ServiceContainer::get('translator')

Шаг 7.3 — Удаление admin.php

  • Все функции уже в domain/ (proxy-вызовы)
  • Все данные в resources/data/
  • Bootstrap через bootstrap.php
  • admin.php → тонкий require-файл (< 50 строк) или удаляется

Фаза 8: Очистка и финализация

Шаг 8.1 — Удаление proxy-методов

  • Обновить все вызывающие места на прямые вызовы новых классов
  • Удалить proxy-методы из CoreUtilities, StreamingUtilities, admin_api.php

Шаг 8.2 — Удаление god-объектов

  • CoreUtilities.php → удалить (все методы разнесены)
  • StreamingUtilities.php → удалить (все методы разнесены)
  • Если что-то осталось — вынести в утилитный класс

Шаг 8.3 — Ревизия core/

  • Убедиться: core/ не содержит бизнес-логики
  • Убедиться: domain/ не знает об interfaces/
  • Убедиться: удаление любого модуля не ломает систему

Шаг 8.4 — Рефакторинг cli/monitor.php

  • Удалить goto-лейблы (label235, label592)
  • Переписать с нормальным control flow
  • Вынести в interfaces/Cli/Commands/MonitorCommand.php

Сводка: объём работы по файлам

Исходный файл Строк Сколько целевых классов Фазы
CoreUtilities.php 4847 ~20 классов 1.7, 2, 3, 4, 5
admin_api.php 6981 ~25 классов (Service) 3.1–3.12, 5
admin.php 4448 ~15 классов (Repository + данные) 3, 5, 7
StreamingUtilities.php 1992 ~10 классов 2, 4
admin/post.php 1946 распределяется по контроллерам 6
admin/table.php 6003 распределяется по контроллерам 6
includes/api/admin/table.php 6868 распределяется по контроллерам 6
www/stream/auth.php 799 3 класса (Auth) 4
www/stream/live.php 707 3 класса (Delivery) 4
Прочие admin/*.php ~100 файлов Controller + View 6

Рекомендуемый порядок работы

Фаза 1.7  →  Фаза 2  →  Фаза 3.1–3.4  →  Фаза 4.1–4.3  →  Фаза 3.5–3.12
                                                              ↓
Фаза 5.1–5.5  →  Фаза 5.6  →  Фаза 6.1–6.4  →  Фаза 7  →  Фаза 8

Каждый шаг (1.7.1, 1.7.2 ...) — это одна рабочая сессия (1–3 часа). Каждая фаза (1.7, 2, 3...) — это неделя–две постепенной работы. После каждого шага система полностью работоспособна.


Приложение: Один bootstrap вместо трёх

bootstrap.php предоставляет класс XC_Bootstrap с четырьмя контекстами инициализации:

Контекст Что загружает Для чего
CONTEXT_MINIMAL autoload + constants + Logger Скрипты, которым нужны только пути
CONTEXT_CLI + Database + CoreUtilities Cron-задачи, CLI-скрипты
CONTEXT_STREAM + Database + StreamingUtilities (кэш) Стриминг-эндпоинты (hot path)
CONTEXT_ADMIN + Database + CoreUtilities + API + ResellerAPI + Translator + session + Redis Админ/реselлер-панель
// interfaces/Http/public/index.php — admin/reseller entry point
require_once '/home/xc_vm/bootstrap.php';
XC_Bootstrap::defineStatusConstants();
XC_Bootstrap::boot(XC_Bootstrap::CONTEXT_ADMIN);
// $db, CoreUtilities, API, ResellerAPI, Translator — всё готово
// interfaces/Http/public/stream.php — streaming entry point (lightweight)
require_once '/home/xc_vm/bootstrap.php';
XC_Bootstrap::boot(XC_Bootstrap::CONTEXT_STREAM);
// Только Database + StreamingUtilities, без admin_api, без Translator
// interfaces/Cli/CronJobs/StreamsCron.php — cron
require_once '/home/xc_vm/bootstrap.php';
XC_Bootstrap::boot(XC_Bootstrap::CONTEXT_CLI, [
    'cached'  => true,
    'redis'   => true,
    'process' => 'XC_VM[Streams]'
]);
// Database + CoreUtilities + Redis, без session и admin API

Один автозагрузчик. Один набор констант. Каждая точка входа вызывает boot() с нужным контекстом. Новые классы миграции находятся автоматически через XC_Autoloader — без ручного require_once.