mirror of
https://github.com/Vateron-Media/XC_VM.git
synced 2026-10-17 12:02:55 +02:00
Route proxy-mode live TS through the xc_fanout daemon behind the `live_fanout` settings flag, taking PHP out of the byte path. When the flag is on, live.php runs its existing auth unchanged, then instead of the socket_read→echo relay it registers the source with the daemon over the control unix socket and hands the viewer to nginx via `X-Accel-Redirect: /xc_fanout/live/<id>` — the FPM worker is freed immediately, same pattern as P1 HLS delivery. Flag off (the default) keeps the legacy relay; a failed registration falls through to it in-request, so a down daemon degrades gracefully. - FanoutClient: control-socket client (PUT/DELETE /streams/<id> over FANOUT_CTL_SOCK via cURL unix socket) + buildSource(), a pure mirror of ProxyCommand's stream_source/user_agent/proxy/cookie extraction whose JSON matches the daemon's streamConfig. - Paths: FANOUT_RUN_PATH / FANOUT_CTL_SOCK / FANOUT_HTTP_SOCK under /run. - nginx: internal `location ^~ /xc_fanout/live/` → proxy_pass unix daemon client socket (buffering off, long read timeout). - FanoutClientTest: 8 cases covering source-config parity and the empty-urls short-circuit. Refs ADR 0002. Daemon lives in XC_VM_Binaries (not this repo).
83 lines
3.0 KiB
PHP
83 lines
3.0 KiB
PHP
<?php
|
|
|
|
use XcVm\Streaming\Fanout\FanoutClient;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
/**
|
|
* @covers \XcVm\Streaming\Fanout\FanoutClient
|
|
*
|
|
* Exercises the pure source-config builder that feeds the xc_fanout daemon's
|
|
* control API (ADR 0002, P2). buildSource() mirrors ProxyCommand's argument
|
|
* extraction; the output shape must match the daemon's streamConfig JSON
|
|
* (urls/ua/proxy/cookie/ffmpeg).
|
|
*/
|
|
final class FanoutClientTest extends TestCase {
|
|
|
|
public function testBuildSourceDecodesStreamSourceArray() {
|
|
$row = ['stream_source' => json_encode(['http://a/1.ts', 'http://b/2.m3u8'])];
|
|
$src = FanoutClient::buildSource($row, []);
|
|
|
|
$this->assertSame(['http://a/1.ts', 'http://b/2.m3u8'], $src['urls']);
|
|
$this->assertArrayHasKey('ua', $src);
|
|
$this->assertArrayHasKey('proxy', $src);
|
|
$this->assertArrayHasKey('cookie', $src);
|
|
$this->assertArrayHasKey('ffmpeg', $src);
|
|
}
|
|
|
|
public function testBuildSourceTrimsAndDropsEmptyUrls() {
|
|
$row = ['stream_source' => json_encode([' http://a/1.ts ', '', ' '])];
|
|
$src = FanoutClient::buildSource($row, []);
|
|
|
|
$this->assertSame(['http://a/1.ts'], $src['urls']);
|
|
}
|
|
|
|
public function testBuildSourceDefaultsUserAgentWhenArgumentMissing() {
|
|
$row = ['stream_source' => json_encode(['http://a/1.ts'])];
|
|
$src = FanoutClient::buildSource($row, []);
|
|
|
|
$this->assertSame('Mozilla/5.0', $src['ua']);
|
|
$this->assertSame('', $src['proxy']);
|
|
$this->assertSame('', $src['cookie']);
|
|
}
|
|
|
|
public function testBuildSourceFallsBackToArgumentDefaultUserAgent() {
|
|
$row = ['stream_source' => json_encode(['http://a/1.ts'])];
|
|
$args = ['user_agent' => ['value' => '', 'argument_default_value' => 'VLC/3.0']];
|
|
$src = FanoutClient::buildSource($row, $args);
|
|
|
|
$this->assertSame('VLC/3.0', $src['ua']);
|
|
}
|
|
|
|
public function testBuildSourcePrefersExplicitUserAgentValue() {
|
|
$row = ['stream_source' => json_encode(['http://a/1.ts'])];
|
|
$args = ['user_agent' => ['value' => 'MyPlayer/1.0', 'argument_default_value' => 'VLC/3.0']];
|
|
$src = FanoutClient::buildSource($row, $args);
|
|
|
|
$this->assertSame('MyPlayer/1.0', $src['ua']);
|
|
}
|
|
|
|
public function testBuildSourceExtractsProxyAndCookie() {
|
|
$row = ['stream_source' => json_encode(['http://a/1.ts'])];
|
|
$args = [
|
|
'proxy' => ['value' => '1.2.3.4:8080'],
|
|
'cookie' => ['value' => 'sid=xyz'],
|
|
];
|
|
$src = FanoutClient::buildSource($row, $args);
|
|
|
|
$this->assertSame('1.2.3.4:8080', $src['proxy']);
|
|
$this->assertSame('sid=xyz', $src['cookie']);
|
|
}
|
|
|
|
public function testBuildSourceHandlesMissingOrInvalidStreamSource() {
|
|
$this->assertSame([], FanoutClient::buildSource([], [])['urls']);
|
|
$this->assertSame([], FanoutClient::buildSource(['stream_source' => ''], [])['urls']);
|
|
$this->assertSame([], FanoutClient::buildSource(['stream_source' => 'not-json'], [])['urls']);
|
|
}
|
|
|
|
public function testRegisterRejectsEmptyUrlsWithoutTouchingDaemon() {
|
|
// No daemon is running in tests; empty urls must short-circuit to false
|
|
// before any socket call is attempted.
|
|
$this->assertFalse(FanoutClient::register(42, ['urls' => []]));
|
|
}
|
|
}
|