mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-30 15:15:24 +00:00
feat: ship the ssh terminal as a first-party in-process plugin
Adds a hardcoded process:transport-owner tier so the terminal can own its WebSocket server and ssh2 clients, which cannot cross the worker boundary.
This commit is contained in:
1 parent
e040b12045
commit
c94a453f1e
43 files changed
+2426
-38
No files matched your search
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* SSH Terminal - first-party, in-process plugin.
|
||||
*
|
||||
* This plugin runs on the main thread rather than in a worker, because it IS
|
||||
* the SSH transport rather than a consumer of one: it owns a WebSocket server
|
||||
* and long-lived ssh2 clients, and neither a live socket nor an ssh2 Client can
|
||||
* cross the structured-clone postMessage boundary a worker plugin talks over.
|
||||
* See src/backend/plugins/first-party.ts for why that tier is a hardcoded
|
||||
* allowlist and not something a manifest can ask for.
|
||||
*
|
||||
* The terminal's implementation stays in core (src/backend/hosts/terminal/)
|
||||
* rather than being copied in here. Two reasons:
|
||||
* - session-manager has six consumers outside the terminal (terminal routes,
|
||||
* open-tabs, user-image-storage, collab, and session-sharing twice), so it
|
||||
* is shared infrastructure, not plugin-private code.
|
||||
* - the terminal needs plaintext host credentials to connect, which ctx.hosts
|
||||
* deliberately never returns (PluginHostView is a 13-field allowlist that
|
||||
* excludes password, key and passphrase).
|
||||
*
|
||||
* What this plugin owns is the lifecycle: enabling it starts the WS server,
|
||||
* disabling it closes live sessions and frees the port.
|
||||
*/
|
||||
|
||||
import { createRequire } from "node:module";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
/**
|
||||
* Resolves the compiled core terminal module.
|
||||
*
|
||||
* The plugin ships beside dist/backend, so in a built server the module is at
|
||||
* dist/backend/backend/hosts/terminal/index.js. Under vitest and dev the
|
||||
* plugin is loaded from the repo instead, where the source .ts is the thing
|
||||
* that exists and tsx is already handling it.
|
||||
*/
|
||||
async function loadTerminalModule() {
|
||||
const here = path.dirname(fileURLToPath(import.meta.url));
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
const candidates = [
|
||||
// Built: plugins/ssh-terminal/backend -> dist/backend/backend/...
|
||||
path.resolve(here, "../../../backend/backend/hosts/terminal/index.js"),
|
||||
// Repo layout, compiled output present.
|
||||
path.resolve(here, "../../../dist/backend/backend/hosts/terminal/index.js"),
|
||||
// Repo layout, running from source under tsx.
|
||||
path.resolve(here, "../../../src/backend/hosts/terminal/index.ts"),
|
||||
];
|
||||
|
||||
for (const candidate of candidates) {
|
||||
try {
|
||||
require.resolve(candidate);
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
return import(new URL(`file://${candidate.replace(/\\/g, "/")}`).href);
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`ssh-terminal could not locate the terminal module. Looked in:\n ${candidates.join("\n ")}`,
|
||||
);
|
||||
}
|
||||
|
||||
let terminal = null;
|
||||
|
||||
export async function activate(ctx) {
|
||||
terminal = await loadTerminalModule();
|
||||
|
||||
await terminal.startTerminalServer();
|
||||
|
||||
// Published so collab and session-sharing can reach live sessions without
|
||||
// importing a plugin. Revoked automatically when this plugin is disabled.
|
||||
ctx.registry.provide("terminal.sessions", terminal.sessionManager ?? null);
|
||||
|
||||
ctx.log.info(
|
||||
`SSH terminal listening on ${terminal.TERMINAL_WS_PORT ?? 30002}`,
|
||||
);
|
||||
}
|
||||
|
||||
export async function deactivate() {
|
||||
if (!terminal) return;
|
||||
await terminal.stopTerminalServer();
|
||||
terminal = null;
|
||||
}
|
||||
Reference in new issue
Block a user