ssh2-sftp-client 9.0.0 → 9.0.3
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/README.md +138 -131
- package/README.org +42 -21
- package/package.json +2 -2
- package/src/index.js +48 -126
- package/src/utils.js +38 -25
- package/.dir-local.el +0 -1
package/README.org
CHANGED
|
@@ -9,16 +9,34 @@ convenience abstraction as well as a Promise based API.
|
|
|
9
9
|
Documentation on the methods and available options in the underlying modules can
|
|
10
10
|
be found on the [[https://github.com/mscdex/ssh2][SSH2]] project pages.
|
|
11
11
|
|
|
12
|
-
Current stable release is *v9.0.
|
|
12
|
+
Current stable release is *v9.0.2*.
|
|
13
13
|
|
|
14
14
|
Code has been tested against Node versions 14.19.1, 16.15.0 and 18.1.0
|
|
15
15
|
|
|
16
|
-
Node versions <
|
|
17
|
-
although some tests will fail due to changes in file system functions used in
|
|
18
|
-
test setup and tear down.
|
|
16
|
+
Node versions < 14.x are not supported.
|
|
19
17
|
|
|
20
18
|
** Version 9.x Changes
|
|
21
|
-
|
|
19
|
+
- Fix bug in ~end()~ method where it was possible for the module to attempt calling
|
|
20
|
+
the underlying ssh2 ~end()~ method when ssh2 has not been initialised. This could
|
|
21
|
+
lead to undefined reference errors.
|
|
22
|
+
- Fix bug in ~get()~ method where supplied destination streams were not close, creating
|
|
23
|
+
a possible resource leak. If the remote file did not exist, the method would return
|
|
24
|
+
an error, but failed to close any passed in stream supplied as the destination for
|
|
25
|
+
the data in the ~get()~ call.
|
|
26
|
+
- Change the default end and close handlers not to throw error or reject
|
|
27
|
+
promises. Previously, an end or close event would cause an error to be raised or a
|
|
28
|
+
promise to be rejected if the event was deemed to be /unexpected/. However,
|
|
29
|
+
classification of events as being unexpected was unreliable and didn't add much real
|
|
30
|
+
value. Both these handlers will now invalidate the sftp connection object and log that
|
|
31
|
+
the event fired and nothing else.
|
|
32
|
+
- Changed when event handled flags are reset. Now they are reset after a new set of
|
|
33
|
+
temporary listeners are added.
|
|
34
|
+
- Don't throw an error when calling end() if there is no active sftp connection. It does
|
|
35
|
+
no harm to call end() when there is no connection, so no need to raise an error.
|
|
36
|
+
- Use nullish coalescing when setting retry parameters instead of or'ing with
|
|
37
|
+
defaults. Allows setting values to 0.
|
|
38
|
+
- *Breaking Change*: This version uses syntax not supported in node versions
|
|
39
|
+
prior to v14. Therefore, node versions less than v14 will not work.
|
|
22
40
|
- *Breaking Change*: This ~list()~ method no longer accepts a regular expression
|
|
23
41
|
for filtering the entries to be returned. You can now specify a filter
|
|
24
42
|
function instead. The function is called for each item in the list of items
|
|
@@ -331,21 +349,6 @@ The objects in the array returned by ~list()~ have the following properties;
|
|
|
331
349
|
}
|
|
332
350
|
#+end_src
|
|
333
351
|
|
|
334
|
-
**** Pattern Filter
|
|
335
|
-
|
|
336
|
-
The filter options can be a regular expression (most powerful option) or a
|
|
337
|
-
simple /glob/-like string where * will match any number of characters, e.g.
|
|
338
|
-
|
|
339
|
-
#+begin_example
|
|
340
|
-
foo* => foo, foobar, foobaz
|
|
341
|
-
,*bar => bar, foobar, tabbar
|
|
342
|
-
,*oo* => foo, foobar, look, book
|
|
343
|
-
#+end_example
|
|
344
|
-
|
|
345
|
-
The /glob/-style matching is very simple. In most cases, you are best off using
|
|
346
|
-
a real regular expression which will allow you to do more powerful matching and
|
|
347
|
-
anchor matches to the beginning/end of the string etc.
|
|
348
|
-
|
|
349
352
|
*** exists(path) ==> boolean
|
|
350
353
|
|
|
351
354
|
Tests to see if remote file or directory exists. Returns type of remote object
|
|
@@ -1078,7 +1081,6 @@ services.
|
|
|
1078
1081
|
|
|
1079
1082
|
#+end_src
|
|
1080
1083
|
|
|
1081
|
-
|
|
1082
1084
|
*** createReadStream(remotePath, options)) ==> stream object
|
|
1083
1085
|
|
|
1084
1086
|
Returns a read stream object which is attached to the remote file specified by
|
|
@@ -1191,6 +1193,25 @@ the ~end()~ method automatically removes all listeners from the client object.
|
|
|
1191
1193
|
additional steps to simulate missing functionality etc. You want to use a CLI
|
|
1192
1194
|
program which does as little as possible.
|
|
1193
1195
|
|
|
1196
|
+
** Issues with ~fastPut()~ and ~fastGet()~ Methods
|
|
1197
|
+
|
|
1198
|
+
The ~fastPut()~ and ~fastGet()~ methods are known to be somewhat dependent on
|
|
1199
|
+
SFTP server capabilities. Some SFTP servers just do not work correctly with
|
|
1200
|
+
concurrent connections and some are known to have issues with negotiating
|
|
1201
|
+
packet sizes. These issues can sometimes be resolved by tweaking the options
|
|
1202
|
+
supplied to the methods, such as setting number of concurrent connections or
|
|
1203
|
+
a psecific packet size.
|
|
1204
|
+
|
|
1205
|
+
To see an example of the type of issues you can observe with ~fastPut()~ or
|
|
1206
|
+
~fastGet()~, have a look at [[https://github.com/theophilusx/ssh2-sftp-client/issues/407][issue 407]], which describes the experiences of one
|
|
1207
|
+
user. Bottom line, when it works, it tends to work well and be significantly
|
|
1208
|
+
faster than using just ~get()~ or ~put()~. However, when developing code to
|
|
1209
|
+
run against different SFTP servers, especially where you are unable to test
|
|
1210
|
+
against each server, you are likely better off just using ~get()~ and ~put()~
|
|
1211
|
+
or structuring your code so that users can select which method to use (this
|
|
1212
|
+
is what =ssh2-sftp-client= does - for example, see the ~!downloadDir()~ and
|
|
1213
|
+
~uploadDir()~ methods.
|
|
1214
|
+
|
|
1194
1215
|
** Promises, Events & Managing Exceptions
|
|
1195
1216
|
|
|
1196
1217
|
One of the challenges in providing a Promise based API over a module like
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ssh2-sftp-client",
|
|
3
|
-
"version": "9.0.
|
|
3
|
+
"version": "9.0.3",
|
|
4
4
|
"description": "ssh2 sftp client for node",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"repository": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"eslint-plugin-mocha": "^10.0.3",
|
|
41
41
|
"eslint-plugin-node": "^11.1.0",
|
|
42
42
|
"eslint-plugin-promise": "^6.0.0",
|
|
43
|
-
"eslint-plugin-unicorn": "^
|
|
43
|
+
"eslint-plugin-unicorn": "^43.0.2",
|
|
44
44
|
"mocha": "^10.0.0",
|
|
45
45
|
"moment": "^2.29.1",
|
|
46
46
|
"nyc": "^15.1.0",
|
package/src/index.js
CHANGED
|
@@ -18,7 +18,7 @@ const { errorCode } = require('./constants');
|
|
|
18
18
|
|
|
19
19
|
class SftpClient {
|
|
20
20
|
constructor(clientName) {
|
|
21
|
-
this.version = '9.0.
|
|
21
|
+
this.version = '9.0.2';
|
|
22
22
|
this.client = new Client();
|
|
23
23
|
this.sftp = undefined;
|
|
24
24
|
this.clientName = clientName ? clientName : 'sftp';
|
|
@@ -31,7 +31,7 @@ class SftpClient {
|
|
|
31
31
|
this.debug = undefined;
|
|
32
32
|
|
|
33
33
|
this.client.on('close', () => {
|
|
34
|
-
if (this.endCalled || this.closeHandled) {
|
|
34
|
+
if (this.endCalled || this.errorHandled || this.closeHandled) {
|
|
35
35
|
// we are processing an expected end event or close event handled elsewhere
|
|
36
36
|
this.debugMsg('Global: Ignoring handled close event');
|
|
37
37
|
} else {
|
|
@@ -41,7 +41,7 @@ class SftpClient {
|
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
this.client.on('end', () => {
|
|
44
|
-
if (this.endCalled || this.endHandled) {
|
|
44
|
+
if (this.endCalled || this.errorHandled || this.endHandled) {
|
|
45
45
|
// end event expected or handled elsewhere
|
|
46
46
|
this.debugMsg('Global: Ignoring hanlded end event');
|
|
47
47
|
} else {
|
|
@@ -95,26 +95,20 @@ class SftpClient {
|
|
|
95
95
|
} else {
|
|
96
96
|
switch (err.code) {
|
|
97
97
|
case 'ENOTFOUND':
|
|
98
|
-
msg =
|
|
99
|
-
`${name}: ${err.level} error. ` +
|
|
100
|
-
`Address lookup failed for host ${err.hostname}${retry}`;
|
|
98
|
+
msg = `${name}: Address lookup failed for host${retry}`;
|
|
101
99
|
break;
|
|
102
100
|
case 'ECONNREFUSED':
|
|
103
|
-
msg =
|
|
104
|
-
`${name}: ${err.level} error. Remote host at ` +
|
|
105
|
-
`${err.address} refused connection${retry}`;
|
|
101
|
+
msg = `${name}: Remote host refused connection${retry}`;
|
|
106
102
|
break;
|
|
107
103
|
case 'ECONNRESET':
|
|
108
|
-
msg =
|
|
109
|
-
`${name}: Remote host has reset the connection: ` +
|
|
110
|
-
`${err.message}${retry}`;
|
|
104
|
+
msg = `${name}: Remote host has reset the connection: ${err.message}${retry}`;
|
|
111
105
|
break;
|
|
112
106
|
default:
|
|
113
107
|
msg = `${name}: ${err.message}${retry}`;
|
|
114
108
|
}
|
|
115
109
|
code = err.code ? err.code : errorCode.generic;
|
|
116
110
|
}
|
|
117
|
-
|
|
111
|
+
const newError = new Error(msg);
|
|
118
112
|
newError.code = code;
|
|
119
113
|
newError.custom = true;
|
|
120
114
|
this.debugMsg(`${newError.message} (${newError.code})`);
|
|
@@ -159,9 +153,7 @@ class SftpClient {
|
|
|
159
153
|
return new Promise((resolve, reject) => {
|
|
160
154
|
listeners = addTempListeners(this, 'getConnection', reject);
|
|
161
155
|
doReady = () => {
|
|
162
|
-
this.debugMsg(
|
|
163
|
-
'getConnection ready listener: got connection - promise resolved'
|
|
164
|
-
);
|
|
156
|
+
this.debugMsg('getConnection ready listener: got connection - promise resolved');
|
|
165
157
|
resolve(true);
|
|
166
158
|
};
|
|
167
159
|
this.on('ready', doReady);
|
|
@@ -169,7 +161,6 @@ class SftpClient {
|
|
|
169
161
|
}).finally(() => {
|
|
170
162
|
this.removeListener('ready', doReady);
|
|
171
163
|
removeTempListeners(this, listeners, 'getConnection');
|
|
172
|
-
this._resetEventFlags();
|
|
173
164
|
});
|
|
174
165
|
}
|
|
175
166
|
|
|
@@ -177,7 +168,6 @@ class SftpClient {
|
|
|
177
168
|
return new Promise((resolve, reject) => {
|
|
178
169
|
this.client.sftp((err, sftp) => {
|
|
179
170
|
if (err) {
|
|
180
|
-
this.client.end();
|
|
181
171
|
reject(this.fmtError(err, 'getSftpChannel', err.code));
|
|
182
172
|
} else {
|
|
183
173
|
this.debugMsg('getSftpChannel: SFTP channel established');
|
|
@@ -208,10 +198,7 @@ class SftpClient {
|
|
|
208
198
|
if (config.debug) {
|
|
209
199
|
this.debug = config.debug;
|
|
210
200
|
this.debugMsg('connect: Debugging turned on');
|
|
211
|
-
this.debugMsg(
|
|
212
|
-
`ssh2-sftp-client Version: ${this.version} `,
|
|
213
|
-
process.versions
|
|
214
|
-
);
|
|
201
|
+
this.debugMsg(`ssh2-sftp-client Version: ${this.version} `, process.versions);
|
|
215
202
|
}
|
|
216
203
|
if (this.sftp) {
|
|
217
204
|
throw this.fmtError(
|
|
@@ -220,10 +207,10 @@ class SftpClient {
|
|
|
220
207
|
errorCode.connect
|
|
221
208
|
);
|
|
222
209
|
}
|
|
223
|
-
|
|
224
|
-
retries: config.retries
|
|
225
|
-
factor: config.factor
|
|
226
|
-
minTimeout: config.retry_minTimeout
|
|
210
|
+
const retryOpts = {
|
|
211
|
+
retries: config.retries ?? 1,
|
|
212
|
+
factor: config.factor ?? 2,
|
|
213
|
+
minTimeout: config.retry_minTimeout ?? 25000,
|
|
227
214
|
};
|
|
228
215
|
await promiseRetry(retryOpts, async (retry, attempt) => {
|
|
229
216
|
try {
|
|
@@ -236,16 +223,8 @@ class SftpClient {
|
|
|
236
223
|
case 'ERR_SOCKET_BAD_PORT':
|
|
237
224
|
throw err;
|
|
238
225
|
case undefined: {
|
|
239
|
-
if (
|
|
240
|
-
err.message.
|
|
241
|
-
'All configured authentication methods failed'
|
|
242
|
-
)
|
|
243
|
-
) {
|
|
244
|
-
throw this.fmtError(
|
|
245
|
-
err.message,
|
|
246
|
-
'getConnection',
|
|
247
|
-
errorCode.badAuth
|
|
248
|
-
);
|
|
226
|
+
if (err.message.endsWith('All configured authentication methods failed')) {
|
|
227
|
+
throw this.fmtError(err.message, 'getConnection', errorCode.badAuth);
|
|
249
228
|
}
|
|
250
229
|
retry(err);
|
|
251
230
|
break;
|
|
@@ -255,14 +234,13 @@ class SftpClient {
|
|
|
255
234
|
}
|
|
256
235
|
}
|
|
257
236
|
});
|
|
258
|
-
|
|
237
|
+
const sftp = await this.getSftpChannel();
|
|
259
238
|
return sftp;
|
|
260
239
|
} catch (err) {
|
|
261
|
-
this.end();
|
|
240
|
+
await this.end();
|
|
262
241
|
throw err.custom ? err : this.fmtError(err, 'connect');
|
|
263
242
|
} finally {
|
|
264
243
|
removeTempListeners(this, listeners, 'connect');
|
|
265
|
-
this._resetEventFlags();
|
|
266
244
|
}
|
|
267
245
|
}
|
|
268
246
|
|
|
@@ -286,9 +264,7 @@ class SftpClient {
|
|
|
286
264
|
this.debugMsg('_realPath <- ""');
|
|
287
265
|
resolve('');
|
|
288
266
|
} else {
|
|
289
|
-
reject(
|
|
290
|
-
this.fmtError(`${err.message} ${rPath}`, 'realPath', err.code)
|
|
291
|
-
);
|
|
267
|
+
reject(this.fmtError(`${err.message} ${rPath}`, 'realPath', err.code));
|
|
292
268
|
}
|
|
293
269
|
}
|
|
294
270
|
this.debugMsg(`_realPath <- ${absPath}`);
|
|
@@ -309,7 +285,6 @@ class SftpClient {
|
|
|
309
285
|
: this.fmtError(`${e.message} ${remotePath}`, 'realPath', e.code);
|
|
310
286
|
} finally {
|
|
311
287
|
removeTempListeners(this, listeners, 'realPath');
|
|
312
|
-
this._resetEventFlags();
|
|
313
288
|
}
|
|
314
289
|
}
|
|
315
290
|
|
|
@@ -336,13 +311,7 @@ class SftpClient {
|
|
|
336
311
|
this.sftp.stat(aPath, (err, stats) => {
|
|
337
312
|
if (err) {
|
|
338
313
|
if (err.code === 2 || err.code === 4) {
|
|
339
|
-
reject(
|
|
340
|
-
this.fmtError(
|
|
341
|
-
`No such file: ${aPath}`,
|
|
342
|
-
'_stat',
|
|
343
|
-
errorCode.notexist
|
|
344
|
-
)
|
|
345
|
-
);
|
|
314
|
+
reject(this.fmtError(`No such file: ${aPath}`, '_stat', errorCode.notexist));
|
|
346
315
|
} else {
|
|
347
316
|
reject(this.fmtError(`${err.message} ${aPath}`, '_stat', err.code));
|
|
348
317
|
}
|
|
@@ -380,7 +349,6 @@ class SftpClient {
|
|
|
380
349
|
throw err.custom ? err : this.fmtError(err, 'stat', err.code);
|
|
381
350
|
} finally {
|
|
382
351
|
removeTempListeners(this, listeners, 'stat');
|
|
383
|
-
this._resetEventFlags();
|
|
384
352
|
}
|
|
385
353
|
}
|
|
386
354
|
|
|
@@ -437,7 +405,6 @@ class SftpClient {
|
|
|
437
405
|
throw err.custom ? err : this.fmtError(err, 'exists', err.code);
|
|
438
406
|
} finally {
|
|
439
407
|
removeTempListeners(this, listeners, 'exists');
|
|
440
|
-
this._resetEventFlags();
|
|
441
408
|
}
|
|
442
409
|
}
|
|
443
410
|
|
|
@@ -447,7 +414,7 @@ class SftpClient {
|
|
|
447
414
|
* List contents of a remote directory. If a pattern is provided,
|
|
448
415
|
* filter the results to only include files with names that match
|
|
449
416
|
* the supplied pattern. Return value is an array of file entry
|
|
450
|
-
* objects that include properties for type, name, size,
|
|
417
|
+
* objects that include properties for type, name, size, modifyTime,
|
|
451
418
|
* accessTime, rights {user, group other}, owner and group.
|
|
452
419
|
*
|
|
453
420
|
* @param {String} remotePath - path to remote directory
|
|
@@ -458,9 +425,7 @@ class SftpClient {
|
|
|
458
425
|
return new Promise((resolve, reject) => {
|
|
459
426
|
this.sftp.readdir(remotePath, (err, fileList) => {
|
|
460
427
|
if (err) {
|
|
461
|
-
reject(
|
|
462
|
-
this.fmtError(`${err.message} ${remotePath}`, 'list', err.code)
|
|
463
|
-
);
|
|
428
|
+
reject(this.fmtError(`${err.message} ${remotePath}`, 'list', err.code));
|
|
464
429
|
} else {
|
|
465
430
|
const reg = /-/gi;
|
|
466
431
|
const newList = fileList.map((item) => {
|
|
@@ -497,12 +462,9 @@ class SftpClient {
|
|
|
497
462
|
haveConnection(this, 'list');
|
|
498
463
|
return await this._list(remotePath, filter);
|
|
499
464
|
} catch (e) {
|
|
500
|
-
throw e.custom
|
|
501
|
-
? e
|
|
502
|
-
: this.fmtError(`${e.message} ${remotePath}`, 'list', e.code);
|
|
465
|
+
throw e.custom ? e : this.fmtError(`${e.message} ${remotePath}`, 'list', e.code);
|
|
503
466
|
} finally {
|
|
504
467
|
removeTempListeners(this, listeners, 'list');
|
|
505
|
-
this._resetEventFlags();
|
|
506
468
|
}
|
|
507
469
|
}
|
|
508
470
|
|
|
@@ -536,11 +498,14 @@ class SftpClient {
|
|
|
536
498
|
};
|
|
537
499
|
rdr = this.sftp.createReadStream(rPath, opts.readStreamOptions);
|
|
538
500
|
rdr.once('error', (err) => {
|
|
501
|
+
if (dst && typeof dst !== 'string' && !dst.destroyed) {
|
|
502
|
+
dst.destroy();
|
|
503
|
+
}
|
|
539
504
|
reject(this.fmtError(`${err.message} ${rPath}`, '_get', err.code));
|
|
540
505
|
});
|
|
541
506
|
if (dst === undefined) {
|
|
542
507
|
// no dst specified, return buffer of data
|
|
543
|
-
this.debugMsg('get
|
|
508
|
+
this.debugMsg('get resolving buffer of data');
|
|
544
509
|
wtr = concat((buff) => {
|
|
545
510
|
resolve(buff);
|
|
546
511
|
});
|
|
@@ -575,8 +540,10 @@ class SftpClient {
|
|
|
575
540
|
});
|
|
576
541
|
rdr.once('end', () => {
|
|
577
542
|
if (typeof dst === 'string') {
|
|
543
|
+
this.debugMsg('get: resolving with dst filename');
|
|
578
544
|
resolve(dst);
|
|
579
|
-
} else {
|
|
545
|
+
} else if (dst !== undefined) {
|
|
546
|
+
this.debugMsg('get: resolving with writer stream object');
|
|
580
547
|
resolve(wtr);
|
|
581
548
|
}
|
|
582
549
|
});
|
|
@@ -591,12 +558,9 @@ class SftpClient {
|
|
|
591
558
|
haveConnection(this, 'get');
|
|
592
559
|
return await this._get(remotePath, dst, options);
|
|
593
560
|
} catch (e) {
|
|
594
|
-
throw e.custom
|
|
595
|
-
? e
|
|
596
|
-
: this.fmtError(`${e.message} ${remotePath}`, 'get', e.code);
|
|
561
|
+
throw e.custom ? e : this.fmtError(`${e.message} ${remotePath}`, 'get', e.code);
|
|
597
562
|
} finally {
|
|
598
563
|
removeTempListeners(this, listeners, 'get');
|
|
599
|
-
this._resetEventFlags();
|
|
600
564
|
}
|
|
601
565
|
}
|
|
602
566
|
|
|
@@ -614,9 +578,7 @@ class SftpClient {
|
|
|
614
578
|
return new Promise((resolve, reject) => {
|
|
615
579
|
this.sftp.fastGet(rPath, lPath, opts, (err) => {
|
|
616
580
|
if (err) {
|
|
617
|
-
reject(
|
|
618
|
-
this.fmtError(`${err.message} Remote: ${rPath} Local: ${lPath}`)
|
|
619
|
-
);
|
|
581
|
+
reject(this.fmtError(`${err.message} Remote: ${rPath} Local: ${lPath}`));
|
|
620
582
|
}
|
|
621
583
|
resolve(`${rPath} was successfully download to ${lPath}!`);
|
|
622
584
|
});
|
|
@@ -630,9 +592,7 @@ class SftpClient {
|
|
|
630
592
|
haveConnection(this, 'fastGet');
|
|
631
593
|
const ftype = await this.exists(remotePath);
|
|
632
594
|
if (ftype !== '-') {
|
|
633
|
-
const msg = `${
|
|
634
|
-
!ftype ? 'No such file ' : 'Not a regular file'
|
|
635
|
-
} ${remotePath}`;
|
|
595
|
+
const msg = `${!ftype ? 'No such file ' : 'Not a regular file'} ${remotePath}`;
|
|
636
596
|
throw this.fmtError(msg, 'fastGet', errorCode.badPath);
|
|
637
597
|
}
|
|
638
598
|
const localCheck = haveLocalCreate(localPath);
|
|
@@ -648,7 +608,6 @@ class SftpClient {
|
|
|
648
608
|
throw this.fmtError(err, 'fastGet');
|
|
649
609
|
} finally {
|
|
650
610
|
removeTempListeners(this, listeners, 'fastGet');
|
|
651
|
-
this._resetEventFlags();
|
|
652
611
|
}
|
|
653
612
|
}
|
|
654
613
|
|
|
@@ -707,7 +666,6 @@ class SftpClient {
|
|
|
707
666
|
throw e.custom ? e : this.fmtError(e.message, 'fastPut', e.code);
|
|
708
667
|
} finally {
|
|
709
668
|
removeTempListeners(this, listeners, 'fastPut');
|
|
710
|
-
this._resetEventFlags();
|
|
711
669
|
}
|
|
712
670
|
}
|
|
713
671
|
|
|
@@ -755,9 +713,7 @@ class SftpClient {
|
|
|
755
713
|
rdr.once('error', (err) => {
|
|
756
714
|
reject(
|
|
757
715
|
this.fmtError(
|
|
758
|
-
`${err.message} ${
|
|
759
|
-
typeof lPath === 'string' ? lPath : '<stream>'
|
|
760
|
-
}`,
|
|
716
|
+
`${err.message} ${typeof lPath === 'string' ? lPath : '<stream>'}`,
|
|
761
717
|
'_put',
|
|
762
718
|
err.code
|
|
763
719
|
)
|
|
@@ -788,7 +744,6 @@ class SftpClient {
|
|
|
788
744
|
throw e.custom ? e : this.fmtError(e.message, 'put', e.code);
|
|
789
745
|
} finally {
|
|
790
746
|
removeTempListeners(this, listeners, 'put');
|
|
791
|
-
this._resetEventFlags();
|
|
792
747
|
}
|
|
793
748
|
}
|
|
794
749
|
|
|
@@ -845,7 +800,6 @@ class SftpClient {
|
|
|
845
800
|
throw e.custom ? e : this.fmtError(e.message, 'append', e.code);
|
|
846
801
|
} finally {
|
|
847
802
|
removeTempListeners(this, listeners, 'append');
|
|
848
|
-
this._resetEventFlags();
|
|
849
803
|
}
|
|
850
804
|
}
|
|
851
805
|
|
|
@@ -936,7 +890,6 @@ class SftpClient {
|
|
|
936
890
|
throw this.fmtError(`${err.message}`, 'mkdir', err.code);
|
|
937
891
|
} finally {
|
|
938
892
|
removeTempListeners(this, listeners, 'append');
|
|
939
|
-
this._resetEventFlags();
|
|
940
893
|
}
|
|
941
894
|
}
|
|
942
895
|
|
|
@@ -977,9 +930,7 @@ class SftpClient {
|
|
|
977
930
|
}
|
|
978
931
|
const promiseList = [];
|
|
979
932
|
for (const f of files) {
|
|
980
|
-
promiseList.push(
|
|
981
|
-
this._delete(`${p}${this.remotePathSep}${f.name}`)
|
|
982
|
-
);
|
|
933
|
+
promiseList.push(this._delete(`${p}${this.remotePathSep}${f.name}`));
|
|
983
934
|
}
|
|
984
935
|
await Promise.all(promiseList);
|
|
985
936
|
}
|
|
@@ -1015,7 +966,6 @@ class SftpClient {
|
|
|
1015
966
|
throw err.custom ? err : this.fmtError(err.message, 'rmdir', err.code);
|
|
1016
967
|
} finally {
|
|
1017
968
|
removeTempListeners(this, listeners, 'rmdir');
|
|
1018
|
-
this._resetEventFlags();
|
|
1019
969
|
}
|
|
1020
970
|
}
|
|
1021
971
|
|
|
@@ -1037,9 +987,7 @@ class SftpClient {
|
|
|
1037
987
|
if (notFoundOK && err.code === 2) {
|
|
1038
988
|
resolve(`Successfully deleted ${rPath}`);
|
|
1039
989
|
} else {
|
|
1040
|
-
reject(
|
|
1041
|
-
this.fmtError(`${err.message} ${rPath}`, 'delete', err.code)
|
|
1042
|
-
);
|
|
990
|
+
reject(this.fmtError(`${err.message} ${rPath}`, 'delete', err.code));
|
|
1043
991
|
}
|
|
1044
992
|
}
|
|
1045
993
|
resolve(`Successfully deleted ${rPath}`);
|
|
@@ -1057,7 +1005,6 @@ class SftpClient {
|
|
|
1057
1005
|
throw err.custom ? err : this.fmtError(err.message, 'delete', err.code);
|
|
1058
1006
|
} finally {
|
|
1059
1007
|
removeTempListeners(this, listeners, 'delete');
|
|
1060
|
-
this._resetEventFlags();
|
|
1061
1008
|
}
|
|
1062
1009
|
}
|
|
1063
1010
|
|
|
@@ -1098,14 +1045,9 @@ class SftpClient {
|
|
|
1098
1045
|
} catch (err) {
|
|
1099
1046
|
throw err.custom
|
|
1100
1047
|
? err
|
|
1101
|
-
: this.fmtError(
|
|
1102
|
-
`${err.message} ${fromPath} ${toPath}`,
|
|
1103
|
-
'rename',
|
|
1104
|
-
err.code
|
|
1105
|
-
);
|
|
1048
|
+
: this.fmtError(`${err.message} ${fromPath} ${toPath}`, 'rename', err.code);
|
|
1106
1049
|
} finally {
|
|
1107
1050
|
removeTempListeners(this, listeners, 'rename');
|
|
1108
|
-
this._resetEventFlags();
|
|
1109
1051
|
}
|
|
1110
1052
|
}
|
|
1111
1053
|
|
|
@@ -1147,14 +1089,9 @@ class SftpClient {
|
|
|
1147
1089
|
} catch (err) {
|
|
1148
1090
|
throw err.custom
|
|
1149
1091
|
? err
|
|
1150
|
-
: this.fmtError(
|
|
1151
|
-
`${err.message} ${fromPath} ${toPath}`,
|
|
1152
|
-
'posixRename',
|
|
1153
|
-
err.code
|
|
1154
|
-
);
|
|
1092
|
+
: this.fmtError(`${err.message} ${fromPath} ${toPath}`, 'posixRename', err.code);
|
|
1155
1093
|
} finally {
|
|
1156
1094
|
removeTempListeners(this, listeners, 'posixRename');
|
|
1157
|
-
this._resetEventFlags();
|
|
1158
1095
|
}
|
|
1159
1096
|
}
|
|
1160
1097
|
|
|
@@ -1191,7 +1128,6 @@ class SftpClient {
|
|
|
1191
1128
|
: this.fmtError(`${err.message} ${remotePath}`, 'chmod', err.code);
|
|
1192
1129
|
} finally {
|
|
1193
1130
|
removeTempListeners(this, listeners, 'chmod');
|
|
1194
|
-
this._resetEventFlags();
|
|
1195
1131
|
}
|
|
1196
1132
|
}
|
|
1197
1133
|
|
|
@@ -1266,9 +1202,7 @@ class SftpClient {
|
|
|
1266
1202
|
}
|
|
1267
1203
|
this.client.emit('upload', { source: newSrc, destination: newDst });
|
|
1268
1204
|
} else {
|
|
1269
|
-
this.debugMsg(
|
|
1270
|
-
`uploadDir: File ignored: ${e.name} not a regular file`
|
|
1271
|
-
);
|
|
1205
|
+
this.debugMsg(`uploadDir: File ignored: ${e.name} not a regular file`);
|
|
1272
1206
|
}
|
|
1273
1207
|
await Promise.all(fileUploads);
|
|
1274
1208
|
}
|
|
@@ -1291,7 +1225,6 @@ class SftpClient {
|
|
|
1291
1225
|
throw err.custom ? err : this.fmtError(err, 'uploadDir');
|
|
1292
1226
|
} finally {
|
|
1293
1227
|
removeTempListeners(this, listeners, 'chmod');
|
|
1294
|
-
this._resetEventFlags();
|
|
1295
1228
|
}
|
|
1296
1229
|
}
|
|
1297
1230
|
|
|
@@ -1353,9 +1286,7 @@ class SftpClient {
|
|
|
1353
1286
|
}
|
|
1354
1287
|
this.client.emit('download', { source: newSrc, destination: newDst });
|
|
1355
1288
|
} else {
|
|
1356
|
-
this.debugMsg(
|
|
1357
|
-
`downloadDir: File ignored: ${f.name} not regular file`
|
|
1358
|
-
);
|
|
1289
|
+
this.debugMsg(`downloadDir: File ignored: ${f.name} not regular file`);
|
|
1359
1290
|
}
|
|
1360
1291
|
}
|
|
1361
1292
|
await Promise.all(downloadFiles);
|
|
@@ -1377,7 +1308,6 @@ class SftpClient {
|
|
|
1377
1308
|
throw err.custom ? err : this.fmtError(err, 'downloadDir', err.code);
|
|
1378
1309
|
} finally {
|
|
1379
1310
|
removeTempListeners(this, listeners, 'downloadDir');
|
|
1380
|
-
this._resetEventFlags();
|
|
1381
1311
|
}
|
|
1382
1312
|
}
|
|
1383
1313
|
|
|
@@ -1402,12 +1332,9 @@ class SftpClient {
|
|
|
1402
1332
|
const stream = this.sftp.createReadStream(remotePath, options);
|
|
1403
1333
|
return stream;
|
|
1404
1334
|
} catch (err) {
|
|
1405
|
-
throw err.custom
|
|
1406
|
-
? err
|
|
1407
|
-
: this.fmtError(err.message, 'createReadStream', err.code);
|
|
1335
|
+
throw err.custom ? err : this.fmtError(err.message, 'createReadStream', err.code);
|
|
1408
1336
|
} finally {
|
|
1409
1337
|
removeTempListeners(this, listeners, 'createReadStreame');
|
|
1410
|
-
this._resetEventFlags();
|
|
1411
1338
|
}
|
|
1412
1339
|
}
|
|
1413
1340
|
|
|
@@ -1432,12 +1359,9 @@ class SftpClient {
|
|
|
1432
1359
|
const stream = this.sftp.createWriteStream(remotePath, options);
|
|
1433
1360
|
return stream;
|
|
1434
1361
|
} catch (err) {
|
|
1435
|
-
throw err.custom
|
|
1436
|
-
? err
|
|
1437
|
-
: this.fmtError(err.message, 'createWriteStream', err.code);
|
|
1362
|
+
throw err.custom ? err : this.fmtError(err.message, 'createWriteStream', err.code);
|
|
1438
1363
|
} finally {
|
|
1439
1364
|
removeTempListeners(this, listeners, 'createWriteStream');
|
|
1440
|
-
this._resetEventFlags();
|
|
1441
1365
|
}
|
|
1442
1366
|
}
|
|
1443
1367
|
|
|
@@ -1486,11 +1410,7 @@ class SftpClient {
|
|
|
1486
1410
|
);
|
|
1487
1411
|
}
|
|
1488
1412
|
if (srcExists !== '-') {
|
|
1489
|
-
throw this.fmtError(
|
|
1490
|
-
`Source not a file ${srcPath}`,
|
|
1491
|
-
'rcopy',
|
|
1492
|
-
errorCode.badPath
|
|
1493
|
-
);
|
|
1413
|
+
throw this.fmtError(`Source not a file ${srcPath}`, 'rcopy', errorCode.badPath);
|
|
1494
1414
|
}
|
|
1495
1415
|
const dstPath = await normalizeRemotePath(this, dst);
|
|
1496
1416
|
const dstExists = await this.exists(dstPath);
|
|
@@ -1501,12 +1421,11 @@ class SftpClient {
|
|
|
1501
1421
|
errorCode.badPath
|
|
1502
1422
|
);
|
|
1503
1423
|
}
|
|
1504
|
-
return
|
|
1424
|
+
return this._rcopy(srcPath, dstPath);
|
|
1505
1425
|
} catch (err) {
|
|
1506
1426
|
throw err.custom ? err : this.fmtError(err, 'rcopy');
|
|
1507
1427
|
} finally {
|
|
1508
1428
|
removeTempListeners(this, listeners, 'rcopy');
|
|
1509
|
-
this._resetEventFlags();
|
|
1510
1429
|
}
|
|
1511
1430
|
}
|
|
1512
1431
|
/**
|
|
@@ -1527,14 +1446,17 @@ class SftpClient {
|
|
|
1527
1446
|
resolve(true);
|
|
1528
1447
|
};
|
|
1529
1448
|
this.on('close', endCloseHandler);
|
|
1530
|
-
if (
|
|
1449
|
+
if (this.client.sftp) {
|
|
1531
1450
|
this.client.end();
|
|
1451
|
+
} else {
|
|
1452
|
+
// no actual connection exists - just resolve
|
|
1453
|
+
this.debugMsg('end: Called when no connection active');
|
|
1454
|
+
resolve(true);
|
|
1532
1455
|
}
|
|
1533
1456
|
}).finally(() => {
|
|
1534
1457
|
removeTempListeners(this, listeners, 'end');
|
|
1535
1458
|
this.removeListener('close', endCloseHandler);
|
|
1536
1459
|
this.endCalled = false;
|
|
1537
|
-
this._resetEventFlags();
|
|
1538
1460
|
});
|
|
1539
1461
|
}
|
|
1540
1462
|
}
|