mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-29 22:55:24 +00:00
feat: finish the remote-desktop plugin (B14)
This commit is contained in:
1 parent
0af2c94983
commit
14eb558b85
215 files changed
+30029
-3921
No files matched your search
@@ -1,4 +1,3 @@
|
||||
import type { GuacamoleConfig } from "@/types/guacamole-config";
|
||||
import type { TerminalConfig } from "@/types";
|
||||
|
||||
export type TerminalDefaults = Partial<
|
||||
@@ -20,8 +19,6 @@ export type TerminalDefaults = Partial<
|
||||
>
|
||||
>;
|
||||
|
||||
export type RemoteDesktopDefaults = Partial<GuacamoleConfig>;
|
||||
|
||||
function parseObject<T extends object>(value?: string | null): Partial<T> {
|
||||
if (!value) return {};
|
||||
try {
|
||||
@@ -38,12 +35,6 @@ export function parseTerminalDefaults(value?: string | null): TerminalDefaults {
|
||||
return parseObject<TerminalDefaults>(value);
|
||||
}
|
||||
|
||||
export function parseRemoteDesktopDefaults(
|
||||
value?: string | null,
|
||||
): RemoteDesktopDefaults {
|
||||
return parseObject<RemoteDesktopDefaults>(value);
|
||||
}
|
||||
|
||||
// Booleans have three states in the defaults UI: unset means the host decides.
|
||||
export type TriState = "inherit" | "on" | "off";
|
||||
|
||||
|
||||
@@ -4,12 +4,9 @@ import { websocketAuthProtocols } from "@/lib/ws-auth";
|
||||
export type ConnectionOrigin = "local" | "remote";
|
||||
|
||||
interface OriginResolvableHost {
|
||||
connectionType?: string | null;
|
||||
connectionOrigin?: ConnectionOrigin | null;
|
||||
}
|
||||
|
||||
const GUACAMOLE_CONNECTION_TYPES = new Set(["rdp", "vnc", "telnet"]);
|
||||
|
||||
/**
|
||||
* Resolves which backend a given host's interactive connection (SSH, Docker
|
||||
* console, RDP/VNC/Telnet) should dial: the desktop app's embedded local
|
||||
@@ -21,16 +18,16 @@ const GUACAMOLE_CONNECTION_TYPES = new Set(["rdp", "vnc", "telnet"]);
|
||||
* Everything else follows the host's own override if set, falling back to
|
||||
* the desktop-wide default.
|
||||
*
|
||||
* RDP/VNC/Telnet are the exception to that fallback: left on Default they
|
||||
* resolve to "remote" rather than following the desktop-wide setting. They
|
||||
* need a guacd, which the desktop does not ship, so originating them here
|
||||
* only works once the user has pointed Termix at one of their own (the
|
||||
* global guacd URL setting, or a host's guacd Proxy override). Making that
|
||||
* opt-in per host keeps an upgrade from moving working connections onto a
|
||||
* guacd that isn't there -- see Termix-SSH/Support#1240.
|
||||
* `defaultRemote` makes a host left on Default resolve to "remote" instead of
|
||||
* following the desktop-wide setting. Remote desktop passes it: it needs a
|
||||
* guacd, which the desktop does not ship, so originating it here only works
|
||||
* once the user has pointed Termix at one of their own. Making that opt-in
|
||||
* per host keeps an upgrade from moving working connections onto a guacd
|
||||
* that isn't there -- see Termix-SSH/Support#1240.
|
||||
*/
|
||||
export async function resolveConnectionOrigin(
|
||||
host: OriginResolvableHost,
|
||||
options: { defaultRemote?: boolean } = {},
|
||||
): Promise<ConnectionOrigin> {
|
||||
if (!isElectron()) {
|
||||
return "local";
|
||||
@@ -38,7 +35,7 @@ export async function resolveConnectionOrigin(
|
||||
if (host.connectionOrigin === "local" || host.connectionOrigin === "remote") {
|
||||
return host.connectionOrigin;
|
||||
}
|
||||
if (GUACAMOLE_CONNECTION_TYPES.has(host.connectionType ?? "")) {
|
||||
if (options.defaultRemote) {
|
||||
return "remote";
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
import type { AxiosInstance } from "axios";
|
||||
import { authApi } from "@/main-axios";
|
||||
import { authApi, createRemoteOriginApiInstance } from "@/main-axios";
|
||||
import { getBasePath } from "@/lib/base-path";
|
||||
import { isElectron } from "@/lib/electron";
|
||||
import { websocketAuthProtocols } from "@/lib/ws-auth";
|
||||
@@ -75,6 +75,27 @@ export function createPluginApi(pluginId: string): AxiosInstance {
|
||||
}) as AxiosInstance;
|
||||
}
|
||||
|
||||
const remotePluginApis = new Map<string, AxiosInstance>();
|
||||
|
||||
/**
|
||||
* The same client pointed at the connected remote server, for a desktop app
|
||||
* host whose connection origin is "remote". Outside Electron, and for
|
||||
* "local", it is the ordinary client.
|
||||
*/
|
||||
export function pluginApiFor(
|
||||
pluginId: string,
|
||||
origin: ConnectionOrigin | undefined,
|
||||
local: AxiosInstance,
|
||||
): AxiosInstance {
|
||||
if (origin !== "remote" || !isElectron()) return local;
|
||||
let client = remotePluginApis.get(pluginId);
|
||||
if (!client) {
|
||||
client = createRemoteOriginApiInstance(pluginApiPath(pluginId));
|
||||
remotePluginApis.set(pluginId, client);
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* pluginWsUrl for a path a backend handed out ("/plugin-ws/<id>/<path>?q"),
|
||||
* so a caller can dial a plugin's socket without naming the plugin.
|
||||
|
||||
Reference in new issue
Block a user