Add Edge Agent implementation for gateway connection lifecycle, agent commands, Shelly device discovery, relay control, and WebSocket communication with broker. Include unit tests for critical flows.

This commit is contained in:
Jeppe Bundgaard
2026-04-08 19:01:42 +02:00
parent 653680376a
commit 45b7250480
101 changed files with 21583 additions and 16 deletions
@@ -0,0 +1,91 @@
<?php
app_require('classes/edge_gateway_manager.php');
use classes\edge_gateway_manager;
class EdgeGatewayManagerUrlHarness extends edge_gateway_manager
{
public function __construct()
{
}
}
function with_edge_gateway_server_state(array $server, callable $callback): void
{
$originalServer = $_SERVER;
$originalPublicApiUrl = getenv('EDGE_PUBLIC_API_URL');
$_SERVER = $server;
try {
$callback();
} finally {
$_SERVER = $originalServer;
if ($originalPublicApiUrl === false) {
putenv('EDGE_PUBLIC_API_URL');
} else {
putenv('EDGE_PUBLIC_API_URL=' . $originalPublicApiUrl);
}
}
}
it('builds install script urls with forwarded https scheme when proxied', function (): void {
with_edge_gateway_server_state([
'HTTP_HOST' => 'api.truckwash.io:4433',
'HTTP_X_FORWARDED_PROTO' => 'https',
], function (): void {
$manager = new EdgeGatewayManagerUrlHarness();
$script = $manager->buildInstallScript('abc123');
expect($manager->getApiBaseUrl())->toBe('https://api.truckwash.io:4433');
expect($manager->buildInstallScriptUrl('abc123'))->toBe('https://api.truckwash.io:4433/edge-agent/install.sh?token=abc123');
expect($manager->buildInstallCommand('abc123'))->toContain("https://api.truckwash.io:4433/edge-agent/install.sh?token=abc123");
expect($script)->toContain('mkdir -p "$INSTALL_DIR"');
expect($script)->toContain('curl -fsSL "https://api.truckwash.io:4433/edge-agent/artifacts/package.json" -o "$INSTALL_DIR/package.json"');
expect($script)->toContain('curl -fsSL "https://api.truckwash.io:4433/edge-agent/artifacts/agent.mjs" -o "$INSTALL_DIR/agent.mjs"');
expect($script)->toContain('"apiUrl":"https://api.truckwash.io:4433"');
expect($script)->toContain('"brokerUrl":"https://api.truckwash.io:4300"');
expect($script)->not->toContain('Undefined variable $INSTALL_DIR');
});
});
it('appends forwarded ports when the forwarded host omits them', function (): void {
with_edge_gateway_server_state([
'HTTP_X_FORWARDED_PROTO' => 'https',
'HTTP_X_FORWARDED_HOST' => 'api.truckwash.io',
'HTTP_X_FORWARDED_PORT' => '4433',
], function (): void {
$manager = new EdgeGatewayManagerUrlHarness();
expect($manager->getApiBaseUrl())->toBe('https://api.truckwash.io:4433');
});
});
it('infers https for the staging api host when only the https port is present', function (): void {
with_edge_gateway_server_state([
'HTTP_HOST' => 'api.truckwash.io:4433',
'SERVER_PORT' => '4433',
], function (): void {
$manager = new EdgeGatewayManagerUrlHarness();
$script = $manager->buildInstallScript('port-only');
expect($manager->getApiBaseUrl())->toBe('https://api.truckwash.io:4433');
expect($script)->toContain('"apiUrl":"https://api.truckwash.io:4433"');
expect($script)->toContain('"brokerUrl":"https://api.truckwash.io:4300"');
});
});
it('prefers EDGE_PUBLIC_API_URL when explicitly configured', function (): void {
with_edge_gateway_server_state([
'HTTP_HOST' => 'localhost',
'HTTP_X_FORWARDED_PROTO' => 'http',
], function (): void {
putenv('EDGE_PUBLIC_API_URL=https://edge.example.test/api');
$manager = new EdgeGatewayManagerUrlHarness();
expect($manager->getApiBaseUrl())->toBe('https://edge.example.test/api');
expect($manager->buildInstallScriptUrl('token-1'))->toBe('https://edge.example.test/api/edge-agent/install.sh?token=token-1');
});
});