Normalize edge broker URL updates

This commit is contained in:
Jeppe Bundgaard
2026-07-01 11:53:01 +02:00
parent f706531534
commit 11d39af934
2 changed files with 37 additions and 1 deletions
@@ -2640,7 +2640,9 @@ final class TruckwashEdgeAgent
}
$current = trim((string)$this->config->get('brokerUrl'));
if (rtrim($current, '/') === rtrim($brokerUrl, '/')) {
$currentNormalized = $this->normalizeBrokerUrlForComparison($current);
$nextNormalized = $this->normalizeBrokerUrlForComparison($brokerUrl);
if ($currentNormalized !== null && $currentNormalized === $nextNormalized) {
return;
}
@@ -2650,6 +2652,38 @@ final class TruckwashEdgeAgent
$this->logger->info('Updated broker URL from control plane heartbeat response.');
}
private function normalizeBrokerUrlForComparison(?string $value): ?string
{
$trimmed = rtrim(trim((string)($value ?? '')), '/');
if ($trimmed === '') {
return null;
}
if (str_starts_with($trimmed, 'https://')) {
$trimmed = 'wss://' . substr($trimmed, 8);
} elseif (str_starts_with($trimmed, 'http://')) {
$trimmed = 'ws://' . substr($trimmed, 7);
} elseif (!str_starts_with($trimmed, 'ws://') && !str_starts_with($trimmed, 'wss://')) {
$trimmed = 'ws://' . $trimmed;
}
$parts = parse_url($trimmed);
if (!is_array($parts) || empty($parts['host'])) {
return strtolower($trimmed);
}
$scheme = strtolower((string)($parts['scheme'] ?? 'ws'));
$host = strtolower((string)$parts['host']);
$port = isset($parts['port']) ? (int)$parts['port'] : ($scheme === 'wss' ? 443 : 80);
$path = rtrim((string)($parts['path'] ?? ''), '/');
if ($host === 'edge-broker' && ($path === '/edge-broker' || str_starts_with($path, '/edge-broker/'))) {
$path = rtrim(substr($path, strlen('/edge-broker')), '/');
}
$isDefaultPort = ($scheme === 'wss' && $port === 443) || ($scheme !== 'wss' && $port === 80);
return $scheme . '://' . $host . ($isDefaultPort ? '' : ':' . $port) . ($path === '' ? '' : $path);
}
private function shouldPersistControlPlaneEventOverHttp(string $endpoint): bool
{
return preg_match('#/edge-agent/gateways/\d+/heartbeat$#', $endpoint) === 1;
@@ -191,6 +191,8 @@ it('exposes update payload, credential rotation, cancel endpoints, and operation
expect($agentSource)->toContain('private AgentShellBridge $shellBridge;');
expect($agentSource)->toContain('private function dispatchBrokerControlPlaneEvent(string $endpoint, array $payload): ?bool');
expect($agentSource)->toContain('private function shouldPersistControlPlaneEventOverHttp(string $endpoint): bool');
expect($agentSource)->toContain('private function normalizeBrokerUrlForComparison(?string $value): ?string');
expect($agentSource)->toContain('$currentNormalized = $this->normalizeBrokerUrlForComparison($current);');
expect($agentSource)->toContain('if ($brokerDispatch === true && !$this->shouldPersistControlPlaneEventOverHttp($endpoint))');
expect($agentSource)->toContain('if ($brokerDispatch !== true || $this->shouldPersistControlPlaneEventOverHttp($endpoint))');
expect($agentSource)->toContain('Broker dispatched \' . $type . \' but HTTP persistence failed on \' . $endpoint');