From d40ebd8ca8e129bcb5ddac21e427bbc0a37a0f06 Mon Sep 17 00:00:00 2001 From: pikastech Date: Sun, 19 Jul 2026 12:07:12 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=8C=89=E4=B8=8D=E6=B4=BB=E8=B7=83?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E9=99=90=E5=88=B6=20trans=20=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/src/remote-ssh.ts | 1 + scripts/src/remote.ts | 1 + scripts/src/ssh-file-transfer.test.ts | 5 ++++- scripts/src/ssh-file-transfer.ts | 10 ++++++---- scripts/src/ssh-runtime.ts | 1 + 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/scripts/src/remote-ssh.ts b/scripts/src/remote-ssh.ts index 14d280fa..272f62aa 100644 --- a/scripts/src/remote-ssh.ts +++ b/scripts/src/remote-ssh.ts @@ -924,6 +924,7 @@ async function runRemoteSshOverFrontend(session: FrontendSession, target: string const invocation = parseSshInvocation(target, normalizedArgs); if (isSshFileTransferOperation(normalizedArgs)) { const executor: SshRemoteCommandExecutor = { + streamInactivityTimeoutMs: sshRuntimeTimeoutMs(), runRemoteCommand: (remoteCommand, input) => runRemoteSshWebSocketCaptureRemoteCommand(session, invocation, remoteCommand, input), streamRemoteCommand: (remoteCommand, handlers, input, options) => runRemoteSshWebSocketStreamRemoteCommand(session, invocation, remoteCommand, handlers, input, options), }; diff --git a/scripts/src/remote.ts b/scripts/src/remote.ts index d0b9e26d..1f40c209 100644 --- a/scripts/src/remote.ts +++ b/scripts/src/remote.ts @@ -1589,6 +1589,7 @@ async function runRemoteSshOverFrontend(session: FrontendSession, target: string const invocation = parseSshInvocation(target, normalizedArgs); if (isSshFileTransferOperation(normalizedArgs)) { const executor: SshRemoteCommandExecutor = { + streamInactivityTimeoutMs: sshRuntimeTimeoutMs(), runRemoteCommand: (remoteCommand, input) => runRemoteSshWebSocketCaptureRemoteCommand(session, invocation, remoteCommand, input), streamRemoteCommand: (remoteCommand, handlers, input, options) => runRemoteSshWebSocketStreamRemoteCommand(session, invocation, remoteCommand, handlers, input, options), }; diff --git a/scripts/src/ssh-file-transfer.test.ts b/scripts/src/ssh-file-transfer.test.ts index ce947d88..403875e9 100644 --- a/scripts/src/ssh-file-transfer.test.ts +++ b/scripts/src/ssh-file-transfer.test.ts @@ -20,6 +20,7 @@ function fakeTransfer(content: Buffer): { executor: SshRemoteCommandExecutor; bu }, }, executor: { + streamInactivityTimeoutMs: 60_000, async runRemoteCommand(remoteCommand) { const command = JSON.parse(remoteCommand) as string[]; const marker = command.indexOf("unidesk-file-transfer"); @@ -153,12 +154,14 @@ describe("ssh text transfer preflight", () => { }, }; const executor: SshRemoteCommandExecutor = { + streamInactivityTimeoutMs: 60_000, async runRemoteCommand(remoteCommand) { commands.push(remoteCommand); return { exitCode: 0, stdout: `${content.length} ${sha256}\n`, stderr: "" }; }, - async streamRemoteCommand(remoteCommand, handlers) { + async streamRemoteCommand(remoteCommand, handlers, _input, options) { commands.push(remoteCommand); + expect(options?.inactivityTimeoutMs).toBe(60_000); await handlers.onStdout(content); return { exitCode: 0, stdout: "", stderr: "" }; }, diff --git a/scripts/src/ssh-file-transfer.ts b/scripts/src/ssh-file-transfer.ts index 3e90e3b9..981c39d5 100644 --- a/scripts/src/ssh-file-transfer.ts +++ b/scripts/src/ssh-file-transfer.ts @@ -11,6 +11,7 @@ export interface SshRemoteCommandStreamHandlers { } export interface SshRemoteCommandExecutor { + streamInactivityTimeoutMs: number; runRemoteCommand(remoteCommand: string, input?: string): Promise; streamRemoteCommand?( remoteCommand: string, @@ -98,7 +99,8 @@ class SshFileTransferError extends Error { const fileTransferWriteB64ArgvLimit = 48_000; const fileTransferWriteRawChunkBytes = 3 * 1024 * 1024; const fileTransferWriteB64ChunkChars = 1_398_104; -const fileTransferProgressEveryChunks = 16; +const fileTransferUploadProgressEveryChunks = 16; +const fileTransferDownloadProgressEveryChunks = 256; const knownTextExtensions = new Set([ ".bat", ".bib", ".c", ".cc", ".cfg", ".cmd", ".conf", ".cpp", ".css", ".csv", ".cts", ".cxx", @@ -412,7 +414,7 @@ async function downloadRemoteFileVerified( hash.update(chunk); emitDownloadProgress(invocation, remotePath, chunkCount, actualBytes, remote.bytes, chunk.length, startedAtMs); }, - }, undefined, { inactivityTimeoutMs }); + }, undefined, { inactivityTimeoutMs: inactivityTimeoutMs ?? executor.streamInactivityTimeoutMs }); await closeWriteStream(output); if (result.exitCode !== 0) { throw new SshFileTransferError("remote ssh download stream failed", { @@ -512,7 +514,7 @@ function emitDownloadProgress( startedAtMs: number, force = false, ): void { - if (!force && chunkCount !== 1 && actualBytes < expectedBytes && chunkCount % fileTransferProgressEveryChunks !== 0) return; + if (!force && chunkCount !== 1 && actualBytes < expectedBytes && chunkCount % fileTransferDownloadProgressEveryChunks !== 0) return; const elapsedMs = Math.max(1, Date.now() - startedAtMs); process.stderr.write(`${JSON.stringify({ event: "unidesk.ssh.download.progress", @@ -544,7 +546,7 @@ function emitUploadProgress( startedAtMs: number, force = false, ): void { - if (!force && chunkCount !== 1 && actualBytes < expectedBytes && chunkCount % fileTransferProgressEveryChunks !== 0) return; + if (!force && chunkCount !== 1 && actualBytes < expectedBytes && chunkCount % fileTransferUploadProgressEveryChunks !== 0) return; const elapsedMs = Math.max(1, Date.now() - startedAtMs); process.stderr.write(`${JSON.stringify({ event: "unidesk.ssh.upload.progress", diff --git a/scripts/src/ssh-runtime.ts b/scripts/src/ssh-runtime.ts index 4432f2c2..8f5a89ec 100644 --- a/scripts/src/ssh-runtime.ts +++ b/scripts/src/ssh-runtime.ts @@ -1422,6 +1422,7 @@ export async function runSsh(config: UniDeskConfig, providerId: string, args: st const operationName = normalizedArgs[0] ?? ""; if (isSshFileTransferOperation(normalizedArgs)) { const executor: SshRemoteCommandExecutor = { + streamInactivityTimeoutMs: sshRuntimeTimeoutMs(), runRemoteCommand: (remoteCommand, input) => runSshCaptureRemoteCommand(config, invocation, remoteCommand, input), streamRemoteCommand: (remoteCommand, handlers, input, options) => runSshStreamRemoteCommand(config, invocation, remoteCommand, handlers, input, options), };