@linxin666/dsh-ssh 0.1.15 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +16 -10
- package/lib/types/engine/connection-pool.d.ts +2 -0
- package/package.json +1 -1
- package/src/engine/connection-pool.ts +23 -12
package/lib/index.js
CHANGED
|
@@ -1352,23 +1352,24 @@ function connectClient(config) {
|
|
|
1352
1352
|
return new Promise((resolve, reject) => {
|
|
1353
1353
|
const client = new Client();
|
|
1354
1354
|
let settled = false;
|
|
1355
|
-
|
|
1355
|
+
const fail = (error) => {
|
|
1356
1356
|
if (settled) return;
|
|
1357
1357
|
settled = true;
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1358
|
+
try {
|
|
1359
|
+
client.destroy();
|
|
1360
|
+
} catch {}
|
|
1361
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
1362
|
+
};
|
|
1363
|
+
client.once("ready", () => {
|
|
1361
1364
|
if (settled) return;
|
|
1362
1365
|
settled = true;
|
|
1363
|
-
|
|
1366
|
+
resolve(client);
|
|
1364
1367
|
});
|
|
1368
|
+
client.on("error", fail);
|
|
1365
1369
|
try {
|
|
1366
1370
|
client.connect(config);
|
|
1367
1371
|
} catch (error) {
|
|
1368
|
-
|
|
1369
|
-
settled = true;
|
|
1370
|
-
reject(error instanceof Error ? error : new Error(String(error)));
|
|
1371
|
-
}
|
|
1372
|
+
fail(error);
|
|
1372
1373
|
}
|
|
1373
1374
|
});
|
|
1374
1375
|
}
|
|
@@ -1414,13 +1415,18 @@ async function connectChain(engine, entry) {
|
|
|
1414
1415
|
});
|
|
1415
1416
|
});
|
|
1416
1417
|
}
|
|
1418
|
+
let target;
|
|
1417
1419
|
try {
|
|
1420
|
+
target = await connectClient(buildConnectConfig(entry, sock));
|
|
1418
1421
|
return {
|
|
1419
|
-
client:
|
|
1422
|
+
client: target,
|
|
1420
1423
|
hops
|
|
1421
1424
|
};
|
|
1422
1425
|
} catch (error) {
|
|
1423
1426
|
for (const client of hops) client.end();
|
|
1427
|
+
if (target !== void 0) try {
|
|
1428
|
+
target.destroy();
|
|
1429
|
+
} catch {}
|
|
1424
1430
|
throw error;
|
|
1425
1431
|
}
|
|
1426
1432
|
}
|
|
@@ -48,6 +48,8 @@ export interface PoolEngine {
|
|
|
48
48
|
}
|
|
49
49
|
/** Build the ssh2 connect config for one entry (key read from disk). */
|
|
50
50
|
export declare function buildConnectConfig(entry: SshHostEntry, sock?: ConnectConfig['sock']): ConnectConfig;
|
|
51
|
+
/** Connect one ssh2 client (resolve on ready, reject on error/close). */
|
|
52
|
+
export declare function connectClient(config: ConnectConfig): Promise<Client>;
|
|
51
53
|
/** Cap captured output at the configured byte budget (marks truncation). */
|
|
52
54
|
export declare function appendOutput(target: {
|
|
53
55
|
text: string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linxin666/dsh-ssh",
|
|
3
3
|
"description": "Remote SSH operations for the dsh web GUI: host config store (~/.dsh/dsh-ssh.json, import from ~/.ssh/config), a persistent ssh2 connection pool with jump-host support, exec / PTY web terminal / SFTP transfer / local port-forward tunnels / cluster execution, plus agent tools (ssh_list, ssh_exec, ssh_upload, ssh_download, ssh_tunnel, ssh_cluster). Hot-pluggable — mounted via ~/.dsh/cordis.patch.yml + a profile node_modules symlink, no dsh source changes.",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.16",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": "^22.19.0 || >=24.0.0"
|
|
@@ -88,27 +88,31 @@ export function buildConnectConfig(entry: SshHostEntry, sock?: ConnectConfig['so
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
/** Connect one ssh2 client (resolve on ready, reject on error/close). */
|
|
91
|
-
function connectClient(config: ConnectConfig): Promise<Client> {
|
|
91
|
+
export function connectClient(config: ConnectConfig): Promise<Client> {
|
|
92
92
|
return new Promise((resolve, reject) => {
|
|
93
93
|
const client = new Client()
|
|
94
94
|
let settled = false
|
|
95
|
-
|
|
95
|
+
const fail = (error: unknown): void => {
|
|
96
96
|
if (settled) return
|
|
97
97
|
settled = true
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
try { client.destroy() } catch { /* already closed */ }
|
|
99
|
+
reject(error instanceof Error ? error : new Error(String(error)))
|
|
100
|
+
}
|
|
101
|
+
client.once('ready', () => {
|
|
101
102
|
if (settled) return
|
|
102
103
|
settled = true
|
|
103
|
-
|
|
104
|
+
resolve(client)
|
|
104
105
|
})
|
|
106
|
+
// Keep an error listener attached after the handshake: when TCP connects
|
|
107
|
+
// but the handshake drops, ssh2 can emit a second 'error' after a single
|
|
108
|
+
// once-listener is gone, which would surface as an unhandled 'error' event.
|
|
109
|
+
// The settled guard turns later emissions into a no-op; other callers
|
|
110
|
+
// (like doAcquire) attach their own error listeners and all fire together.
|
|
111
|
+
client.on('error', fail)
|
|
105
112
|
try {
|
|
106
113
|
client.connect(config)
|
|
107
114
|
} catch (error) {
|
|
108
|
-
|
|
109
|
-
settled = true
|
|
110
|
-
reject(error instanceof Error ? error : new Error(String(error)))
|
|
111
|
-
}
|
|
115
|
+
fail(error)
|
|
112
116
|
}
|
|
113
117
|
})
|
|
114
118
|
}
|
|
@@ -159,11 +163,18 @@ export async function connectChain(engine: PoolEngine, entry: SshHostEntry): Pro
|
|
|
159
163
|
})
|
|
160
164
|
})
|
|
161
165
|
}
|
|
166
|
+
let target: Client | undefined
|
|
162
167
|
try {
|
|
163
|
-
|
|
164
|
-
return { client, hops }
|
|
168
|
+
target = await connectClient(buildConnectConfig(entry, sock))
|
|
169
|
+
return { client: target, hops }
|
|
165
170
|
} catch (error) {
|
|
166
171
|
for (const client of hops) client.end()
|
|
172
|
+
// connectClient already destroys the failed target on its own failure
|
|
173
|
+
// path; destroy defensively only when a reference leaked through, and
|
|
174
|
+
// guard it so a second destroy is never an issue.
|
|
175
|
+
if (target !== undefined) {
|
|
176
|
+
try { target.destroy() } catch { /* already destroyed */ }
|
|
177
|
+
}
|
|
167
178
|
throw error
|
|
168
179
|
}
|
|
169
180
|
}
|