Files

53 lines
1.7 KiB
TypeScript

import { DomainError } from "./domain-error.ts";
export type RelayPlacementRouteRecord = {
tenant_id: string;
tenant_status: string;
home_region: string;
relay_node_id: string | null;
generation: number;
placement_state: string;
authorization_revision: number;
internal_endpoint_ref?: string | null;
relay_node_status?: string | null;
};
export type RelayRouteResolution = {
relay_node_id: string;
placement_generation: number;
home_region: string;
local: boolean;
endpoint_ref?: string;
};
export function isWritableRelayPlacement(
placementState: string | null | undefined,
relayNodeStatus: string | null | undefined,
): boolean {
return ["active", "draining"].includes(placementState ?? "") && relayNodeStatus === "active";
}
export function resolveRelayPlacementRoute(
placement: RelayPlacementRouteRecord,
currentNodeId: string,
): RelayRouteResolution {
if (!placement.relay_node_id || !["active", "draining"].includes(placement.placement_state)) {
throw new DomainError("service_provisioning", "租户 Relay 正在准备", 503, true, 5);
}
if (placement.relay_node_status !== "active") {
throw new DomainError("region_unavailable", "目标 Relay 节点当前不可用", 503, true, 5);
}
const local = placement.relay_node_id === currentNodeId;
const endpointRef = placement.internal_endpoint_ref?.trim() ?? "";
if (!local && !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(endpointRef)) {
throw new DomainError("route_unavailable", "目标 Relay 内部路由不可用", 503, true, 5);
}
return {
relay_node_id: placement.relay_node_id,
placement_generation: placement.generation,
home_region: placement.home_region,
local,
...(local ? {} : { endpoint_ref: endpointRef }),
};
}