Files
paseo/packages/app/src/components/multi-daemon-session-host.tsx
T
2026-02-13 05:08:26 +00:00

106 lines
2.7 KiB
TypeScript

import { SessionProvider } from "@/contexts/session-context";
import {
useDaemonRegistry,
type HostProfile,
} from "@/contexts/daemon-registry-context";
import {
buildDaemonWebSocketUrl,
buildRelayWebSocketUrl,
} from "@/utils/daemon-endpoints";
import { useMemo } from "react";
import type { ActiveConnection } from "@/contexts/daemon-connections-context";
type Candidate = {
connectionId: string;
url: string;
activeConnection: ActiveConnection;
daemonPublicKeyB64?: string;
};
function sortConnectionsByPreference<T extends { id: string }>(
connections: T[],
preferredId: string | null
): T[] {
if (!preferredId) return connections;
const idx = connections.findIndex((c) => c.id === preferredId);
if (idx === -1) return connections;
return [connections[idx]!, ...connections.slice(0, idx), ...connections.slice(idx + 1)];
}
function buildCandidates(host: HostProfile): Candidate[] {
const preferred = host.preferredConnectionId ?? null;
const direct = sortConnectionsByPreference(
host.connections.filter((c) => c.type === "direct"),
preferred
);
const relay = sortConnectionsByPreference(
host.connections.filter((c) => c.type === "relay"),
preferred
);
const out: Candidate[] = [];
for (const conn of direct) {
out.push({
connectionId: conn.id,
url: buildDaemonWebSocketUrl(conn.endpoint),
activeConnection: { type: "direct", endpoint: conn.endpoint, display: conn.endpoint },
});
}
for (const conn of relay) {
out.push({
connectionId: conn.id,
url: buildRelayWebSocketUrl({
endpoint: conn.relayEndpoint,
serverId: host.serverId,
}),
activeConnection: { type: "relay", endpoint: conn.relayEndpoint, display: "relay" },
daemonPublicKeyB64: conn.daemonPublicKeyB64,
});
}
return out;
}
function ManagedDaemonSession({ daemon }: { daemon: HostProfile }) {
const candidates = useMemo(() => buildCandidates(daemon), [daemon]);
const active =
candidates.find((candidate) => candidate.connectionId === daemon.preferredConnectionId) ??
candidates[0] ??
null;
const activeUrl = active?.url ?? null;
if (!activeUrl) {
return null;
}
return (
<SessionProvider
key={daemon.serverId}
serverUrl={activeUrl}
serverId={daemon.serverId}
activeConnection={active?.activeConnection ?? null}
daemonPublicKeyB64={active?.daemonPublicKeyB64}
>
{null}
</SessionProvider>
);
}
export function MultiDaemonSessionHost() {
const { daemons } = useDaemonRegistry();
if (daemons.length === 0) {
return null;
}
return (
<>
{daemons.map((daemon) => (
<ManagedDaemonSession key={daemon.serverId} daemon={daemon} />
))}
</>
);
}