mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-30 23:25:24 +00:00
feat: convert ssh tunnels into a plugin
This commit is contained in:
1 parent
c85c1fdb86
commit
1682861853
220 files changed
+36928
-11374
No files matched your search
@@ -433,7 +433,10 @@ and `session.remoteDisplay`. `host-metrics.managers` (component slot,
|
||||
**B3**) is host-metrics's own: tailscale contributes its manager card there
|
||||
instead of host-metrics knowing tailscale exists, and host-metrics works with
|
||||
or without tailscale enabled. Cross-plugin frontend calls go through actions:
|
||||
`automations.list`, `fleets.list`, `session.remoteDisplay.token`.
|
||||
`automations.list`, `fleets.list`, `session.remoteDisplay.token`. Core calls
|
||||
plugin actions the same way when a core view shows a plugin's data:
|
||||
`files.openHost`, and **B7**'s `tunnels.statuses` and `tunnels.open` behind the
|
||||
dashboard's active tunnel counter, which reads as zero while tunnels is off.
|
||||
|
||||
**B2** added a live-terminal-session surface, for a plugin that needs to push
|
||||
resolved text into an open SSH session rather than just fill a slot with a
|
||||
@@ -499,6 +502,15 @@ the caller. The workspaces plugin provides `workspaces.saved` (`list()`), which
|
||||
the AI assistant's `list_workspaces` tool reaches through an optional entry in
|
||||
its `requires`, answering `unavailable: true` while workspaces is off.
|
||||
|
||||
**B7**'s `tunnels.access` is the first service with a hard consumer:
|
||||
web-endpoint lists tunnels in `dependencies` and a non-optional `requires`,
|
||||
because its tunnel endpoints cannot work without it, while automations keeps
|
||||
it optional for its one tunnel step. `forward()` resolves only once the
|
||||
forward is listening and the target answered a probe, so a caller never has
|
||||
to poll the plugin's state. A plugin can also listen for another plugin's
|
||||
`plugin.<id>.*` events without any capability: automations turns
|
||||
`plugin.tunnels.tunnel_disconnected` into its `tunnel_disconnected` trigger.
|
||||
|
||||
### 10. Lifecycle
|
||||
|
||||
`activate(ctx)` creates all state. Everything registered through `ctx` or `app`
|
||||
@@ -1076,6 +1088,13 @@ connect pipeline instead of importing ssh2 helpers from core:
|
||||
since the file-manager plugin's interactive connect route and its dedicated
|
||||
transfer sessions both need their own keepalive/timeout defaults rather than
|
||||
falling back to the generic `"plugin"` purpose.
|
||||
- **B7** added `sock` to the connect options: an already-open stream to the
|
||||
host, such as a `forwardOut` channel through another host. `connect` then
|
||||
skips the transport step (port knocking, proxy, jump hosts, DNS) and runs
|
||||
the host key check and auth over that stream. The tunnels plugin opens the
|
||||
endpoint leg of a source-to-endpoint tunnel this way, so both legs go
|
||||
through the pipeline; before B7 tunnels built their own ssh2 `Client` and
|
||||
never checked host keys at all.
|
||||
|
||||
Each new connection is audited and runs as the current actor; pooled reuse is
|
||||
not. Connections and pool entries are closed on deactivate.
|
||||
@@ -1644,10 +1663,12 @@ Known specifics:
|
||||
degrade silently when automations is absent, so host-metrics declares it as
|
||||
an `optionalDependency` (added in A2; it previously declared nothing, and
|
||||
the loader had no reason to order the two).
|
||||
- Core feature servers that are not plugins yet still own ports: tunnel 30003,
|
||||
dashboard 30006, tmux 30010, serial 30011 and homepage 30012. Each keeps its
|
||||
nginx block until its own Phase B step. No plugin owns a port any more (A4).
|
||||
**B6** moved file-manager off port 30004 onto `/plugin-api/file-manager/`.
|
||||
- Core feature servers that are not plugins yet still own ports: dashboard
|
||||
30006, tmux 30010, serial 30011 and homepage 30012. Each keeps its nginx
|
||||
block until its own Phase B step. No plugin owns a port any more (A4).
|
||||
**B6** moved file-manager off port 30004 onto `/plugin-api/file-manager/`,
|
||||
and **B7** moved tunnels off port 30003 onto `/plugin-api/tunnels/` and
|
||||
`/plugin-ws/tunnels/c2s/stream`.
|
||||
- The terminal component and `TerminalTabContent` stay in core until the
|
||||
terminal's Phase B step (session manager, split view). ssh-terminal
|
||||
registers them through the legacy alias; **B6** switched every core caller
|
||||
|
||||
@@ -80,3 +80,33 @@ build`'s esbuild step has no static-asset-copy pipeline the way core's Vite
|
||||
dialect, `schema:generate`) is real, separate work this step didn't
|
||||
attempt, since none of those reads block the plugin conversion itself.
|
||||
Owner: a dedicated follow-up step, or D0.
|
||||
- **B7 (tunnels):** `enable_tunnel` and `tunnel_connections` are still live
|
||||
`ssh_data` columns; only the copy-into-plugin-settings migration shipped
|
||||
(`tunnels-settings-migration.ts`), and the plugin reads its host settings
|
||||
now. Core still carries the columns through the host routes, the
|
||||
encrypt/decrypt round trip, `SidebarTree.tsx`'s host duplicate payload, the
|
||||
quick-connect mapping and the `Host`/`SSHHost` types, none of which the
|
||||
plugin reads any more. Dropping them in lockstep (`schema.ts`, `db/index.ts`,
|
||||
a drizzle migration per dialect, `schema:generate`) is the same follow-up the
|
||||
B6 file-manager line above describes. Owner: a dedicated follow-up step, or D0.
|
||||
- **B7 (tunnels):** host export/import, host duplicate, the Hosts panel
|
||||
feature filter and the bulk enable/disable menu all work off `ssh_data`
|
||||
columns, so none of them can see a plugin's host settings. For tunnels the
|
||||
"Tunnel" filter and the bulk enable/disable entries were removed, and the
|
||||
export's "Tunnels" group became "Proxy" (SOCKS5 fields only) since
|
||||
`tunnelConnections` there is now stale. Bringing these back needs a way for
|
||||
core to read and write host-scope plugin settings generically (keyed off
|
||||
`contributes.settings.host` or `hostCapability`) rather than per column.
|
||||
Owner: D1.
|
||||
- **B7 (tunnels):** the tunnel tab no longer writes a recent-activity entry:
|
||||
`logActivity` is a core `@/main-axios` call and the plugin imports nothing
|
||||
from `@/`. Old "tunnel" entries still reopen the tab through the plugin's
|
||||
`activityTypes`. An `app.logActivity` (or equivalent bridge member) would
|
||||
restore it for this plugin and let docker, file-manager and host-metrics drop
|
||||
their own `@/main-axios` import for it too. Owner: D1.
|
||||
- **B7 (tunnels):** on the desktop app, tunnel statuses from a connected
|
||||
remote server are no longer merged into the tab: the old code polled the
|
||||
remote tunnel service through `getRemoteTunnelApi()`, and the SDK has no
|
||||
remote-origin plugin API client. `subscribeTunnelStatuses` already takes a
|
||||
`fetchRemote` and merges with local statuses winning, so it only needs a
|
||||
client for `/plugin-api/tunnels/status` on the remote server. Owner: D1.
|
||||
@@ -661,6 +661,12 @@ export interface PluginSshConnectOptions {
|
||||
prompt?: PluginSshPromptChannel;
|
||||
/** Config fields to force, e.g. a longer readyTimeout. */
|
||||
overrides?: Record<string, unknown>;
|
||||
/**
|
||||
* An already-open stream to the host, such as a forwardOut channel through
|
||||
* another host. The transport step is skipped: no port knocking, proxy,
|
||||
* jump hosts or DNS lookup. Host key checks and auth still run.
|
||||
*/
|
||||
sock?: unknown;
|
||||
}
|
||||
|
||||
export interface PluginSshConnection<Client = unknown> {
|
||||
|
||||
@@ -22,6 +22,7 @@ import type {
|
||||
PluginLoginMethod,
|
||||
PluginSecondFactor,
|
||||
PluginSshAuthProvider,
|
||||
PluginSshConnectOptions,
|
||||
PluginSshHost,
|
||||
PluginHostSummary,
|
||||
PluginHostRecord,
|
||||
@@ -94,7 +95,11 @@ export interface FakePluginContext {
|
||||
/** Core settings readable through ctx.settings.readCore. */
|
||||
coreSettings: Map<string, string>;
|
||||
/** Every ctx.ssh.connect and withConnection call, in order. */
|
||||
sshConnections: Array<{ host: number | PluginSshHost; pool?: string }>;
|
||||
sshConnections: Array<{
|
||||
host: number | PluginSshHost;
|
||||
pool?: string;
|
||||
options?: PluginSshConnectOptions;
|
||||
}>;
|
||||
/** Every ctx.hosts.share call, in order. */
|
||||
hostShares: Array<{
|
||||
hostId: number;
|
||||
@@ -467,8 +472,8 @@ export function createFakeContext(
|
||||
},
|
||||
|
||||
ssh: {
|
||||
connect: async (host) => {
|
||||
sshConnections.push({ host });
|
||||
connect: async (host, connectOptions) => {
|
||||
sshConnections.push({ host, options: connectOptions });
|
||||
return {
|
||||
client: sshClient as never,
|
||||
jumpClient: null,
|
||||
|
||||
Reference in new issue
Block a user