Files
paseo/packages/app/src/utils/connection-selection.ts
T

66 lines
1.9 KiB
TypeScript

import type { HostConnection } from "@/contexts/daemon-registry-context";
export type ConnectionCandidate = {
connectionId: string;
connection: HostConnection;
};
export type ConnectionProbeState =
| { status: "pending"; latencyMs: null }
| { status: "unavailable"; latencyMs: null }
| { status: "available"; latencyMs: number };
export type SelectBestConnectionInput = {
candidates: ConnectionCandidate[];
preferredConnectionId: string | null;
probeByConnectionId: Map<string, ConnectionProbeState>;
};
export function selectBestConnection(
input: SelectBestConnectionInput
): string | null {
const { candidates, preferredConnectionId, probeByConnectionId } = input;
if (candidates.length === 0) {
return null;
}
const available = candidates
.map((candidate, index) => ({ candidate, index }))
.filter(({ candidate }) => {
const probe = probeByConnectionId.get(candidate.connectionId);
return probe?.status === "available";
})
.sort((left, right) => {
const leftProbe = probeByConnectionId.get(left.candidate.connectionId);
const rightProbe = probeByConnectionId.get(right.candidate.connectionId);
const leftLatency =
leftProbe && leftProbe.status === "available"
? leftProbe.latencyMs
: Number.POSITIVE_INFINITY;
const rightLatency =
rightProbe && rightProbe.status === "available"
? rightProbe.latencyMs
: Number.POSITIVE_INFINITY;
if (leftLatency === rightLatency) {
return left.index - right.index;
}
return leftLatency - rightLatency;
});
if (available.length > 0) {
return available[0]!.candidate.connectionId;
}
const preferred = candidates.find(
(candidate) => candidate.connectionId === preferredConnectionId
);
if (preferred) {
return preferred.connectionId;
}
return candidates[0]!.connectionId;
}