ssh2-sftp-client 6.0.1 → 7.0.0
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/CHANGELOG.org +8 -1
- package/README.md +90 -106
- package/README.org +64 -93
- package/package.json +8 -7
- package/src/index.js +218 -203
- package/src/utils.js +41 -15
package/src/index.js
CHANGED
|
@@ -4,20 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
'use strict';
|
|
6
6
|
|
|
7
|
-
const {Client} = require('ssh2');
|
|
7
|
+
const { Client } = require('ssh2');
|
|
8
8
|
const fs = require('fs');
|
|
9
9
|
const concat = require('concat-stream');
|
|
10
10
|
const promiseRetry = require('promise-retry');
|
|
11
|
-
const {join, parse} = require('path');
|
|
11
|
+
const { join, parse } = require('path');
|
|
12
12
|
const {
|
|
13
13
|
fmtError,
|
|
14
14
|
addTempListeners,
|
|
15
15
|
removeTempListeners,
|
|
16
16
|
haveConnection,
|
|
17
17
|
normalizeRemotePath,
|
|
18
|
-
localExists
|
|
18
|
+
localExists,
|
|
19
19
|
} = require('./utils');
|
|
20
|
-
const {errorCode} = require('./constants');
|
|
20
|
+
const { errorCode } = require('./constants');
|
|
21
21
|
|
|
22
22
|
class SftpClient {
|
|
23
23
|
constructor(clientName) {
|
|
@@ -32,21 +32,30 @@ class SftpClient {
|
|
|
32
32
|
|
|
33
33
|
this.client.on('close', () => {
|
|
34
34
|
if (!this.endCalled) {
|
|
35
|
-
this.debugMsg(
|
|
35
|
+
this.debugMsg(
|
|
36
|
+
`${this.clientName}: Unexpected close event raised by server`
|
|
37
|
+
);
|
|
36
38
|
this.sftp = undefined;
|
|
37
39
|
}
|
|
38
40
|
});
|
|
41
|
+
|
|
39
42
|
this.client.on('end', () => {
|
|
40
43
|
if (!this.endCalled) {
|
|
41
|
-
this.debugMsg(
|
|
44
|
+
this.debugMsg(
|
|
45
|
+
`${this.clientName}: Unexpected end event raised by server`
|
|
46
|
+
);
|
|
42
47
|
this.sftp = undefined;
|
|
43
48
|
}
|
|
44
49
|
});
|
|
50
|
+
|
|
45
51
|
this.client.on('error', (err) => {
|
|
46
52
|
if (!this.errorHandled) {
|
|
53
|
+
this.debugMsg(
|
|
54
|
+
`${this.clientName}: Global Error Handler: ${err.message}`
|
|
55
|
+
);
|
|
47
56
|
throw fmtError(
|
|
48
57
|
`Unexpected error: ${err.message}`,
|
|
49
|
-
|
|
58
|
+
`${this.clientName}: global error handler`,
|
|
50
59
|
err.code
|
|
51
60
|
);
|
|
52
61
|
} else {
|
|
@@ -97,28 +106,37 @@ class SftpClient {
|
|
|
97
106
|
* @return {Promise} which will resolve to an sftp client object
|
|
98
107
|
*
|
|
99
108
|
*/
|
|
100
|
-
|
|
101
|
-
let
|
|
102
|
-
|
|
109
|
+
getConnection(config) {
|
|
110
|
+
let doReady;
|
|
103
111
|
return new Promise((resolve, reject) => {
|
|
104
112
|
addTempListeners(this, 'sftpConnect', reject);
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if (err) {
|
|
108
|
-
this.debugMsg(`SFTP channel error: ${err.message} ${err.code}`);
|
|
109
|
-
reject(fmtError(err, 'sftpConnect', err.code));
|
|
110
|
-
} else {
|
|
111
|
-
this.debugMsg('SFTP channel established');
|
|
112
|
-
resolve(sftp);
|
|
113
|
-
}
|
|
114
|
-
});
|
|
113
|
+
doReady = () => {
|
|
114
|
+
resolve(true);
|
|
115
115
|
};
|
|
116
|
-
|
|
117
|
-
this.client.
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
116
|
+
this.client.on('ready', doReady);
|
|
117
|
+
this.client.connect(config);
|
|
118
|
+
})
|
|
119
|
+
.catch((err) => {
|
|
120
|
+
return Promise.reject(err);
|
|
121
|
+
})
|
|
122
|
+
.finally((resp) => {
|
|
123
|
+
this.removeListener('ready', doReady);
|
|
124
|
+
removeTempListeners(this);
|
|
125
|
+
return resp;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
getSftpChannel() {
|
|
130
|
+
return new Promise((resolve, reject) => {
|
|
131
|
+
this.client.sftp((err, sftp) => {
|
|
132
|
+
if (err) {
|
|
133
|
+
this.debugMsg(`SFTP Channel Error: ${err.message}`);
|
|
134
|
+
reject(fmtError(err, 'getSftpChannel', err.code));
|
|
135
|
+
} else {
|
|
136
|
+
this.sftp = sftp;
|
|
137
|
+
resolve(sftp);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
122
140
|
});
|
|
123
141
|
}
|
|
124
142
|
|
|
@@ -140,17 +158,17 @@ class SftpClient {
|
|
|
140
158
|
return promiseRetry(
|
|
141
159
|
(retry, attempt) => {
|
|
142
160
|
this.debugMsg(`Connect attempt ${attempt}`);
|
|
143
|
-
return this.
|
|
161
|
+
return this.getConnection(config).catch((err) => {
|
|
144
162
|
retry(err);
|
|
145
163
|
});
|
|
146
164
|
},
|
|
147
165
|
{
|
|
148
166
|
retries: config.retries || 1,
|
|
149
167
|
factor: config.retry_factor || 2,
|
|
150
|
-
minTimeout: config.retry_minTimeout || 1000
|
|
168
|
+
minTimeout: config.retry_minTimeout || 1000,
|
|
151
169
|
}
|
|
152
|
-
).then((
|
|
153
|
-
this.
|
|
170
|
+
).then(() => {
|
|
171
|
+
return this.getSftpChannel();
|
|
154
172
|
});
|
|
155
173
|
}
|
|
156
174
|
|
|
@@ -187,7 +205,7 @@ class SftpClient {
|
|
|
187
205
|
});
|
|
188
206
|
}
|
|
189
207
|
}).finally((rsp) => {
|
|
190
|
-
removeTempListeners(this
|
|
208
|
+
removeTempListeners(this);
|
|
191
209
|
return rsp;
|
|
192
210
|
});
|
|
193
211
|
}
|
|
@@ -238,12 +256,12 @@ class SftpClient {
|
|
|
238
256
|
isCharacterDevice: stats.isCharacterDevice(),
|
|
239
257
|
isSymbolicLink: stats.isSymbolicLink(),
|
|
240
258
|
isFIFO: stats.isFIFO(),
|
|
241
|
-
isSocket: stats.isSocket()
|
|
259
|
+
isSocket: stats.isSocket(),
|
|
242
260
|
});
|
|
243
261
|
}
|
|
244
262
|
});
|
|
245
263
|
}).finally((rsp) => {
|
|
246
|
-
removeTempListeners(this
|
|
264
|
+
removeTempListeners(this);
|
|
247
265
|
return rsp;
|
|
248
266
|
});
|
|
249
267
|
};
|
|
@@ -350,10 +368,10 @@ class SftpClient {
|
|
|
350
368
|
rights: {
|
|
351
369
|
user: item.longname.substr(1, 3).replace(reg, ''),
|
|
352
370
|
group: item.longname.substr(4, 3).replace(reg, ''),
|
|
353
|
-
other: item.longname.substr(7, 3).replace(reg, '')
|
|
371
|
+
other: item.longname.substr(7, 3).replace(reg, ''),
|
|
354
372
|
},
|
|
355
373
|
owner: item.attrs.uid,
|
|
356
|
-
group: item.attrs.gid
|
|
374
|
+
group: item.attrs.gid,
|
|
357
375
|
};
|
|
358
376
|
});
|
|
359
377
|
}
|
|
@@ -370,7 +388,7 @@ class SftpClient {
|
|
|
370
388
|
});
|
|
371
389
|
}
|
|
372
390
|
}).finally((rsp) => {
|
|
373
|
-
removeTempListeners(this
|
|
391
|
+
removeTempListeners(this);
|
|
374
392
|
return rsp;
|
|
375
393
|
});
|
|
376
394
|
}
|
|
@@ -385,33 +403,44 @@ class SftpClient {
|
|
|
385
403
|
*
|
|
386
404
|
* @param {String} path, remote file path
|
|
387
405
|
* @param {string|stream|undefined} dst, data destination
|
|
388
|
-
* @param {Object}
|
|
406
|
+
* @param {Object} options, options object with supported properties of readStreamOptions,
|
|
407
|
+
* writeStreamOptions and pipeOptions.
|
|
389
408
|
*
|
|
390
409
|
* @return {Promise}
|
|
391
410
|
*/
|
|
392
|
-
get(
|
|
411
|
+
get(
|
|
412
|
+
remotePath,
|
|
413
|
+
dst,
|
|
414
|
+
options = { readStreamOptions: {}, writeStreamOptions: {}, pipeOptions: {} }
|
|
415
|
+
) {
|
|
416
|
+
let rdr, wtr;
|
|
417
|
+
|
|
393
418
|
return new Promise((resolve, reject) => {
|
|
394
419
|
if (haveConnection(this, 'get', reject)) {
|
|
395
420
|
this.debugMsg(`get -> ${remotePath} `, options);
|
|
396
421
|
addTempListeners(this, 'get', reject);
|
|
397
|
-
|
|
422
|
+
rdr = this.sftp.createReadStream(
|
|
423
|
+
remotePath,
|
|
424
|
+
options.readStreamOptions ? options.readStreamOptions : {}
|
|
425
|
+
);
|
|
398
426
|
rdr.once('error', (err) => {
|
|
399
427
|
reject(fmtError(`${err.message} ${remotePath}`, 'get', err.code));
|
|
400
428
|
});
|
|
401
429
|
if (dst === undefined) {
|
|
402
430
|
// no dst specified, return buffer of data
|
|
403
431
|
this.debugMsg('get returning buffer of data');
|
|
404
|
-
|
|
405
|
-
rdr.removeAllListeners('error');
|
|
432
|
+
wtr = concat((buff) => {
|
|
433
|
+
//rdr.removeAllListeners('error');
|
|
406
434
|
resolve(buff);
|
|
407
435
|
});
|
|
408
|
-
rdr.pipe(concatStream);
|
|
409
436
|
} else {
|
|
410
|
-
let wtr;
|
|
411
437
|
if (typeof dst === 'string') {
|
|
412
438
|
// dst local file path
|
|
413
439
|
this.debugMsg('get returning local file');
|
|
414
|
-
wtr = fs.createWriteStream(
|
|
440
|
+
wtr = fs.createWriteStream(
|
|
441
|
+
dst,
|
|
442
|
+
options.writeStreamOptions ? options.writeStreamOptions : {}
|
|
443
|
+
);
|
|
415
444
|
} else {
|
|
416
445
|
this.debugMsg('get returning data into supplied stream');
|
|
417
446
|
wtr = dst;
|
|
@@ -424,25 +453,34 @@ class SftpClient {
|
|
|
424
453
|
err.code
|
|
425
454
|
)
|
|
426
455
|
);
|
|
427
|
-
if (options.autoClose === false) {
|
|
428
|
-
rdr.destroy();
|
|
429
|
-
}
|
|
430
456
|
});
|
|
431
|
-
|
|
432
|
-
if (options.autoClose === false) {
|
|
433
|
-
rdr.destroy();
|
|
434
|
-
}
|
|
457
|
+
rdr.once('end', () => {
|
|
435
458
|
if (typeof dst === 'string') {
|
|
436
459
|
resolve(dst);
|
|
437
460
|
} else {
|
|
438
461
|
resolve(wtr);
|
|
439
462
|
}
|
|
440
463
|
});
|
|
441
|
-
rdr.pipe(wtr);
|
|
442
464
|
}
|
|
465
|
+
rdr.pipe(wtr, options.pipeOptions ? options.pipeOptions : {});
|
|
443
466
|
}
|
|
444
467
|
}).finally((rsp) => {
|
|
445
|
-
removeTempListeners(this
|
|
468
|
+
removeTempListeners(this);
|
|
469
|
+
if (
|
|
470
|
+
rdr &&
|
|
471
|
+
options.readStreamOptions &&
|
|
472
|
+
options.readStreamOptions.autoClose === false
|
|
473
|
+
) {
|
|
474
|
+
rdr.destroy();
|
|
475
|
+
}
|
|
476
|
+
if (
|
|
477
|
+
wtr &&
|
|
478
|
+
options.writeStreamOptions &&
|
|
479
|
+
options.writeStreamOptions.autoClose === false &&
|
|
480
|
+
typeof dst === 'string'
|
|
481
|
+
) {
|
|
482
|
+
wtr.destroy();
|
|
483
|
+
}
|
|
446
484
|
return rsp;
|
|
447
485
|
});
|
|
448
486
|
}
|
|
@@ -490,7 +528,7 @@ class SftpClient {
|
|
|
490
528
|
});
|
|
491
529
|
}
|
|
492
530
|
}).finally((rsp) => {
|
|
493
|
-
removeTempListeners(this
|
|
531
|
+
removeTempListeners(this);
|
|
494
532
|
return rsp;
|
|
495
533
|
});
|
|
496
534
|
});
|
|
@@ -511,60 +549,42 @@ class SftpClient {
|
|
|
511
549
|
*/
|
|
512
550
|
fastPut(localPath, remotePath, options) {
|
|
513
551
|
this.debugMsg(`fastPut -> local ${localPath} remote ${remotePath}`);
|
|
514
|
-
return localExists(localPath)
|
|
515
|
-
.
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
552
|
+
return localExists(localPath).then((localStatus) => {
|
|
553
|
+
this.debugMsg(`fastPut <- localStatus ${localStatus}`);
|
|
554
|
+
if (localStatus !== '-') {
|
|
555
|
+
this.debugMsg('fastPut reject bad source path');
|
|
556
|
+
return Promise.reject(
|
|
557
|
+
fmtError(`Bad path ${localPath}`, 'fastPut', errorCode.badPath)
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
return new Promise((resolve, reject) => {
|
|
561
|
+
if (haveConnection(this, 'fastPut', reject)) {
|
|
562
|
+
this.debugMsg(
|
|
563
|
+
`fastPut -> local: ${localPath} remote: ${remotePath} opts: ${JSON.stringify(
|
|
564
|
+
options
|
|
565
|
+
)}`
|
|
521
566
|
);
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
fs.access(localPath, fs.constants.F_OK | fs.constants.R_OK, (err) => {
|
|
567
|
+
addTempListeners(this, 'fastPut', reject);
|
|
568
|
+
this.sftp.fastPut(localPath, remotePath, options, (err) => {
|
|
525
569
|
if (err) {
|
|
526
|
-
this.debugMsg(
|
|
570
|
+
this.debugMsg(`fastPut error ${err.message} ${err.code}`);
|
|
527
571
|
reject(
|
|
528
|
-
fmtError(
|
|
572
|
+
fmtError(
|
|
573
|
+
`${err.message} Local: ${localPath} Remote: ${remotePath}`,
|
|
574
|
+
'fastPut',
|
|
575
|
+
err.code
|
|
576
|
+
)
|
|
529
577
|
);
|
|
530
|
-
} else {
|
|
531
|
-
this.debugMsg('fastPut source access ok');
|
|
532
|
-
resolve(true);
|
|
533
578
|
}
|
|
579
|
+
this.debugMsg('fastPut file transferred');
|
|
580
|
+
resolve(`${localPath} was successfully uploaded to ${remotePath}!`);
|
|
534
581
|
});
|
|
535
|
-
}
|
|
536
|
-
})
|
|
537
|
-
|
|
538
|
-
return
|
|
539
|
-
if (haveConnection(this, 'fastPut', reject)) {
|
|
540
|
-
this.debugMsg(
|
|
541
|
-
`fastPut -> local: ${localPath} remote: ${remotePath} opts: ${JSON.stringify(
|
|
542
|
-
options
|
|
543
|
-
)}`
|
|
544
|
-
);
|
|
545
|
-
addTempListeners(this, 'fastPut', reject);
|
|
546
|
-
this.sftp.fastPut(localPath, remotePath, options, (err) => {
|
|
547
|
-
if (err) {
|
|
548
|
-
this.debugMsg(`fastPut error ${err.message} ${err.code}`);
|
|
549
|
-
reject(
|
|
550
|
-
fmtError(
|
|
551
|
-
`${err.message} Local: ${localPath} Remote: ${remotePath}`,
|
|
552
|
-
'fastPut',
|
|
553
|
-
err.code
|
|
554
|
-
)
|
|
555
|
-
);
|
|
556
|
-
}
|
|
557
|
-
this.debugMsg('fastPut file transferred');
|
|
558
|
-
resolve(
|
|
559
|
-
`${localPath} was successfully uploaded to ${remotePath}!`
|
|
560
|
-
);
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
|
-
}).finally((rsp) => {
|
|
564
|
-
removeTempListeners(this.client);
|
|
565
|
-
return rsp;
|
|
566
|
-
});
|
|
582
|
+
}
|
|
583
|
+
}).finally((rsp) => {
|
|
584
|
+
removeTempListeners(this);
|
|
585
|
+
return rsp;
|
|
567
586
|
});
|
|
587
|
+
});
|
|
568
588
|
}
|
|
569
589
|
|
|
570
590
|
/**
|
|
@@ -574,100 +594,95 @@ class SftpClient {
|
|
|
574
594
|
*
|
|
575
595
|
* @param {String|Buffer|stream} src - source data to use
|
|
576
596
|
* @param {String} remotePath - path to remote file
|
|
577
|
-
* @param {Object} options - options used for write stream configuration
|
|
578
|
-
* value supported by node
|
|
597
|
+
* @param {Object} options - options used for read, write stream and pipe configuration
|
|
598
|
+
* value supported by node. Allowed properties are readStreamOptions,
|
|
599
|
+
* writeStreamOptions and pipeOptions.
|
|
579
600
|
* @return {Promise}
|
|
580
601
|
*/
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
return
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
602
|
+
doPut(
|
|
603
|
+
localSrc,
|
|
604
|
+
remotePath,
|
|
605
|
+
options = { readStreamOptions: {}, writeStreamOptions: {}, pipeOptions: {} }
|
|
606
|
+
) {
|
|
607
|
+
let wtr, rdr;
|
|
608
|
+
|
|
609
|
+
return new Promise((resolve, reject) => {
|
|
610
|
+
addTempListeners(this, 'put', reject);
|
|
611
|
+
wtr = this.sftp.createWriteStream(
|
|
612
|
+
remotePath,
|
|
613
|
+
options.writeStreamOptions ? options.writeStreamOptions : {}
|
|
614
|
+
);
|
|
615
|
+
wtr.once('error', (err) => {
|
|
616
|
+
reject(fmtError(`${err.message} ${remotePath}`, 'put', err.code));
|
|
617
|
+
});
|
|
618
|
+
wtr.once('finish', () => {
|
|
619
|
+
resolve(`Uploaded data stream to ${remotePath}`);
|
|
620
|
+
});
|
|
621
|
+
if (localSrc instanceof Buffer) {
|
|
622
|
+
this.debugMsg('put source is a buffer');
|
|
623
|
+
wtr.end(localSrc);
|
|
624
|
+
} else {
|
|
625
|
+
if (typeof localSrc === 'string') {
|
|
626
|
+
this.debugMsg(`put source is a file path: ${localSrc}`);
|
|
627
|
+
rdr = fs.createReadStream(
|
|
628
|
+
localSrc,
|
|
629
|
+
options.readStreamOptions ? options.readStreamOptons : {}
|
|
594
630
|
);
|
|
631
|
+
} else {
|
|
632
|
+
this.debugMsg('put source is a stream');
|
|
633
|
+
rdr = localSrc;
|
|
595
634
|
}
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
localSrc
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
reject(
|
|
605
|
-
fmtError(
|
|
606
|
-
`Permission denied ${localSrc}`,
|
|
607
|
-
'put',
|
|
608
|
-
errorCode.permission
|
|
609
|
-
)
|
|
610
|
-
);
|
|
611
|
-
} else {
|
|
612
|
-
this.debugMsg('put: localSrc file OK');
|
|
613
|
-
resolve(true);
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
);
|
|
617
|
-
} else {
|
|
618
|
-
this.debugMsg('put: localSrc buffer or string OK');
|
|
619
|
-
resolve(true);
|
|
620
|
-
}
|
|
621
|
-
});
|
|
622
|
-
})
|
|
623
|
-
.then(() => {
|
|
624
|
-
return new Promise((resolve, reject) => {
|
|
625
|
-
if (haveConnection(this, 'put', reject)) {
|
|
626
|
-
addTempListeners(this, 'put', reject);
|
|
627
|
-
let stream = this.sftp.createWriteStream(remotePath, options);
|
|
628
|
-
stream.once('error', (err) => {
|
|
629
|
-
reject(fmtError(`${err.message} ${remotePath}`, 'put', err.code));
|
|
630
|
-
});
|
|
631
|
-
stream.once('finish', () => {
|
|
632
|
-
if (options.autoClose === false) {
|
|
633
|
-
stream.destroy();
|
|
634
|
-
}
|
|
635
|
-
resolve(`Uploaded data stream to ${remotePath}`);
|
|
636
|
-
});
|
|
637
|
-
if (localSrc instanceof Buffer) {
|
|
638
|
-
this.debugMsg('put source is a buffer');
|
|
639
|
-
stream.end(localSrc);
|
|
640
|
-
} else {
|
|
641
|
-
let rdr;
|
|
642
|
-
if (typeof localSrc === 'string') {
|
|
643
|
-
this.debugMsg(`put source is a file path: ${localSrc}`);
|
|
644
|
-
rdr = fs.createReadStream(localSrc);
|
|
645
|
-
} else {
|
|
646
|
-
this.debugMsg('put source is a stream');
|
|
647
|
-
rdr = localSrc;
|
|
648
|
-
}
|
|
649
|
-
rdr.once('error', (err) => {
|
|
650
|
-
reject(
|
|
651
|
-
fmtError(
|
|
652
|
-
`${err.message} ${
|
|
653
|
-
typeof localSrc === 'string' ? localSrc : ''
|
|
654
|
-
}`,
|
|
655
|
-
'put',
|
|
656
|
-
err.code
|
|
657
|
-
)
|
|
658
|
-
);
|
|
659
|
-
if (options.autoClose === false) {
|
|
660
|
-
stream.destroy();
|
|
661
|
-
}
|
|
662
|
-
});
|
|
663
|
-
rdr.pipe(stream);
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
}).finally((rsp) => {
|
|
667
|
-
removeTempListeners(this.client);
|
|
668
|
-
return rsp;
|
|
635
|
+
rdr.once('error', (err) => {
|
|
636
|
+
reject(
|
|
637
|
+
fmtError(
|
|
638
|
+
`${err.message} ${typeof localSrc === 'string' ? localSrc : ''}`,
|
|
639
|
+
'put',
|
|
640
|
+
err.code
|
|
641
|
+
)
|
|
642
|
+
);
|
|
669
643
|
});
|
|
670
|
-
|
|
644
|
+
rdr.pipe(wtr, options.pipeOptions ? options.pipeOptions : {});
|
|
645
|
+
}
|
|
646
|
+
}).finally((resp) => {
|
|
647
|
+
removeTempListeners(this);
|
|
648
|
+
if (
|
|
649
|
+
rdr &&
|
|
650
|
+
options.readStreamOptions &&
|
|
651
|
+
options.readStreamOptions.autoClose === false &&
|
|
652
|
+
typeof localSrc === 'string'
|
|
653
|
+
) {
|
|
654
|
+
rdr.destroy();
|
|
655
|
+
}
|
|
656
|
+
if (
|
|
657
|
+
wtr &&
|
|
658
|
+
options.writeStreamOptions &&
|
|
659
|
+
options.writeStreamOptions.autoClose === false
|
|
660
|
+
) {
|
|
661
|
+
wtr.destroy();
|
|
662
|
+
}
|
|
663
|
+
return resp;
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
async put(
|
|
668
|
+
localSrc,
|
|
669
|
+
remoePath,
|
|
670
|
+
options = { readStreamOptions: {}, writeStreamOptions: {}, pipeOptions: {} }
|
|
671
|
+
) {
|
|
672
|
+
try {
|
|
673
|
+
haveConnection(this, 'put');
|
|
674
|
+
if (typeof localSrc === 'string') {
|
|
675
|
+
let type = await localExists(localSrc);
|
|
676
|
+
if (type !== '-' && type !== 'l') {
|
|
677
|
+
let err = new Error(`Bad path: ${localSrc}`);
|
|
678
|
+
err.code = errorCode.badPath;
|
|
679
|
+
throw err;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
return await this.doPut(localSrc, remoePath, options);
|
|
683
|
+
} catch (err) {
|
|
684
|
+
throw fmtError(err, 'put');
|
|
685
|
+
}
|
|
671
686
|
}
|
|
672
687
|
|
|
673
688
|
/**
|
|
@@ -704,7 +719,7 @@ class SftpClient {
|
|
|
704
719
|
}
|
|
705
720
|
}
|
|
706
721
|
}).finally((rsp) => {
|
|
707
|
-
removeTempListeners(this
|
|
722
|
+
removeTempListeners(this);
|
|
708
723
|
return rsp;
|
|
709
724
|
});
|
|
710
725
|
}
|
|
@@ -731,7 +746,7 @@ class SftpClient {
|
|
|
731
746
|
resolve(`${p} directory created`);
|
|
732
747
|
});
|
|
733
748
|
}).finally((rsp) => {
|
|
734
|
-
removeTempListeners(this
|
|
749
|
+
removeTempListeners(this);
|
|
735
750
|
return rsp;
|
|
736
751
|
});
|
|
737
752
|
};
|
|
@@ -782,7 +797,7 @@ class SftpClient {
|
|
|
782
797
|
resolve('Successfully removed directory');
|
|
783
798
|
});
|
|
784
799
|
}).finally((rsp) => {
|
|
785
|
-
removeTempListeners(this
|
|
800
|
+
removeTempListeners(this);
|
|
786
801
|
return rsp;
|
|
787
802
|
});
|
|
788
803
|
};
|
|
@@ -848,7 +863,7 @@ class SftpClient {
|
|
|
848
863
|
});
|
|
849
864
|
}
|
|
850
865
|
}).finally((rsp) => {
|
|
851
|
-
removeTempListeners(this
|
|
866
|
+
removeTempListeners(this);
|
|
852
867
|
return rsp;
|
|
853
868
|
});
|
|
854
869
|
}
|
|
@@ -884,7 +899,7 @@ class SftpClient {
|
|
|
884
899
|
});
|
|
885
900
|
}
|
|
886
901
|
}).finally((rsp) => {
|
|
887
|
-
removeTempListeners(this
|
|
902
|
+
removeTempListeners(this);
|
|
888
903
|
return rsp;
|
|
889
904
|
});
|
|
890
905
|
}
|
|
@@ -921,7 +936,7 @@ class SftpClient {
|
|
|
921
936
|
});
|
|
922
937
|
}
|
|
923
938
|
}).finally((rsp) => {
|
|
924
|
-
removeTempListeners(this
|
|
939
|
+
removeTempListeners(this);
|
|
925
940
|
return rsp;
|
|
926
941
|
});
|
|
927
942
|
}
|
|
@@ -947,7 +962,7 @@ class SftpClient {
|
|
|
947
962
|
resolve('Successfully change file mode');
|
|
948
963
|
});
|
|
949
964
|
}).finally((rsp) => {
|
|
950
|
-
removeTempListeners(this
|
|
965
|
+
removeTempListeners(this);
|
|
951
966
|
return rsp;
|
|
952
967
|
});
|
|
953
968
|
}
|
|
@@ -978,7 +993,7 @@ class SftpClient {
|
|
|
978
993
|
}
|
|
979
994
|
let dirEntries = fs.readdirSync(srcDir, {
|
|
980
995
|
encoding: 'utf8',
|
|
981
|
-
withFileTypes: true
|
|
996
|
+
withFileTypes: true,
|
|
982
997
|
});
|
|
983
998
|
dirEntries = dirEntries.filter((item) => filter.test(item.name));
|
|
984
999
|
for (let e of dirEntries) {
|
|
@@ -990,7 +1005,7 @@ class SftpClient {
|
|
|
990
1005
|
let src = join(srcDir, e.name);
|
|
991
1006
|
let dst = dstDir + this.remotePathSep + e.name;
|
|
992
1007
|
await this.fastPut(src, dst);
|
|
993
|
-
this.client.emit('upload', {source: src, destination: dst});
|
|
1008
|
+
this.client.emit('upload', { source: src, destination: dst });
|
|
994
1009
|
} else {
|
|
995
1010
|
this.debugMsg(
|
|
996
1011
|
`uploadDir: File ignored: ${e.name} not a regular file`
|
|
@@ -1025,12 +1040,12 @@ class SftpClient {
|
|
|
1025
1040
|
this.debugMsg(`downloadDir -> ${srcDir} ${dstDir}`);
|
|
1026
1041
|
haveConnection(this, 'downloadDir');
|
|
1027
1042
|
let fileList = await this.list(srcDir, filter);
|
|
1028
|
-
let dstStatus = await localExists(dstDir);
|
|
1043
|
+
let dstStatus = await localExists(dstDir, true);
|
|
1029
1044
|
if (dstStatus && dstStatus !== 'd') {
|
|
1030
1045
|
throw fmtError(`Bad path ${dstDir}`, 'downloadDir', errorCode.badPath);
|
|
1031
1046
|
}
|
|
1032
1047
|
if (!dstStatus) {
|
|
1033
|
-
fs.mkdirSync(dstDir, {recursive: true});
|
|
1048
|
+
fs.mkdirSync(dstDir, { recursive: true });
|
|
1034
1049
|
}
|
|
1035
1050
|
for (let f of fileList) {
|
|
1036
1051
|
if (f.type === 'd') {
|
|
@@ -1041,7 +1056,7 @@ class SftpClient {
|
|
|
1041
1056
|
let src = srcDir + this.remotePathSep + f.name;
|
|
1042
1057
|
let dst = join(dstDir, f.name);
|
|
1043
1058
|
await this.fastGet(src, dst);
|
|
1044
|
-
this.client.emit('download', {source: src, destination: dst});
|
|
1059
|
+
this.client.emit('download', { source: src, destination: dst });
|
|
1045
1060
|
} else {
|
|
1046
1061
|
this.debugMsg(
|
|
1047
1062
|
`downloadDir: File ignored: ${f.name} not regular file`
|
|
@@ -1079,7 +1094,7 @@ class SftpClient {
|
|
|
1079
1094
|
this.client.end();
|
|
1080
1095
|
}
|
|
1081
1096
|
}).finally(() => {
|
|
1082
|
-
removeTempListeners(this
|
|
1097
|
+
removeTempListeners(this);
|
|
1083
1098
|
this.removeListener('close', endCloseHandler);
|
|
1084
1099
|
return true;
|
|
1085
1100
|
});
|