Use edge bindings for lane hardware batch relays

This commit is contained in:
Jeppe Bundgaard
2026-06-30 13:28:03 +02:00
parent f7a4126718
commit 3eafc597c6
2 changed files with 166 additions and 1 deletions
@@ -22,6 +22,7 @@ use modules\selfserve\helpers\selfserve_wash_session_status;
use modules\subusers\helpers\subusers_permission_node_key;
use objects\department_lanes_o;
use objects\departments_o;
use objects\edge_gateway_relay_bindings_o;
use objects\logs_o;
use objects\orders_o;
use objects\customer_vehicles_o;
@@ -1806,7 +1807,7 @@ class moduleSelfServeRoute
private function relayIdForLaneHardwareTarget(selfserve_lane $lane, string $target): string
{
return trim((string)match ($target) {
$relayId = trim((string)match ($target) {
'MACHINE' => $lane->department_lane->relay_machine_id->value(),
'PROGRAM_PICKER', 'MACHINE_PROGRAM_PICKER' => $lane->department_lane->relay_machine_program_picker_id->value(),
'CLEANER', 'MACHINE_CLEANER' => $lane->department_lane->relay_machine_cleaner_id->value(),
@@ -1814,6 +1815,153 @@ class moduleSelfServeRoute
'EXIT' => $lane->department_lane->relay_out_id->value(),
default => throw new \Exception('Unsupported lane hardware target: ' . $target),
});
if ($relayId !== '') {
return $relayId;
}
return $this->edgeGatewayRelayIdForLaneHardwareTarget($lane, $target);
}
private function edgeGatewayRelayIdForLaneHardwareTarget(selfserve_lane $lane, string $target): string
{
$departmentId = $this->departmentIdForLane($lane);
if ($departmentId <= 0) {
return '';
}
$rows = (new edge_gateway_relay_bindings_o())->getFieldsWhere([
'department_id' => $departmentId,
'deleted_at' => null,
], ['id']);
$laneScoped = [];
$unscoped = [];
foreach ($rows as $row) {
$binding = (new edge_gateway_relay_bindings_o())->select((int)$row['id']);
if (!$binding->exists()) {
continue;
}
$payload = $binding->asArray();
if (!$this->edgeGatewayBindingMatchesHardwareTarget($payload, $target)) {
continue;
}
if ($this->edgeGatewayBindingMatchesLane($payload, (int)$lane->id, $target)) {
$laneScoped[] = (string)$payload['relay_id'];
continue;
}
if ($this->edgeGatewayBindingHasConsumers($payload)) {
continue;
}
$unscoped[] = (string)$payload['relay_id'];
}
$candidates = $laneScoped !== [] ? array_values(array_unique($laneScoped)) : array_values(array_unique($unscoped));
if (count($candidates) === 1) {
return $candidates[0];
}
if (count($candidates) > 1) {
throw new \Exception('Multiple edge gateway relay bindings match lane hardware target ' . $target);
}
return '';
}
/**
* @param array<string,mixed> $binding
*/
private function edgeGatewayBindingMatchesHardwareTarget(array $binding, string $target): bool
{
$accepted = match ($target) {
'MACHINE' => ['MACHINE'],
'PROGRAM_PICKER', 'MACHINE_PROGRAM_PICKER' => ['PROGRAM_PICKER', 'MACHINE_PROGRAM_PICKER'],
'CLEANER', 'MACHINE_CLEANER' => ['CLEANER', 'MACHINE_CLEANER'],
'ENTRANCE' => ['ENTRANCE', 'ENTRY'],
'EXIT' => ['EXIT'],
default => [],
};
if ($accepted === []) {
return false;
}
$metadata = isset($binding['metadata']) && is_array($binding['metadata']) ? (array)$binding['metadata'] : [];
$values = [
$binding['role'] ?? null,
$binding['service'] ?? null,
$binding['slot'] ?? null,
$metadata['role'] ?? null,
$metadata['relay_role'] ?? null,
$metadata['service'] ?? null,
$metadata['slot'] ?? null,
];
foreach ((array)($binding['services'] ?? $metadata['services'] ?? []) as $service) {
$values[] = $service;
}
foreach ($values as $value) {
if (in_array($this->normalizeLaneHardwareTargetRole($value), $accepted, true)) {
return true;
}
}
return false;
}
/**
* @param array<string,mixed> $binding
*/
private function edgeGatewayBindingMatchesLane(array $binding, int $laneId, string $target): bool
{
$targetRoles = match ($target) {
'MACHINE' => ['MACHINE'],
'PROGRAM_PICKER', 'MACHINE_PROGRAM_PICKER' => ['PROGRAM_PICKER', 'MACHINE_PROGRAM_PICKER'],
'CLEANER', 'MACHINE_CLEANER' => ['CLEANER', 'MACHINE_CLEANER'],
'ENTRANCE' => ['ENTRANCE', 'ENTRY'],
'EXIT' => ['EXIT'],
default => [],
};
$metadata = isset($binding['metadata']) && is_array($binding['metadata']) ? (array)$binding['metadata'] : [];
$consumers = $binding['consumer_contexts'] ?? $binding['consumers'] ?? $metadata['consumer_contexts'] ?? $metadata['consumers'] ?? [];
if (!is_array($consumers)) {
return false;
}
foreach ($consumers as $consumer) {
if (!is_array($consumer)) {
continue;
}
if (strtolower(trim((string)($consumer['type'] ?? ''))) !== 'lane') {
continue;
}
if ((int)($consumer['id'] ?? 0) !== $laneId) {
continue;
}
$slot = $this->normalizeLaneHardwareTargetRole($consumer['slot'] ?? '');
if ($slot === '' || in_array($slot, $targetRoles, true)) {
return true;
}
}
return false;
}
/**
* @param array<string,mixed> $binding
*/
private function edgeGatewayBindingHasConsumers(array $binding): bool
{
$metadata = isset($binding['metadata']) && is_array($binding['metadata']) ? (array)$binding['metadata'] : [];
$consumers = $binding['consumer_contexts'] ?? $binding['consumers'] ?? $metadata['consumer_contexts'] ?? $metadata['consumers'] ?? [];
return is_array($consumers) && $consumers !== [];
}
private function normalizeLaneHardwareTargetRole(mixed $value): string
{
return strtoupper(str_replace(['-', ' '], '_', trim((string)($value ?? ''))));
}
private function requireLaneHardwareStatusPermission(string $target): void