Overhaul the Docsify documentation (English + Russian) so it matches the current codebase and follows one consistent pattern. Content accuracy (post-migration): - Rewrite development/autoloader.md to PSR-4 / Composer (the old XC_Autoloader scanner, igbinary tmp/cache/autoload_map and registerDirectories are gone). - PascalCase every source path (src/core -> src/Core, domain/Stream, cli/Commands, public/Controllers, Infrastructure/Redis, ...) across all docs. - Replace the removed autoload.php references with vendor/autoload.php (build_system, bootstrap-contexts, error-handling, modules). - ssl-generation: note that the installer now auto-generates a unique self-signed certificate before Nginx starts. Common pattern (Clean & uniform): - Strip emoji from headings; remove the in-page Navigation blocks (the Docsify sidebar already provides navigation). - One H1 + intro per doc; uniform "Related files" / "Связанные файлы" section, added to the code-centric docs that lacked it. Structure: - Remove the empty stray docs/api/; move updates_checklist.md into builds/; link the previously-orphaned ucs-integration.md. - Regroup the sidebars (split the oversized guides group into Developer Guides / Security & Access / Integrations; fold builds into Build & Release). Augment: - dev-workflow: Local Setup (make dev-tools) + Quality Checks (phpstan, cs, gates). - build_system: Composer Dependencies section (committed prod-only vendor, committed lock, dev tools via composer install, no build-time vendor step). en/ru parity: - Apply the same structure, fixes and pattern to docs/ru/ (translated), including a new Russian ucs-integration.md. The en and ru file sets are now identical.
7.6 KiB
Caching and Redis Strategy
XC_VM uses a dual-layer caching strategy:
- File-based cache (igbinary) — primary layer, used by both streaming and admin paths
- Redis/KeyDB — optional high-performance layer for connection state and advanced operations
The streaming path reads exclusively from file cache (no database queries). The admin path reads from the database with optional short-lived cache.
Cache Interface
File: src/Core/Cache/CacheInterface.php
get($key, $maxAge = null)
set($key, $data, $ttl = 0)
delete($key)
has($key, $maxAge = null)
flush()
$ttl = 0means cache forever (until manual deletion or flush).$maxAgechecks file modification time for freshness (FileCache only).
FileCache
File: src/Core/Cache/FileCache.php
Default cache implementation. Stores igbinary-serialized data as flat files.
$cache = new FileCache(CACHE_TMP_PATH);
$cache->set('my_key', $data, 3600);
$data = $cache->get('my_key', 120); // only if < 2 min old
Static convenience API (backward compatibility):
FileCache::setCache($key, $data)
FileCache::getCache($key, $maxAge = null)
Characteristics:
- Serialization: igbinary (if available) or PHP serialize fallback.
- Locking:
LOCK_EXon write to prevent corruption. - File location:
{basePath}/{key}(no subdirectories for core keys). - Corruption recovery: detects bad data, auto-deletes corrupted files.
RedisCache
File: src/Core/Cache/RedisCache.php
Optional high-performance implementation.
$redis = new RedisCache('127.0.0.1', 6379, $password, 'prefix:');
$redis->set($key, $data, 600); // 10-minute TTL via SETEX
$redis->getConnection(); // raw phpredis for sorted sets, pipelines
- Lazy connection: connects on first operation.
- Native TTL support via Redis
SETEX. - Used primarily for
ConnectionTracker(sorted sets for live connection state).
Redis Connection Management
File: src/Infrastructure/Redis/RedisManager.php
Singleton lifecycle:
RedisManager::instance() // get active Redis or null
RedisManager::ensureConnected() // connect if not already
RedisManager::isConnected() // health check
RedisManager::closeInstance() // disconnect
Health check pings Redis every 30 seconds (debounced). Auto-reconnects on failure. Returns null on connection failure (graceful degradation).
Configuration:
| Setting | Source | Default |
|---|---|---|
hostname |
config.ini |
— |
port |
hardcoded | 6379 |
password |
settings.redis_password |
— |
read_timeout |
hardcoded | 2.0s |
tcp_keepalive |
hardcoded | 60s |
Cache Population
Cache files are generated by two cron jobs:
Lightweight cache (CacheCronJob)
Runs every cron cycle. Rebuilds fast-changing data (~1 second):
settings— panel settingsservers— server listbouquets— channel packagescategories— stream categories- Blocklists:
blocked_isp,blocked_ua,blocked_ips,blocked_servers allowed_ips,output_formats,hmac_keys,rtmp_ips
Heavy cache (CacheEngineCronJob)
Rebuilds stream, line, and series data. Throttled to once per 5 minutes via heavy_cache_built marker:
STREAMS_TMP_PATH/stream_{id}— individual stream metadataLINES_TMP_PATH/line_i_{user_id}— user account dataLINES_TMP_PATH/line_c_{username_password}— username → user_id lookupLINES_TMP_PATH/line_t_{access_token}— token → user_id lookupSERIES_TMP_PATH/series_{id}— series metadata
Change detection mode (if cache_changes enabled): compares DB updated timestamp vs file mtime, rebuilds only changed items.
Full rebuild mode: regenerates all entries. Controlled by cache_thread_count setting.
Cache readiness
A cache_complete file is written after each full cache build. The streaming path checks for this file and exits with an error if missing.
Cache Key Conventions
System keys (CACHE_TMP_PATH)
| Key | Contents |
|---|---|
settings |
panel settings array |
servers |
array[server_id] → server config |
bouquets |
array[bouquet_id] → bouquet definition |
categories |
array[category_id] → category data |
bouquet_map |
array[stream_id] → array[bouquet_id] |
category_map |
array[bouquet_id] → array[category_id] |
permissions_{group_id} |
group permission set |
cache_complete |
time() timestamp of last full build |
Stream keys (STREAMS_TMP_PATH)
| Key | Contents |
|---|---|
stream_{id} |
stream info + bouquets + per-server state |
channels_categories |
array[stream_id] → array[category_id] |
Line keys (LINES_TMP_PATH)
| Key | Contents |
|---|---|
line_i_{user_id} |
full user record |
line_c_{username_password} |
user_id (credential lookup) |
line_t_{access_token} |
user_id (token lookup) |
Series keys (SERIES_TMP_PATH)
| Key | Contents |
|---|---|
series_{id} |
series metadata |
series_map |
array[stream_id] → series_id |
episodes_{series_id} |
array[season_num] → episode list |
Invalidation Patterns
| Trigger | Affected keys | Mechanism |
|---|---|---|
| Admin edits stream | stream_{id}, bouquet_map |
signal → next cron:cache_engine |
| Admin edits line | line_i_*, line_c_*, line_t_* |
next cron:cache_engine |
| Settings changed | settings, categories, blocklists |
SettingsManager::clearCache() + cron |
| Server list updated | servers, bouquet_map |
cron |
| Stream start (FFprobe) | {md5(source)} |
5-minute TTL via file mtime check |
| Admin flush button | all files in CACHE_TMP_PATH |
rm -rf |
Streaming vs Admin Path
Streaming path (www/stream/*)
cached: trueby default.- Reads from file cache exclusively (no DB queries).
- Raw igbinary deserialization:
igbinary_unserialize(file_get_contents(...)). - If
cache_completemissing: exit with error.
Admin path (Public/Controllers/Admin/*)
cached: falseby default.- Reads from database directly via domain services.
- Optional short-lived cache (example from
BouquetService::getAll()):
$rCache = FileCache::getCache('bouquets', 60); // only if < 60s old
if (!empty($rCache)) {
return $rCache;
}
// miss: query database and write cache
FileCache::setCache('bouquets', $rOutput);
Cache File Layout
/home/xc_vm/tmp/cache/
├── settings
├── servers
├── bouquets
├── categories
├── bouquet_map
├── category_map
├── cache_complete
├── heavy_cache_built
├── streams/
│ ├── stream_{id}
│ └── channels_categories
├── lines/
│ ├── line_i_{user_id}
│ ├── line_c_{username_password}
│ └── line_t_{access_token}
└── series/
├── series_{id}
├── series_map
└── episodes_{series_id}
Related files
| File | Purpose |
|---|---|
src/Core/Cache/CacheInterface.php |
cache contract |
src/Core/Cache/FileCache.php |
file-based cache implementation |
src/Core/Cache/RedisCache.php |
Redis cache implementation |
src/Infrastructure/Redis/RedisManager.php |
Redis connection singleton |
src/Infrastructure/Cache/CacheReader.php |
legacy cache reader bridge |
src/Cli/CronJobs/CacheCronJob.php |
lightweight cache generation |
src/Cli/CronJobs/CacheEngineCronJob.php |
heavy cache generation (streams, lines, series) |
src/Domain/Bouquet/BouquetService.php |
example of admin-path caching |
src/Domain/Stream/ConnectionTracker.php |
Redis sorted sets for connection state |