mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-08-29 18:31:33 +00:00
115 lines
3.2 KiB
TypeScript
115 lines
3.2 KiB
TypeScript
import { isElectron } from "@/lib/electron";
|
|
|
|
export type ConnectionOrigin = "local" | "remote";
|
|
|
|
interface OriginResolvableHost {
|
|
connectionType?: string | null;
|
|
connectionOrigin?: ConnectionOrigin | null;
|
|
}
|
|
|
|
/**
|
|
* Resolves which backend a given host's interactive connection (SSH,
|
|
* Docker console, Serial) should dial: the desktop app's embedded local
|
|
* backend, or a connected remote sync server.
|
|
*
|
|
* RDP/VNC/Telnet always resolve to "remote" -- guacd isn't bundled with the
|
|
* embedded backend. Serial always resolves to "local" -- the hardware is
|
|
* physically attached to this desktop machine. Everything else follows the
|
|
* host's own override if set, falling back to the desktop-wide default.
|
|
*/
|
|
export async function resolveConnectionOrigin(
|
|
host: OriginResolvableHost,
|
|
): Promise<ConnectionOrigin> {
|
|
if (
|
|
host.connectionType === "rdp" ||
|
|
host.connectionType === "vnc" ||
|
|
host.connectionType === "telnet"
|
|
) {
|
|
return "remote";
|
|
}
|
|
if (host.connectionType === "serial") {
|
|
return "local";
|
|
}
|
|
if (!isElectron()) {
|
|
return "local";
|
|
}
|
|
if (host.connectionOrigin === "local" || host.connectionOrigin === "remote") {
|
|
return host.connectionOrigin;
|
|
}
|
|
|
|
try {
|
|
const settings = (await window.electronAPI?.invoke?.(
|
|
"get-desktop-settings",
|
|
)) as { defaultConnectionOrigin?: ConnectionOrigin } | null;
|
|
return settings?.defaultConnectionOrigin === "remote" ? "remote" : "local";
|
|
} catch {
|
|
return "local";
|
|
}
|
|
}
|
|
|
|
export interface RemoteConnectionTarget {
|
|
serverUrl: string;
|
|
jwt: string | null;
|
|
}
|
|
|
|
async function getRemoteConnectionTarget(): Promise<RemoteConnectionTarget | null> {
|
|
try {
|
|
const [config, jwt] = await Promise.all([
|
|
window.electronAPI?.invoke?.("get-remote-sync-config") as Promise<{
|
|
serverUrl?: string;
|
|
} | null>,
|
|
window.electronAPI?.invoke?.("get-remote-sync-jwt") as Promise<
|
|
string | null
|
|
>,
|
|
]);
|
|
if (!config?.serverUrl) return null;
|
|
return { serverUrl: config.serverUrl, jwt: jwt ?? null };
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Builds the base WebSocket URL for an interactive connection protocol,
|
|
* given a resolved origin. Returns null when origin is "remote" but no
|
|
* remote server is connected -- callers must show a blocking message
|
|
* rather than attempting to connect.
|
|
*/
|
|
export async function buildOriginWsUrl({
|
|
origin,
|
|
localPort,
|
|
localPath,
|
|
remotePath,
|
|
includeJwt = true,
|
|
}: {
|
|
origin: ConnectionOrigin;
|
|
localPort: number;
|
|
localPath: string;
|
|
remotePath: string;
|
|
includeJwt?: boolean;
|
|
}): Promise<string | null> {
|
|
if (origin === "local") {
|
|
let url = `ws://127.0.0.1:${localPort}${localPath}`;
|
|
if (includeJwt) {
|
|
const token = localStorage.getItem("jwt");
|
|
if (token) url += `?token=${encodeURIComponent(token)}`;
|
|
}
|
|
return url;
|
|
}
|
|
|
|
const remote = await getRemoteConnectionTarget();
|
|
if (!remote) return null;
|
|
|
|
const wsProtocol = remote.serverUrl.startsWith("https://")
|
|
? "wss://"
|
|
: "ws://";
|
|
const wsHost = remote.serverUrl
|
|
.replace(/^https?:\/\//, "")
|
|
.replace(/\/$/, "");
|
|
let url = `${wsProtocol}${wsHost}${remotePath}`;
|
|
if (includeJwt && remote.jwt) {
|
|
url += `?token=${encodeURIComponent(remote.jwt)}`;
|
|
}
|
|
return url;
|
|
}
|