feat(FTP Node): Add support for concurrent reads when using SFTP (#17896)

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: Michael Kret <michael.k@radency.com>
This commit is contained in:
Jon
2025-08-04 12:40:18 +01:00
committed by GitHub
parent 508c636c2c
commit e437dace70
3 changed files with 94 additions and 18 deletions

View File

@@ -289,7 +289,50 @@ export class Ftp implements INodeType {
hint: 'The name of the output binary field to put the file in',
required: true,
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
operation: ['download'],
},
},
options: [
{
displayName: 'Enable Concurrent Reads',
name: 'enableConcurrentReads',
type: 'boolean',
default: false,
description: 'Whether to enable concurrent reads for downloading files',
},
{
displayName: 'Max Concurrent Reads',
name: 'maxConcurrentReads',
type: 'number',
default: 5,
displayOptions: {
show: {
enableConcurrentReads: [true],
},
},
},
{
displayName: 'Chunk Size',
name: 'chunkSize',
type: 'number',
default: 64,
description: 'Size of each chunk in KB to download, Not all servers support this',
displayOptions: {
show: {
enableConcurrentReads: [true],
},
},
},
],
},
// ----------------------------------
// rename
// ----------------------------------
@@ -530,6 +573,10 @@ export class Ftp implements INodeType {
password: (credentials.password as string) || undefined,
privateKey: formatPrivateKey(credentials.privateKey as string),
passphrase: credentials.passphrase as string | undefined,
readyTimeout: 10000,
algorithms: {
compress: ['zlib@openssh.com', 'zlib', 'none'],
},
});
} else {
await sftp.connect({
@@ -537,6 +584,10 @@ export class Ftp implements INodeType {
port: credentials.port as number,
username: credentials.username as string,
password: credentials.password as string,
readyTimeout: 10000,
algorithms: {
compress: ['zlib@openssh.com', 'zlib', 'none'],
},
});
}
} else {
@@ -632,9 +683,21 @@ export class Ftp implements INodeType {
if (operation === 'download') {
const path = this.getNodeParameter('path', i) as string;
const options = this.getNodeParameter('options', i);
const binaryFile = await tmpFile({ prefix: 'n8n-sftp-' });
try {
await sftp!.get(path, createWriteStream(binaryFile.path));
if (!options.enableConcurrentReads) {
await sftp!.get(path, createWriteStream(binaryFile.path));
} else {
await sftp!.fastGet(path, binaryFile.path, {
concurrency:
options.maxConcurrentReads === undefined
? 5
: Number(options.maxConcurrentReads),
chunkSize:
(options.chunkSize === undefined ? 64 : Number(options.chunkSize)) * 1024,
});
}
const dataPropertyNameDownload = this.getNodeParameter('binaryPropertyName', i);
const remoteFilePath = this.getNodeParameter('path', i) as string;

View File

@@ -871,7 +871,7 @@
"@types/rfc2047": "^2.0.1",
"@types/sanitize-html": "^2.11.0",
"@types/showdown": "^1.9.4",
"@types/ssh2-sftp-client": "^5.1.0",
"@types/ssh2-sftp-client": "^9.0.5",
"@types/uuid": "catalog:",
"@types/xml2js": "catalog:",
"eslint-plugin-n8n-nodes-base": "^1.16.3",
@@ -943,7 +943,7 @@
"showdown": "2.1.0",
"simple-git": "3.17.0",
"snowflake-sdk": "2.1.0",
"ssh2-sftp-client": "7.2.3",
"ssh2-sftp-client": "12.0.1",
"tmp-promise": "3.0.3",
"ts-ics": "1.2.2",
"uuid": "catalog:",