Files
XC_VM/docs/en/builds/build_system.md
T
Divarion_D 1aede3bf4c refactor(i18n): co-locate language files with the Translator
Move the .ini language files from src/resources/langs/ to
src/Core/Localization/lang/, next to the Translator subsystem that owns
them — which already defaulted its $langsDir to __DIR__ . '/lang/'. This
dissolves the now-vestigial src/resources/ bucket (its data/ tree went
with admin_constants, libs/ was empty).

- bootstrap.php calls Translator::init() with no argument, relying on the
  class's own __DIR__-relative default instead of MAIN_HOME . 'resources/langs/'.
- Makefile LB removal list points at Core/Localization/lang (and drops the
  gone resources/langs, resources/libs); LB still ships no UI translations.
- Drop the stale src/resources entries from phpstan scanDirectories and the
  phpunit coverage excludes.
- Update the English docs (translations guide, build-system table); the ru
  tree is regenerated before release.
2026-08-31 21:28:16 +03:00

291 lines
10 KiB
Markdown

# XC_VM Build System (MAIN vs LB)
How XC_VM produces two build variants from a single codebase: a full MAIN server and a lightweight Load Balancer (LB) server.
---
## Build Variants
XC_VM supports two deployment roles from a single source tree:
| Variant | Archive | Purpose |
| --- | --- | --- |
| **MAIN** | `xc_vm.tar.gz` | Full application — admin panel, streaming, all modules, cron jobs |
| **LB** (Load Balancer) | `loadbalancer.tar.gz` | Streaming-only server — no admin panel, no user management |
**MAIN** is the primary server that manages everything: admin UI, database writes, user/device management, EPG processing, backups, etc.
**LB** is a lightweight streaming node that receives streams from MAIN (or other sources) and delivers them to clients. It connects to the master database in read-only mode and has no admin panel or management capabilities.
---
## Makefile Targets
| Target | Output | Description |
| --- | --- | --- |
| `make main` | `dist/xc_vm.tar.gz` | Full MAIN build |
| `make lb` | `dist/loadbalancer.tar.gz` | LB build (streaming-only subset) |
| `make new` | (resets `dist/`) | Remove and recreate the empty `dist/` output dir — run before a build; builds nothing itself |
| `make generate_deleted_files` | `src/migrations/deleted_files.txt` | List files removed since the last tag (see below) |
> **Updates reuse the full archive.** There is no separate incremental-update target — the same
> `xc_vm.tar.gz` / `loadbalancer.tar.gz` is used for both install and update; filtering happens on
> the server at update time (see [Update Mechanism](../administration/update-system.md)). To delete
> files that were *removed* between releases, `make generate_deleted_files [LAST_TAG=vX.Y.Z]` diffs
> git and writes `deleted_files.txt`, which the updater applies.
Additional outputs:
- `XC_VM.zip` — installer package (`install/` + `xc_vm.tar.gz`)
- `hashes.md5` — MD5 checksums for integrity verification
---
## Composer Dependencies
`src/vendor/` (the Composer PSR-4 autoloader plus the production dependencies) is
**committed** and shipped as-is — the deploy path has no Composer and never runs
`composer install`. It is kept production-only via `composer install --no-dev`, so
both build variants ship a lean vendor with no dev tooling.
- `src/composer.lock` is committed so `composer install` is reproducible.
- Dev tools (PHPStan, phpcs) are `require-dev` and are **not** in the
committed vendor or the archives. Developers and CI add them with `make dev-tools`
(`composer install`); the `check-vendor-prod-only` gate fails if a dev package is
ever committed under `src/vendor/`.
- There is no build-time vendor step — `make main` / `make lb` copy the committed
`vendor/` directly into the archive.
---
## What Goes Into Each Build
### MAIN Build
The MAIN build contains the **entire** `src/` directory.
### LB Build — Included Directories
Only these directories are copied into the LB archive:
```text
bin/ Cli/ config/ content/ Core/
Domain/ Infrastructure/ Public/ resources/
signals/ Streaming/ tmp/ vendor/ www/
```
Plus root files: `bootstrap.php`, `console.php`, `service`, `update`.
### LB Build — Excluded Content
After copying, admin-specific content is **removed** from the LB build:
**Directories removed:**
| Path | Reason |
| --- | --- |
| `bin/install/` | Installer scripts (not needed on LB) |
| `bin/redis/` | Redis binary (LB doesn't run its own Redis) |
| `bin/nginx/conf/codes/` | Error code pages (admin UI) |
| `Public/Controllers/Admin/` | Admin panel controllers |
| `Public/Controllers/Player/` | Player panel controllers |
| `Public/Controllers/Reseller/` | Reseller panel controllers |
| `Public/Views/` | Panel templates |
| `Public/assets/` | Panel static assets |
| `Public/routes/` | Panel route maps |
| `Domain/User/` | User management |
| `Domain/Device/` | Device registration |
| `Domain/Auth/` | Auth management (panel auth) |
| `Core/Reference/` | Admin reference-data classes (MAIN-only) |
| `Core/Localization/lang/` | Language resource files (`.ini`) |
**Files removed** (these mirror `LB_FILES_TO_REMOVE` in the Makefile):
> ⚠️ Several entries here use the legacy `www/…` prefix (e.g. `www/stream/auth.php`,
> `www/xplugin.php`). `src/www/` no longer exists — the streaming/API endpoints moved under
> `src/Public/stream/` and `src/Public/…`. These `www/…` removal entries are therefore **no-ops**
> today and are worth auditing in the Makefile (a file that should be stripped from LB may in fact
> still ship under its `Public/` path).
| File | Reason |
| --- | --- |
| `Public/Controllers/Api/AdminApiController.php` | Full admin API removed from LB |
| `Public/Controllers/Api/ResellerRestApiController.php` | Reseller API removed from LB |
| `www/xplugin.php`, `www/probe.php`, `www/playlist.php` | Admin endpoints |
| `www/player_api.php`, `www/epg.php`, `www/enigma2.php` | Client API endpoints (served by MAIN) |
| `www/stream/auth.php` | Auth endpoint (legacy path — see note) |
| `www/admin/api.php`, `www/admin/proxy_api.php` | Admin API |
| `bin/maxmind/GeoLite2-City.mmdb` | GeoIP DB shipped separately |
| `config/rclone.conf` | Backup config |
| `Domain/Epg/EPG.php` | EPG processing class |
| `bin/nginx/conf/gzip.conf` | Gzip config (LB uses own) |
**CLI commands removed:**
| File | Reason |
| --- | --- |
| `Cli/Commands/MigrateCommand.php` | Migration is MAIN-only |
| `Cli/Commands/CacheHandlerCommand.php` | Cache handler is MAIN-only |
| `Cli/Commands/ServerInstallCommand.php` | Server installer (not needed on LB itself) |
| `Cli/Commands/LbInstallFlow.php` | LB install helper (not needed on LB itself) |
| `Cli/Commands/ProxyInstallFlow.php` | Proxy install helper (not needed on LB itself) |
**Cron jobs removed:**
| File | Reason |
| --- | --- |
| `Cli/CronJobs/RootMysqlCronJob.php` | DB maintenance (MAIN-only) |
| `Cli/CronJobs/BackupsCronJob.php` | Backups (MAIN-only) |
| `Cli/CronJobs/CacheEngineCronJob.php` | Full cache rebuild (MAIN-only) |
| `Cli/CronJobs/EpgCronJob.php` | EPG processing (MAIN-only) |
| `Cli/CronJobs/UpdateCronJob.php` | Update check (MAIN-only) |
| `Cli/CronJobs/ProvidersCronJob.php` | Provider sync (MAIN-only) |
| `Cli/CronJobs/SeriesCronJob.php` | Series metadata (MAIN-only) |
> **Note:** Module-related crons (TMDB, Plex, Watch) live inside `src/Modules/<name>/` and are excluded from LB builds automatically — `Modules/` is not in `LB_DIRS`.
>
> **Ministra** (`src/Ministra/`, the Stalker portal — ~50 MB of assets) is likewise excluded by
> **omission**: it isn't listed in `LB_DIRS`, so it's never copied into the LB archive (there is no
> explicit removal rule for it — hence the `ministra` absence check in *Build Verification* below).
### LB Build — Replaced Configs
These files from `lb_configs/` **replace** the MAIN versions:
| Source | Target | Purpose |
| --- | --- | --- |
| `lb_configs/nginx.conf` | `bin/nginx/conf/nginx.conf` | Performance-tuned nginx for streaming |
| `lb_configs/live.conf` | `bin/nginx_rtmp/conf/live.conf` | RTMP callback hooks |
---
## MAIN vs LB — Key Differences
| Aspect | MAIN | LB |
| --- | --- | --- |
| Admin panel | ✅ Full UI | ❌ Not included |
| Database role | Read + Write | Read-only consumer |
| User/device management | ✅ | ❌ |
| EPG processing | ✅ | ❌ |
| Backups | ✅ | ❌ |
| Migration tool | ✅ | ❌ |
| Stream delivery | ✅ | ✅ |
| RTMP ingestion | ✅ | ✅ |
| Transcoding (FFmpeg) | ✅ | ✅ |
| CLI commands | 26 | ~15 (admin-only removed) |
| Cron jobs | 25 | ~16 (admin-only removed) |
| Module system | ✅ | ❌ |
---
## LB Nginx Configuration
The LB build uses a specialized nginx config optimized for high-throughput streaming:
| Setting | Value | Purpose |
| --- | --- | --- |
| Worker processes | `auto` | Scale to CPU cores |
| Worker connections | 16,000 | High concurrency per worker |
| Max file descriptors | 300,000 | System resource limit |
| Thread pool | `pool_xc_vm` (32 threads) | Async I/O for streaming |
| Gzip | OFF | Streaming data is already compressed |
| Access logs | OFF | Reduce I/O overhead |
| Rate limiting | 20 req/s per IP | DDoS mitigation |
| Send timeout | 20 min | Support long-running streams |
RTMP hooks (`lb_configs/live.conf`) route authentication through local HTTP callbacks instead of the admin panel:
```nginx
on_play http://127.0.0.1:8080/stream/rtmp;
on_publish http://127.0.0.1:8080/stream/rtmp;
on_play_done http://127.0.0.1:8080/stream/rtmp;
```
---
## Runtime Behavior on LB
### Conditional Command Loading
`console.php` uses `file_exists()` guards for commands that may not exist on LB servers:
```php
if (file_exists(__DIR__ . '/Cli/Commands/CacheHandlerCommand.php')) {
$rRegistry->register(new CacheHandlerCommand());
}
```
This prevents crashes when LB attempts to register a command whose file was removed during the build.
### Streaming Dependency Chain
LB servers retain the full streaming pipeline:
```text
www/stream/*.php
├── www/stream/init.php
├── vendor/autoload.php (Composer PSR-4 autoloader)
├── bootstrap.php (lightweight stream/bootstrap path)
├── Core/* (Config, Database, Cache, Auth, Http, Logging, Util)
├── Domain/Stream, Domain/Server, Domain/Vod, Domain/Bouquet
├── Streaming/* (Auth, Delivery, Codec, Protection)
├── Infrastructure/Redis, Infrastructure/Database
└── resources/data
```
---
## Adding New Code to Builds
### New streaming-relevant directory under `src/`
Add it to `LB_DIRS` in the Makefile:
```makefile
LB_DIRS := bin Cli config content Core Domain \
Infrastructure Public resources signals Streaming tmp vendor www your_dir
```
### New admin-only directory
Add it to `LB_DIRS_TO_REMOVE`:
```makefile
LB_DIRS_TO_REMOVE = ... your_dir/admin_stuff
```
### New admin-only file
Add it to `LB_FILES_TO_REMOVE`:
```makefile
LB_FILES_TO_REMOVE = ... your_dir/admin_file.php
```
### New CLI command (admin-only)
1. Add `file_exists()` guard in `console.php`
2. Add the file to `LB_FILES_TO_REMOVE`
---
## Build Verification
After modifying the build, verify both variants:
```bash
# Build both
make new
# Check LB contains streaming code
tar -tzf dist/loadbalancer.tar.gz | grep -cE "Core/|Domain/Stream|Streaming/"
# Expected: > 0
# Check LB does NOT contain admin code
tar -tzf dist/loadbalancer.tar.gz | grep -cE "admin/|player/|ministra|reseller"
# Expected: 0
# Compare sizes (LB should be significantly smaller)
ls -lh dist/xc_vm.tar.gz dist/loadbalancer.tar.gz
```