ssh2-sftp-client 6.0.0 → 6.0.1
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 +9 -1
- package/README.md +11 -2
- package/README.org +8 -0
- package/package.json +6 -3
- package/src/index.js +186 -223
- package/src/utils.js +16 -83
package/CHANGELOG.org
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
* Change Logging
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
** Version 6.0.1
|
|
4
|
+
- Fix issue with connect retry not releasing 'ready' listeners
|
|
5
|
+
- Add finally clauses to all promises to ensure temporary listeners are deleted
|
|
6
|
+
- Add nyc module to report on code test coverage
|
|
7
|
+
- Add additional utils tests to increase test coverage
|
|
8
|
+
- Removed some dead code and unused utility functions to reduce download size
|
|
9
|
+
- Cleanup tests and reduce inter-test dependencies
|
|
10
|
+
|
|
11
|
+
** V6.0.0.0
|
|
4
12
|
- Update connection retry code to use the promise-retry module instead of
|
|
5
13
|
plain rety module
|
|
6
14
|
- Added optional filter argument for uploadDir/downlDir to select which files
|
package/README.md
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
- [Installation](#sec-2)
|
|
3
3
|
- [Basic Usage](#sec-3)
|
|
4
4
|
- [Version 6.x Changes](#sec-4)
|
|
5
|
-
- [Version 6.0.
|
|
5
|
+
- [Version 6.0.1](#sec-4-1)
|
|
6
|
+
- [Version 6.0.0 Changes](#sec-4-2)
|
|
6
7
|
- [Documentation](#sec-5)
|
|
7
8
|
- [Specifying Paths](#sec-5-1)
|
|
8
9
|
- [Methods](#sec-5-2)
|
|
@@ -104,7 +105,15 @@ sftp.connect({
|
|
|
104
105
|
|
|
105
106
|
# Version 6.x Changes<a id="sec-4"></a>
|
|
106
107
|
|
|
107
|
-
## Version 6.0.
|
|
108
|
+
## Version 6.0.1<a id="sec-4-1"></a>
|
|
109
|
+
|
|
110
|
+
- Fix issue with connect retry not releasing 'ready' listener.
|
|
111
|
+
- Add finally clauses to all promises to ensure release of temporary listeners.
|
|
112
|
+
- Add nyc module to improve test coverage
|
|
113
|
+
- Added additional utils tests to improve test coverage
|
|
114
|
+
- Removed some unnecessary util functions to reduce code size
|
|
115
|
+
|
|
116
|
+
## Version 6.0.0 Changes<a id="sec-4-2"></a>
|
|
108
117
|
|
|
109
118
|
- Added new optional argument *notFoundOK* to `delete()` method. If true, no error is thrown when trying to delete a file which does not exist. Default is false.
|
|
110
119
|
- Added new filter argument to `uploadDir()` and `downloadDir()` methods. The filter argument is a regular expression used to match the files and directories to be included in the upload or download. Defaults to match all files and directories.
|
package/README.org
CHANGED
|
@@ -68,6 +68,14 @@ npm install ssh2-sftp-client
|
|
|
68
68
|
#+end_src
|
|
69
69
|
|
|
70
70
|
* Version 6.x Changes
|
|
71
|
+
** Version 6.0.1
|
|
72
|
+
|
|
73
|
+
- Fix issue with connect retry not releasing 'ready' listener.
|
|
74
|
+
- Add finally clauses to all promises to ensure release of temporary listeners.
|
|
75
|
+
- Add nyc module to improve test coverage
|
|
76
|
+
- Added additional utils tests to improve test coverage
|
|
77
|
+
- Removed some unnecessary util functions to reduce code size
|
|
78
|
+
|
|
71
79
|
** Version 6.0.0 Changes
|
|
72
80
|
|
|
73
81
|
- Added new optional argument /notFoundOK/ to ~delete()~ method. If true, no
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ssh2-sftp-client",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.1",
|
|
4
4
|
"description": "ssh2 sftp client for node",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"repository": {
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
},
|
|
10
10
|
"keywords": ["sftp", "nodejs", "promises"],
|
|
11
11
|
"scripts": {
|
|
12
|
-
"test": "mocha"
|
|
12
|
+
"test": "mocha",
|
|
13
|
+
"coverage": "nyc npm run test"
|
|
13
14
|
},
|
|
14
15
|
"author": "Tim Cross",
|
|
15
16
|
"email": "theophilusx@gmail.com",
|
|
@@ -23,7 +24,8 @@
|
|
|
23
24
|
"dependencies": {
|
|
24
25
|
"concat-stream": "^2.0.0",
|
|
25
26
|
"promise-retry": "^2.0.1",
|
|
26
|
-
"ssh2": "^0.8.9"
|
|
27
|
+
"ssh2": "^0.8.9",
|
|
28
|
+
"winston": "^3.3.3"
|
|
27
29
|
},
|
|
28
30
|
"devDependencies": {
|
|
29
31
|
"chai": "^4.2.0",
|
|
@@ -33,6 +35,7 @@
|
|
|
33
35
|
"dotenv": "^8.2.0",
|
|
34
36
|
"mocha": "^8.2.1",
|
|
35
37
|
"moment": "^2.29.1",
|
|
38
|
+
"nyc": "^15.1.0",
|
|
36
39
|
"through2": "^4.0.2"
|
|
37
40
|
}
|
|
38
41
|
}
|
package/src/index.js
CHANGED
|
@@ -7,10 +7,16 @@
|
|
|
7
7
|
const {Client} = require('ssh2');
|
|
8
8
|
const fs = require('fs');
|
|
9
9
|
const concat = require('concat-stream');
|
|
10
|
-
//const retry = require('retry');
|
|
11
10
|
const promiseRetry = require('promise-retry');
|
|
12
11
|
const {join, parse} = require('path');
|
|
13
|
-
const
|
|
12
|
+
const {
|
|
13
|
+
fmtError,
|
|
14
|
+
addTempListeners,
|
|
15
|
+
removeTempListeners,
|
|
16
|
+
haveConnection,
|
|
17
|
+
normalizeRemotePath,
|
|
18
|
+
localExists
|
|
19
|
+
} = require('./utils');
|
|
14
20
|
const {errorCode} = require('./constants');
|
|
15
21
|
|
|
16
22
|
class SftpClient {
|
|
@@ -38,7 +44,7 @@ class SftpClient {
|
|
|
38
44
|
});
|
|
39
45
|
this.client.on('error', (err) => {
|
|
40
46
|
if (!this.errorHandled) {
|
|
41
|
-
throw
|
|
47
|
+
throw fmtError(
|
|
42
48
|
`Unexpected error: ${err.message}`,
|
|
43
49
|
'global-error-handler',
|
|
44
50
|
err.code
|
|
@@ -92,30 +98,49 @@ class SftpClient {
|
|
|
92
98
|
*
|
|
93
99
|
*/
|
|
94
100
|
sftpConnect(config) {
|
|
101
|
+
let connectReady;
|
|
102
|
+
|
|
95
103
|
return new Promise((resolve, reject) => {
|
|
96
|
-
|
|
104
|
+
addTempListeners(this, 'sftpConnect', reject);
|
|
105
|
+
connectReady = () => {
|
|
97
106
|
this.client.sftp((err, sftp) => {
|
|
98
107
|
if (err) {
|
|
99
108
|
this.debugMsg(`SFTP channel error: ${err.message} ${err.code}`);
|
|
100
|
-
reject(
|
|
109
|
+
reject(fmtError(err, 'sftpConnect', err.code));
|
|
101
110
|
} else {
|
|
102
|
-
|
|
111
|
+
this.debugMsg('SFTP channel established');
|
|
103
112
|
resolve(sftp);
|
|
104
113
|
}
|
|
105
|
-
this.client.removeListener('ready', connectReady);
|
|
106
114
|
});
|
|
107
115
|
};
|
|
108
|
-
|
|
116
|
+
// addTempListeners(this, 'sftpConnect', reject);
|
|
109
117
|
this.client.on('ready', connectReady).connect(config);
|
|
118
|
+
}).finally((rsp) => {
|
|
119
|
+
this.removeListener('ready', connectReady);
|
|
120
|
+
removeTempListeners(this.client);
|
|
121
|
+
return rsp;
|
|
110
122
|
});
|
|
111
123
|
}
|
|
112
124
|
|
|
113
|
-
|
|
125
|
+
connect(config) {
|
|
126
|
+
if (config.debug) {
|
|
127
|
+
this.debug = config.debug;
|
|
128
|
+
this.debugMsg('Debugging turned on');
|
|
129
|
+
}
|
|
130
|
+
if (this.sftp) {
|
|
131
|
+
this.debugMsg('Already connected - reject');
|
|
132
|
+
return Promise.reject(
|
|
133
|
+
fmtError(
|
|
134
|
+
'An existing SFTP connection is already defined',
|
|
135
|
+
'connect',
|
|
136
|
+
errorCode.connect
|
|
137
|
+
)
|
|
138
|
+
);
|
|
139
|
+
}
|
|
114
140
|
return promiseRetry(
|
|
115
141
|
(retry, attempt) => {
|
|
116
142
|
this.debugMsg(`Connect attempt ${attempt}`);
|
|
117
143
|
return this.sftpConnect(config).catch((err) => {
|
|
118
|
-
utils.removeTempListeners(this.client);
|
|
119
144
|
retry(err);
|
|
120
145
|
});
|
|
121
146
|
},
|
|
@@ -124,30 +149,9 @@ class SftpClient {
|
|
|
124
149
|
factor: config.retry_factor || 2,
|
|
125
150
|
minTimeout: config.retry_minTimeout || 1000
|
|
126
151
|
}
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
async connect(config) {
|
|
131
|
-
try {
|
|
132
|
-
if (config.debug) {
|
|
133
|
-
this.debug = config.debug;
|
|
134
|
-
this.debugMsg('Debugging turned on');
|
|
135
|
-
}
|
|
136
|
-
if (this.sftp) {
|
|
137
|
-
this.debugMsg('Already connected - reject');
|
|
138
|
-
throw utils.formatError(
|
|
139
|
-
'An existing SFTP connection is already defined',
|
|
140
|
-
'connect',
|
|
141
|
-
errorCode.connect
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
//this.sftp = await this.sftpConnect(config);
|
|
145
|
-
this.sftp = await this.retryConnect(config);
|
|
146
|
-
this.debugMsg('SFTP Connection established');
|
|
147
|
-
utils.removeTempListeners(this.client);
|
|
148
|
-
} catch (err) {
|
|
149
|
-
throw utils.formatError(err.message, 'connect', err.errorCode);
|
|
150
|
-
}
|
|
152
|
+
).then((sftp) => {
|
|
153
|
+
this.sftp = sftp;
|
|
154
|
+
});
|
|
151
155
|
}
|
|
152
156
|
|
|
153
157
|
/**
|
|
@@ -165,8 +169,8 @@ class SftpClient {
|
|
|
165
169
|
realPath(remotePath) {
|
|
166
170
|
return new Promise((resolve, reject) => {
|
|
167
171
|
this.debugMsg(`realPath -> ${remotePath}`);
|
|
168
|
-
|
|
169
|
-
if (
|
|
172
|
+
addTempListeners(this, 'realPath', reject);
|
|
173
|
+
if (haveConnection(this, 'realPath', reject)) {
|
|
170
174
|
this.sftp.realpath(remotePath, (err, absPath) => {
|
|
171
175
|
if (err) {
|
|
172
176
|
this.debugMsg(`realPath Error: ${err.message} Code: ${err.code}`);
|
|
@@ -174,19 +178,17 @@ class SftpClient {
|
|
|
174
178
|
resolve('');
|
|
175
179
|
} else {
|
|
176
180
|
reject(
|
|
177
|
-
|
|
178
|
-
`${err.message} ${remotePath}`,
|
|
179
|
-
'realPath',
|
|
180
|
-
err.code
|
|
181
|
-
)
|
|
181
|
+
fmtError(`${err.message} ${remotePath}`, 'realPath', err.code)
|
|
182
182
|
);
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
185
|
this.debugMsg(`realPath <- ${absPath}`);
|
|
186
186
|
resolve(absPath);
|
|
187
|
-
utils.removeTempListeners(this.client);
|
|
188
187
|
});
|
|
189
188
|
}
|
|
189
|
+
}).finally((rsp) => {
|
|
190
|
+
removeTempListeners(this.client);
|
|
191
|
+
return rsp;
|
|
190
192
|
});
|
|
191
193
|
}
|
|
192
194
|
|
|
@@ -204,13 +206,13 @@ class SftpClient {
|
|
|
204
206
|
const _stat = (aPath) => {
|
|
205
207
|
return new Promise((resolve, reject) => {
|
|
206
208
|
this.debugMsg(`stat -> ${aPath}`);
|
|
207
|
-
|
|
209
|
+
addTempListeners(this, 'stat', reject);
|
|
208
210
|
this.sftp.stat(aPath, (err, stats) => {
|
|
209
211
|
if (err) {
|
|
210
212
|
this.debugMsg(`stat error ${err.message} code: ${err.code}`);
|
|
211
213
|
if (err.code === 2 || err.code === 4) {
|
|
212
214
|
reject(
|
|
213
|
-
|
|
215
|
+
fmtError(
|
|
214
216
|
`No such file: ${remotePath}`,
|
|
215
217
|
'_stat',
|
|
216
218
|
errorCode.notexist
|
|
@@ -218,11 +220,7 @@ class SftpClient {
|
|
|
218
220
|
);
|
|
219
221
|
} else {
|
|
220
222
|
reject(
|
|
221
|
-
|
|
222
|
-
`${err.message} ${remotePath}`,
|
|
223
|
-
'_stat',
|
|
224
|
-
err.code
|
|
225
|
-
)
|
|
223
|
+
fmtError(`${err.message} ${remotePath}`, '_stat', err.code)
|
|
226
224
|
);
|
|
227
225
|
}
|
|
228
226
|
} else {
|
|
@@ -243,17 +241,23 @@ class SftpClient {
|
|
|
243
241
|
isSocket: stats.isSocket()
|
|
244
242
|
});
|
|
245
243
|
}
|
|
246
|
-
utils.removeTempListeners(this.client);
|
|
247
244
|
});
|
|
245
|
+
}).finally((rsp) => {
|
|
246
|
+
removeTempListeners(this.client);
|
|
247
|
+
return rsp;
|
|
248
248
|
});
|
|
249
249
|
};
|
|
250
250
|
|
|
251
251
|
try {
|
|
252
|
-
|
|
253
|
-
let absPath = await
|
|
252
|
+
haveConnection(this, 'stat');
|
|
253
|
+
let absPath = await normalizeRemotePath(this, remotePath);
|
|
254
254
|
return _stat(absPath);
|
|
255
255
|
} catch (err) {
|
|
256
|
-
|
|
256
|
+
if (err.custom) {
|
|
257
|
+
throw err;
|
|
258
|
+
} else {
|
|
259
|
+
throw fmtError(err, 'stat', err.code);
|
|
260
|
+
}
|
|
257
261
|
}
|
|
258
262
|
}
|
|
259
263
|
|
|
@@ -270,11 +274,11 @@ class SftpClient {
|
|
|
270
274
|
*/
|
|
271
275
|
async exists(remotePath) {
|
|
272
276
|
try {
|
|
273
|
-
if (
|
|
277
|
+
if (haveConnection(this, 'exists')) {
|
|
274
278
|
if (remotePath === '.') {
|
|
275
279
|
return 'd';
|
|
276
280
|
}
|
|
277
|
-
let absPath = await
|
|
281
|
+
let absPath = await normalizeRemotePath(this, remotePath);
|
|
278
282
|
try {
|
|
279
283
|
this.debugMsg(`exists -> ${absPath}`);
|
|
280
284
|
let info = await this.stat(absPath);
|
|
@@ -299,7 +303,11 @@ class SftpClient {
|
|
|
299
303
|
return false;
|
|
300
304
|
}
|
|
301
305
|
} catch (err) {
|
|
302
|
-
|
|
306
|
+
if (err.custom) {
|
|
307
|
+
throw err;
|
|
308
|
+
} else {
|
|
309
|
+
throw fmtError(err, 'exists', err.code);
|
|
310
|
+
}
|
|
303
311
|
}
|
|
304
312
|
}
|
|
305
313
|
|
|
@@ -319,20 +327,14 @@ class SftpClient {
|
|
|
319
327
|
*/
|
|
320
328
|
list(remotePath, pattern = /.*/) {
|
|
321
329
|
return new Promise((resolve, reject) => {
|
|
322
|
-
if (
|
|
330
|
+
if (haveConnection(this, 'list', reject)) {
|
|
323
331
|
const reg = /-/gi;
|
|
324
332
|
this.debugMsg(`list -> ${remotePath} filter -> ${pattern}`);
|
|
325
|
-
|
|
333
|
+
addTempListeners(this, 'list', reject);
|
|
326
334
|
this.sftp.readdir(remotePath, (err, fileList) => {
|
|
327
335
|
if (err) {
|
|
328
336
|
this.debugMsg(`list error ${err.message} code: ${err.code}`);
|
|
329
|
-
reject(
|
|
330
|
-
utils.formatError(
|
|
331
|
-
`${err.message} ${remotePath}`,
|
|
332
|
-
'list',
|
|
333
|
-
err.code
|
|
334
|
-
)
|
|
335
|
-
);
|
|
337
|
+
reject(fmtError(`${err.message} ${remotePath}`, 'list', err.code));
|
|
336
338
|
} else {
|
|
337
339
|
this.debugMsg('list <- ', fileList);
|
|
338
340
|
let newList = [];
|
|
@@ -365,9 +367,11 @@ class SftpClient {
|
|
|
365
367
|
}
|
|
366
368
|
resolve(newList.filter((item) => regex.test(item.name)));
|
|
367
369
|
}
|
|
368
|
-
utils.removeTempListeners(this.client);
|
|
369
370
|
});
|
|
370
371
|
}
|
|
372
|
+
}).finally((rsp) => {
|
|
373
|
+
removeTempListeners(this.client);
|
|
374
|
+
return rsp;
|
|
371
375
|
});
|
|
372
376
|
}
|
|
373
377
|
|
|
@@ -387,16 +391,12 @@ class SftpClient {
|
|
|
387
391
|
*/
|
|
388
392
|
get(remotePath, dst, options = {}) {
|
|
389
393
|
return new Promise((resolve, reject) => {
|
|
390
|
-
if (
|
|
394
|
+
if (haveConnection(this, 'get', reject)) {
|
|
391
395
|
this.debugMsg(`get -> ${remotePath} `, options);
|
|
392
|
-
|
|
396
|
+
addTempListeners(this, 'get', reject);
|
|
393
397
|
let rdr = this.sftp.createReadStream(remotePath, options);
|
|
394
398
|
rdr.once('error', (err) => {
|
|
395
|
-
|
|
396
|
-
reject(
|
|
397
|
-
utils.formatError(`${err.message} ${remotePath}`, 'get', err.code)
|
|
398
|
-
);
|
|
399
|
-
utils.removeTempListeners(this.client);
|
|
399
|
+
reject(fmtError(`${err.message} ${remotePath}`, 'get', err.code));
|
|
400
400
|
});
|
|
401
401
|
if (dst === undefined) {
|
|
402
402
|
// no dst specified, return buffer of data
|
|
@@ -404,7 +404,6 @@ class SftpClient {
|
|
|
404
404
|
let concatStream = concat((buff) => {
|
|
405
405
|
rdr.removeAllListeners('error');
|
|
406
406
|
resolve(buff);
|
|
407
|
-
utils.removeTempListeners(this.client);
|
|
408
407
|
});
|
|
409
408
|
rdr.pipe(concatStream);
|
|
410
409
|
} else {
|
|
@@ -418,9 +417,8 @@ class SftpClient {
|
|
|
418
417
|
wtr = dst;
|
|
419
418
|
}
|
|
420
419
|
wtr.once('error', (err) => {
|
|
421
|
-
utils.removeListeners(rdr);
|
|
422
420
|
reject(
|
|
423
|
-
|
|
421
|
+
fmtError(
|
|
424
422
|
`${err.message} ${typeof dst === 'string' ? dst : ''}`,
|
|
425
423
|
'get',
|
|
426
424
|
err.code
|
|
@@ -429,10 +427,8 @@ class SftpClient {
|
|
|
429
427
|
if (options.autoClose === false) {
|
|
430
428
|
rdr.destroy();
|
|
431
429
|
}
|
|
432
|
-
utils.removeTempListeners(this.client);
|
|
433
430
|
});
|
|
434
431
|
wtr.once('finish', () => {
|
|
435
|
-
utils.removeListeners(rdr);
|
|
436
432
|
if (options.autoClose === false) {
|
|
437
433
|
rdr.destroy();
|
|
438
434
|
}
|
|
@@ -441,11 +437,13 @@ class SftpClient {
|
|
|
441
437
|
} else {
|
|
442
438
|
resolve(wtr);
|
|
443
439
|
}
|
|
444
|
-
utils.removeTempListeners(this.client);
|
|
445
440
|
});
|
|
446
441
|
rdr.pipe(wtr);
|
|
447
442
|
}
|
|
448
443
|
}
|
|
444
|
+
}).finally((rsp) => {
|
|
445
|
+
removeTempListeners(this.client);
|
|
446
|
+
return rsp;
|
|
449
447
|
});
|
|
450
448
|
}
|
|
451
449
|
|
|
@@ -470,30 +468,30 @@ class SftpClient {
|
|
|
470
468
|
ftype === false
|
|
471
469
|
? `No such file ${remotePath}`
|
|
472
470
|
: `Not a regular file ${remotePath}`;
|
|
473
|
-
return Promise.reject(
|
|
474
|
-
utils.formatError(msg, 'fastGet', errorCode.badPath)
|
|
475
|
-
);
|
|
471
|
+
return Promise.reject(fmtError(msg, 'fastGet', errorCode.badPath));
|
|
476
472
|
}
|
|
477
473
|
})
|
|
478
474
|
.then(() => {
|
|
479
475
|
return new Promise((resolve, reject) => {
|
|
480
|
-
if (
|
|
476
|
+
if (haveConnection(this, 'fastGet', reject)) {
|
|
481
477
|
this.debugMsg(
|
|
482
478
|
`fastGet -> remote: ${remotePath} local: ${localPath} `,
|
|
483
479
|
options
|
|
484
480
|
);
|
|
485
|
-
|
|
481
|
+
addTempListeners(this, 'fastGet', reject);
|
|
486
482
|
this.sftp.fastGet(remotePath, localPath, options, (err) => {
|
|
487
483
|
if (err) {
|
|
488
484
|
this.debugMsg(`fastGet error ${err.message} code: ${err.code}`);
|
|
489
|
-
reject(
|
|
485
|
+
reject(fmtError(err, 'fastGet'));
|
|
490
486
|
}
|
|
491
487
|
resolve(
|
|
492
488
|
`${remotePath} was successfully download to ${localPath}!`
|
|
493
489
|
);
|
|
494
|
-
utils.removeTempListeners(this.client);
|
|
495
490
|
});
|
|
496
491
|
}
|
|
492
|
+
}).finally((rsp) => {
|
|
493
|
+
removeTempListeners(this.client);
|
|
494
|
+
return rsp;
|
|
497
495
|
});
|
|
498
496
|
});
|
|
499
497
|
}
|
|
@@ -513,18 +511,13 @@ class SftpClient {
|
|
|
513
511
|
*/
|
|
514
512
|
fastPut(localPath, remotePath, options) {
|
|
515
513
|
this.debugMsg(`fastPut -> local ${localPath} remote ${remotePath}`);
|
|
516
|
-
return
|
|
517
|
-
.localExists(localPath)
|
|
514
|
+
return localExists(localPath)
|
|
518
515
|
.then((localStatus) => {
|
|
519
516
|
this.debugMsg(`fastPut <- localStatus ${localStatus}`);
|
|
520
517
|
if (localStatus !== '-') {
|
|
521
518
|
this.debugMsg('fastPut reject bad source path');
|
|
522
519
|
return Promise.reject(
|
|
523
|
-
|
|
524
|
-
`Bad path ${localPath}`,
|
|
525
|
-
'fastPut',
|
|
526
|
-
errorCode.badPath
|
|
527
|
-
)
|
|
520
|
+
fmtError(`Bad path ${localPath}`, 'fastPut', errorCode.badPath)
|
|
528
521
|
);
|
|
529
522
|
}
|
|
530
523
|
return new Promise((resolve, reject) => {
|
|
@@ -532,11 +525,7 @@ class SftpClient {
|
|
|
532
525
|
if (err) {
|
|
533
526
|
this.debugMsg('fastPut reject no access source');
|
|
534
527
|
reject(
|
|
535
|
-
|
|
536
|
-
`${err.message} ${localPath}`,
|
|
537
|
-
'fastPut',
|
|
538
|
-
err.code
|
|
539
|
-
)
|
|
528
|
+
fmtError(`${err.message} ${localPath}`, 'fastPut', err.code)
|
|
540
529
|
);
|
|
541
530
|
} else {
|
|
542
531
|
this.debugMsg('fastPut source access ok');
|
|
@@ -547,18 +536,18 @@ class SftpClient {
|
|
|
547
536
|
})
|
|
548
537
|
.then(() => {
|
|
549
538
|
return new Promise((resolve, reject) => {
|
|
550
|
-
if (
|
|
539
|
+
if (haveConnection(this, 'fastPut', reject)) {
|
|
551
540
|
this.debugMsg(
|
|
552
541
|
`fastPut -> local: ${localPath} remote: ${remotePath} opts: ${JSON.stringify(
|
|
553
542
|
options
|
|
554
543
|
)}`
|
|
555
544
|
);
|
|
556
|
-
|
|
545
|
+
addTempListeners(this, 'fastPut', reject);
|
|
557
546
|
this.sftp.fastPut(localPath, remotePath, options, (err) => {
|
|
558
547
|
if (err) {
|
|
559
548
|
this.debugMsg(`fastPut error ${err.message} ${err.code}`);
|
|
560
549
|
reject(
|
|
561
|
-
|
|
550
|
+
fmtError(
|
|
562
551
|
`${err.message} Local: ${localPath} Remote: ${remotePath}`,
|
|
563
552
|
'fastPut',
|
|
564
553
|
err.code
|
|
@@ -571,11 +560,10 @@ class SftpClient {
|
|
|
571
560
|
);
|
|
572
561
|
});
|
|
573
562
|
}
|
|
563
|
+
}).finally((rsp) => {
|
|
564
|
+
removeTempListeners(this.client);
|
|
565
|
+
return rsp;
|
|
574
566
|
});
|
|
575
|
-
})
|
|
576
|
-
.then((msg) => {
|
|
577
|
-
utils.removeTempListeners(this.client);
|
|
578
|
-
return msg;
|
|
579
567
|
});
|
|
580
568
|
}
|
|
581
569
|
|
|
@@ -597,13 +585,12 @@ class SftpClient {
|
|
|
597
585
|
} -> ${remotePath}`,
|
|
598
586
|
options
|
|
599
587
|
);
|
|
600
|
-
return
|
|
601
|
-
.localExists(typeof localSrc === 'string' ? localSrc : 'dummy')
|
|
588
|
+
return localExists(typeof localSrc === 'string' ? localSrc : 'dummy')
|
|
602
589
|
.then((localStatus) => {
|
|
603
590
|
if (typeof localSrc === 'string' && localStatus !== '-') {
|
|
604
591
|
this.debugMsg(`put: file does not exist ${localSrc} - rejecting`);
|
|
605
592
|
return Promise.reject(
|
|
606
|
-
|
|
593
|
+
fmtError(`Bad path ${localSrc}`, 'put', errorCode.badPath)
|
|
607
594
|
);
|
|
608
595
|
}
|
|
609
596
|
return new Promise((resolve, reject) => {
|
|
@@ -615,7 +602,7 @@ class SftpClient {
|
|
|
615
602
|
if (err) {
|
|
616
603
|
this.debugMsg(`put: Cannot read ${localSrc} - rejecting`);
|
|
617
604
|
reject(
|
|
618
|
-
|
|
605
|
+
fmtError(
|
|
619
606
|
`Permission denied ${localSrc}`,
|
|
620
607
|
'put',
|
|
621
608
|
errorCode.permission
|
|
@@ -635,26 +622,17 @@ class SftpClient {
|
|
|
635
622
|
})
|
|
636
623
|
.then(() => {
|
|
637
624
|
return new Promise((resolve, reject) => {
|
|
638
|
-
if (
|
|
639
|
-
|
|
625
|
+
if (haveConnection(this, 'put', reject)) {
|
|
626
|
+
addTempListeners(this, 'put', reject);
|
|
640
627
|
let stream = this.sftp.createWriteStream(remotePath, options);
|
|
641
628
|
stream.once('error', (err) => {
|
|
642
|
-
reject(
|
|
643
|
-
utils.formatError(
|
|
644
|
-
`${err.message} ${remotePath}`,
|
|
645
|
-
'put',
|
|
646
|
-
err.code
|
|
647
|
-
)
|
|
648
|
-
);
|
|
649
|
-
utils.removeTempListeners(this.client);
|
|
629
|
+
reject(fmtError(`${err.message} ${remotePath}`, 'put', err.code));
|
|
650
630
|
});
|
|
651
631
|
stream.once('finish', () => {
|
|
652
|
-
utils.removeListeners(stream);
|
|
653
632
|
if (options.autoClose === false) {
|
|
654
633
|
stream.destroy();
|
|
655
634
|
}
|
|
656
635
|
resolve(`Uploaded data stream to ${remotePath}`);
|
|
657
|
-
utils.removeTempListeners(this.client);
|
|
658
636
|
});
|
|
659
637
|
if (localSrc instanceof Buffer) {
|
|
660
638
|
this.debugMsg('put source is a buffer');
|
|
@@ -669,9 +647,8 @@ class SftpClient {
|
|
|
669
647
|
rdr = localSrc;
|
|
670
648
|
}
|
|
671
649
|
rdr.once('error', (err) => {
|
|
672
|
-
utils.removeListeners(stream);
|
|
673
650
|
reject(
|
|
674
|
-
|
|
651
|
+
fmtError(
|
|
675
652
|
`${err.message} ${
|
|
676
653
|
typeof localSrc === 'string' ? localSrc : ''
|
|
677
654
|
}`,
|
|
@@ -682,11 +659,13 @@ class SftpClient {
|
|
|
682
659
|
if (options.autoClose === false) {
|
|
683
660
|
stream.destroy();
|
|
684
661
|
}
|
|
685
|
-
utils.removeTempListeners(this.client);
|
|
686
662
|
});
|
|
687
663
|
rdr.pipe(stream);
|
|
688
664
|
}
|
|
689
665
|
}
|
|
666
|
+
}).finally((rsp) => {
|
|
667
|
+
removeTempListeners(this.client);
|
|
668
|
+
return rsp;
|
|
690
669
|
});
|
|
691
670
|
});
|
|
692
671
|
}
|
|
@@ -701,31 +680,21 @@ class SftpClient {
|
|
|
701
680
|
*/
|
|
702
681
|
append(input, remotePath, options = {}) {
|
|
703
682
|
return new Promise((resolve, reject) => {
|
|
704
|
-
if (
|
|
683
|
+
if (haveConnection(this, 'append', reject)) {
|
|
705
684
|
if (typeof input === 'string') {
|
|
706
|
-
reject(
|
|
707
|
-
utils.formatError('Cannot append one file to another', 'append')
|
|
708
|
-
);
|
|
685
|
+
reject(fmtError('Cannot append one file to another', 'append'));
|
|
709
686
|
} else {
|
|
710
687
|
this.debugMsg(`append -> remote: ${remotePath} `, options);
|
|
711
|
-
|
|
688
|
+
addTempListeners(this, 'append', reject);
|
|
712
689
|
options.flags = 'a';
|
|
713
690
|
let stream = this.sftp.createWriteStream(remotePath, options);
|
|
714
691
|
stream.once('error', (err) => {
|
|
715
|
-
utils.removeListeners(stream);
|
|
716
692
|
reject(
|
|
717
|
-
|
|
718
|
-
`${err.message} ${remotePath}`,
|
|
719
|
-
'append',
|
|
720
|
-
err.code
|
|
721
|
-
)
|
|
693
|
+
fmtError(`${err.message} ${remotePath}`, 'append', err.code)
|
|
722
694
|
);
|
|
723
|
-
utils.removeTempListeners(this.client);
|
|
724
695
|
});
|
|
725
696
|
stream.once('finish', () => {
|
|
726
|
-
utils.removeListeners(stream);
|
|
727
697
|
resolve(`Appended data to ${remotePath}`);
|
|
728
|
-
utils.removeTempListeners(this.client);
|
|
729
698
|
});
|
|
730
699
|
if (input instanceof Buffer) {
|
|
731
700
|
stream.end(input);
|
|
@@ -734,6 +703,9 @@ class SftpClient {
|
|
|
734
703
|
}
|
|
735
704
|
}
|
|
736
705
|
}
|
|
706
|
+
}).finally((rsp) => {
|
|
707
|
+
removeTempListeners(this.client);
|
|
708
|
+
return rsp;
|
|
737
709
|
});
|
|
738
710
|
}
|
|
739
711
|
|
|
@@ -750,23 +722,23 @@ class SftpClient {
|
|
|
750
722
|
const _mkdir = (p) => {
|
|
751
723
|
return new Promise((resolve, reject) => {
|
|
752
724
|
this.debugMsg(`mkdir -> ${p}`);
|
|
753
|
-
|
|
725
|
+
addTempListeners(this, 'mkdir', reject);
|
|
754
726
|
this.sftp.mkdir(p, (err) => {
|
|
755
727
|
if (err) {
|
|
756
728
|
this.debugMsg(`mkdir error ${err.message} code: ${err.code}`);
|
|
757
|
-
reject(
|
|
758
|
-
utils.formatError(`${err.message} ${p}`, '_mkdir', err.code)
|
|
759
|
-
);
|
|
729
|
+
reject(fmtError(`${err.message} ${p}`, '_mkdir', err.code));
|
|
760
730
|
}
|
|
761
731
|
resolve(`${p} directory created`);
|
|
762
|
-
utils.removeTempListeners(this.client);
|
|
763
732
|
});
|
|
733
|
+
}).finally((rsp) => {
|
|
734
|
+
removeTempListeners(this.client);
|
|
735
|
+
return rsp;
|
|
764
736
|
});
|
|
765
737
|
};
|
|
766
738
|
|
|
767
739
|
try {
|
|
768
|
-
|
|
769
|
-
let rPath = await
|
|
740
|
+
haveConnection(this, 'mkdir');
|
|
741
|
+
let rPath = await normalizeRemotePath(this, remotePath);
|
|
770
742
|
if (!recursive) {
|
|
771
743
|
return _mkdir(rPath);
|
|
772
744
|
}
|
|
@@ -779,7 +751,11 @@ class SftpClient {
|
|
|
779
751
|
}
|
|
780
752
|
return _mkdir(rPath);
|
|
781
753
|
} catch (err) {
|
|
782
|
-
|
|
754
|
+
if (err.custom) {
|
|
755
|
+
throw err;
|
|
756
|
+
} else {
|
|
757
|
+
throw fmtError(`${err.message} ${remotePath}`, 'mkdir', err.code);
|
|
758
|
+
}
|
|
783
759
|
}
|
|
784
760
|
}
|
|
785
761
|
|
|
@@ -797,23 +773,23 @@ class SftpClient {
|
|
|
797
773
|
const _rmdir = (p) => {
|
|
798
774
|
return new Promise((resolve, reject) => {
|
|
799
775
|
this.debugMsg(`rmdir -> ${p}`);
|
|
800
|
-
|
|
776
|
+
addTempListeners(this, 'rmdir', reject);
|
|
801
777
|
this.sftp.rmdir(p, (err) => {
|
|
802
778
|
if (err) {
|
|
803
779
|
this.debugMsg(`rmdir error ${err.message} code: ${err.code}`);
|
|
804
|
-
reject(
|
|
805
|
-
utils.formatError(`${err.message} ${p}`, '_rmdir', err.code)
|
|
806
|
-
);
|
|
780
|
+
reject(fmtError(`${err.message} ${p}`, '_rmdir', err.code));
|
|
807
781
|
}
|
|
808
782
|
resolve('Successfully removed directory');
|
|
809
|
-
utils.removeTempListeners(this.client);
|
|
810
783
|
});
|
|
784
|
+
}).finally((rsp) => {
|
|
785
|
+
removeTempListeners(this.client);
|
|
786
|
+
return rsp;
|
|
811
787
|
});
|
|
812
788
|
};
|
|
813
789
|
|
|
814
790
|
try {
|
|
815
|
-
|
|
816
|
-
let absPath = await
|
|
791
|
+
haveConnection(this, 'rmdir');
|
|
792
|
+
let absPath = await normalizeRemotePath(this, remotePath);
|
|
817
793
|
if (!recursive) {
|
|
818
794
|
return _rmdir(absPath);
|
|
819
795
|
}
|
|
@@ -832,7 +808,11 @@ class SftpClient {
|
|
|
832
808
|
}
|
|
833
809
|
return _rmdir(absPath);
|
|
834
810
|
} catch (err) {
|
|
835
|
-
|
|
811
|
+
if (err.custom) {
|
|
812
|
+
throw err;
|
|
813
|
+
} else {
|
|
814
|
+
throw fmtError(err, 'rmdir', err.code);
|
|
815
|
+
}
|
|
836
816
|
}
|
|
837
817
|
}
|
|
838
818
|
|
|
@@ -849,9 +829,9 @@ class SftpClient {
|
|
|
849
829
|
*/
|
|
850
830
|
delete(remotePath, notFoundOK = false) {
|
|
851
831
|
return new Promise((resolve, reject) => {
|
|
852
|
-
if (
|
|
832
|
+
if (haveConnection(this, 'delete', reject)) {
|
|
853
833
|
this.debugMsg(`delete -> ${remotePath}`);
|
|
854
|
-
|
|
834
|
+
addTempListeners(this, 'delete', reject);
|
|
855
835
|
this.sftp.unlink(remotePath, (err) => {
|
|
856
836
|
if (err) {
|
|
857
837
|
this.debugMsg(`delete error ${err.message} code: ${err.code}`);
|
|
@@ -860,18 +840,16 @@ class SftpClient {
|
|
|
860
840
|
resolve(`Successfully deleted ${remotePath}`);
|
|
861
841
|
} else {
|
|
862
842
|
reject(
|
|
863
|
-
|
|
864
|
-
`${err.message} ${remotePath}`,
|
|
865
|
-
'delete',
|
|
866
|
-
err.code
|
|
867
|
-
)
|
|
843
|
+
fmtError(`${err.message} ${remotePath}`, 'delete', err.code)
|
|
868
844
|
);
|
|
869
845
|
}
|
|
870
846
|
}
|
|
871
847
|
resolve(`Successfully deleted ${remotePath}`);
|
|
872
|
-
utils.removeTempListeners(this.client);
|
|
873
848
|
});
|
|
874
849
|
}
|
|
850
|
+
}).finally((rsp) => {
|
|
851
|
+
removeTempListeners(this.client);
|
|
852
|
+
return rsp;
|
|
875
853
|
});
|
|
876
854
|
}
|
|
877
855
|
|
|
@@ -888,14 +866,14 @@ class SftpClient {
|
|
|
888
866
|
*/
|
|
889
867
|
rename(fromPath, toPath) {
|
|
890
868
|
return new Promise((resolve, reject) => {
|
|
891
|
-
if (
|
|
869
|
+
if (haveConnection(this, 'rename', reject)) {
|
|
892
870
|
this.debugMsg(`rename -> ${fromPath} ${toPath}`);
|
|
893
|
-
|
|
871
|
+
addTempListeners(this, 'rename', reject);
|
|
894
872
|
this.sftp.rename(fromPath, toPath, (err) => {
|
|
895
873
|
if (err) {
|
|
896
874
|
this.debugMsg(`rename error ${err.message} code: ${err.code}`);
|
|
897
875
|
reject(
|
|
898
|
-
|
|
876
|
+
fmtError(
|
|
899
877
|
`${err.message} From: ${fromPath} To: ${toPath}`,
|
|
900
878
|
'rename',
|
|
901
879
|
err.code
|
|
@@ -903,9 +881,11 @@ class SftpClient {
|
|
|
903
881
|
);
|
|
904
882
|
}
|
|
905
883
|
resolve(`Successfully renamed ${fromPath} to ${toPath}`);
|
|
906
|
-
utils.removeTempListeners(this.client);
|
|
907
884
|
});
|
|
908
885
|
}
|
|
886
|
+
}).finally((rsp) => {
|
|
887
|
+
removeTempListeners(this.client);
|
|
888
|
+
return rsp;
|
|
909
889
|
});
|
|
910
890
|
}
|
|
911
891
|
|
|
@@ -923,14 +903,14 @@ class SftpClient {
|
|
|
923
903
|
*/
|
|
924
904
|
posixRename(fromPath, toPath) {
|
|
925
905
|
return new Promise((resolve, reject) => {
|
|
926
|
-
if (
|
|
906
|
+
if (haveConnection(this, 'posixRename', reject)) {
|
|
927
907
|
this.debugMsg(`posixRename -> ${fromPath} ${toPath}`);
|
|
928
|
-
|
|
908
|
+
addTempListeners(this, 'posixRename', reject);
|
|
929
909
|
this.sftp.ext_openssh_rename(fromPath, toPath, (err) => {
|
|
930
910
|
if (err) {
|
|
931
911
|
this.debugMsg(`posixRename error ${err.message} code: ${err.code}`);
|
|
932
912
|
reject(
|
|
933
|
-
|
|
913
|
+
fmtError(
|
|
934
914
|
`${err.message} From: ${fromPath} To: ${toPath}`,
|
|
935
915
|
'posixRename',
|
|
936
916
|
err.code
|
|
@@ -938,9 +918,11 @@ class SftpClient {
|
|
|
938
918
|
);
|
|
939
919
|
}
|
|
940
920
|
resolve(`Successful POSIX rename ${fromPath} to ${toPath}`);
|
|
941
|
-
utils.removeTempListeners(this.client);
|
|
942
921
|
});
|
|
943
922
|
}
|
|
923
|
+
}).finally((rsp) => {
|
|
924
|
+
removeTempListeners(this.client);
|
|
925
|
+
return rsp;
|
|
944
926
|
});
|
|
945
927
|
}
|
|
946
928
|
|
|
@@ -957,16 +939,16 @@ class SftpClient {
|
|
|
957
939
|
chmod(remotePath, mode) {
|
|
958
940
|
return new Promise((resolve, reject) => {
|
|
959
941
|
this.debugMsg(`chmod -> ${remotePath} ${mode}`);
|
|
960
|
-
|
|
942
|
+
addTempListeners(this, 'chmod', reject);
|
|
961
943
|
this.sftp.chmod(remotePath, mode, (err) => {
|
|
962
944
|
if (err) {
|
|
963
|
-
reject(
|
|
964
|
-
utils.formatError(`${err.message} ${remotePath}`, 'chmod', err.code)
|
|
965
|
-
);
|
|
945
|
+
reject(fmtError(`${err.message} ${remotePath}`, 'chmod', err.code));
|
|
966
946
|
}
|
|
967
947
|
resolve('Successfully change file mode');
|
|
968
|
-
utils.removeTempListeners(this.client);
|
|
969
948
|
});
|
|
949
|
+
}).finally((rsp) => {
|
|
950
|
+
removeTempListeners(this.client);
|
|
951
|
+
return rsp;
|
|
970
952
|
});
|
|
971
953
|
}
|
|
972
954
|
|
|
@@ -986,14 +968,10 @@ class SftpClient {
|
|
|
986
968
|
async uploadDir(srcDir, dstDir, filter = /.*/) {
|
|
987
969
|
try {
|
|
988
970
|
this.debugMsg(`uploadDir -> ${srcDir} ${dstDir}`);
|
|
989
|
-
|
|
971
|
+
haveConnection(this, 'uploadDir');
|
|
990
972
|
let dstStatus = await this.exists(dstDir);
|
|
991
973
|
if (dstStatus && dstStatus !== 'd') {
|
|
992
|
-
throw
|
|
993
|
-
`Bad path ${dstDir}`,
|
|
994
|
-
'uploadDir',
|
|
995
|
-
errorCode.badPath
|
|
996
|
-
);
|
|
974
|
+
throw fmtError(`Bad path ${dstDir}`, 'uploadDir', errorCode.badPath);
|
|
997
975
|
}
|
|
998
976
|
if (!dstStatus) {
|
|
999
977
|
await this.mkdir(dstDir, true);
|
|
@@ -1021,7 +999,11 @@ class SftpClient {
|
|
|
1021
999
|
}
|
|
1022
1000
|
return `${srcDir} uploaded to ${dstDir}`;
|
|
1023
1001
|
} catch (err) {
|
|
1024
|
-
|
|
1002
|
+
if (err.custom) {
|
|
1003
|
+
throw err;
|
|
1004
|
+
} else {
|
|
1005
|
+
throw fmtError(err, 'uploadDir');
|
|
1006
|
+
}
|
|
1025
1007
|
}
|
|
1026
1008
|
}
|
|
1027
1009
|
|
|
@@ -1041,15 +1023,11 @@ class SftpClient {
|
|
|
1041
1023
|
async downloadDir(srcDir, dstDir, filter = /.*/) {
|
|
1042
1024
|
try {
|
|
1043
1025
|
this.debugMsg(`downloadDir -> ${srcDir} ${dstDir}`);
|
|
1044
|
-
|
|
1026
|
+
haveConnection(this, 'downloadDir');
|
|
1045
1027
|
let fileList = await this.list(srcDir, filter);
|
|
1046
|
-
let dstStatus = await
|
|
1028
|
+
let dstStatus = await localExists(dstDir);
|
|
1047
1029
|
if (dstStatus && dstStatus !== 'd') {
|
|
1048
|
-
throw
|
|
1049
|
-
`Bad path ${dstDir}`,
|
|
1050
|
-
'downloadDir',
|
|
1051
|
-
errorCode.badPath
|
|
1052
|
-
);
|
|
1030
|
+
throw fmtError(`Bad path ${dstDir}`, 'downloadDir', errorCode.badPath);
|
|
1053
1031
|
}
|
|
1054
1032
|
if (!dstStatus) {
|
|
1055
1033
|
fs.mkdirSync(dstDir, {recursive: true});
|
|
@@ -1072,7 +1050,11 @@ class SftpClient {
|
|
|
1072
1050
|
}
|
|
1073
1051
|
return `${srcDir} downloaded to ${dstDir}`;
|
|
1074
1052
|
} catch (err) {
|
|
1075
|
-
|
|
1053
|
+
if (err.custom) {
|
|
1054
|
+
throw err;
|
|
1055
|
+
} else {
|
|
1056
|
+
throw fmtError(err, 'downloadDir', err.code);
|
|
1057
|
+
}
|
|
1076
1058
|
}
|
|
1077
1059
|
}
|
|
1078
1060
|
|
|
@@ -1083,42 +1065,23 @@ class SftpClient {
|
|
|
1083
1065
|
*
|
|
1084
1066
|
*/
|
|
1085
1067
|
end() {
|
|
1068
|
+
let endCloseHandler;
|
|
1086
1069
|
return new Promise((resolve, reject) => {
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
this.debugMsg(
|
|
1091
|
-
`endErrorListener called with ${err.message} and code ${err.code}`
|
|
1092
|
-
);
|
|
1093
|
-
this.errorHandled = true;
|
|
1094
|
-
if (err.code !== 'ECONNRESET') {
|
|
1095
|
-
reject(utils.formatError(err, 'end'));
|
|
1096
|
-
} else {
|
|
1097
|
-
this.debugMsg('Error is ECONNRESET - ignoring error');
|
|
1098
|
-
}
|
|
1099
|
-
};
|
|
1100
|
-
|
|
1101
|
-
try {
|
|
1102
|
-
if (!utils.hasListener(this.client, 'error', 'endErrorListener')) {
|
|
1103
|
-
this.debugMsg('Adding enderrorListener');
|
|
1104
|
-
this.client.prependListener('error', endErrorListener);
|
|
1105
|
-
} else {
|
|
1106
|
-
this.debugMsg('endErrorListener already set');
|
|
1107
|
-
}
|
|
1108
|
-
this.endCalled = true;
|
|
1109
|
-
if (utils.haveConnection(this, 'end', reject)) {
|
|
1110
|
-
this.debugMsg('Have connection - calling end()');
|
|
1111
|
-
this.client.end();
|
|
1112
|
-
} else {
|
|
1113
|
-
this.debugMsg('No connection - skipping call to end()');
|
|
1114
|
-
}
|
|
1115
|
-
resolve(true);
|
|
1116
|
-
} catch (err) {
|
|
1117
|
-
utils.handleError(err, 'end', reject);
|
|
1118
|
-
} finally {
|
|
1070
|
+
this.endCalled = true;
|
|
1071
|
+
addTempListeners(this, 'end', reject);
|
|
1072
|
+
endCloseHandler = () => {
|
|
1119
1073
|
this.sftp = undefined;
|
|
1120
|
-
|
|
1074
|
+
resolve(true);
|
|
1075
|
+
};
|
|
1076
|
+
this.on('close', endCloseHandler);
|
|
1077
|
+
if (haveConnection(this, 'end', reject)) {
|
|
1078
|
+
this.debugMsg('Have connection - calling end()');
|
|
1079
|
+
this.client.end();
|
|
1121
1080
|
}
|
|
1081
|
+
}).finally(() => {
|
|
1082
|
+
removeTempListeners(this.client);
|
|
1083
|
+
this.removeListener('close', endCloseHandler);
|
|
1084
|
+
return true;
|
|
1122
1085
|
});
|
|
1123
1086
|
}
|
|
1124
1087
|
}
|
package/src/utils.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const {prependListener} = require('cluster');
|
|
4
3
|
const fs = require('fs');
|
|
5
4
|
const {errorCode} = require('./constants');
|
|
6
5
|
|
|
@@ -13,7 +12,7 @@ const {errorCode} = require('./constants');
|
|
|
13
12
|
* attempts to complete before giving up
|
|
14
13
|
* @returns {Error} New error with custom error message
|
|
15
14
|
*/
|
|
16
|
-
function
|
|
15
|
+
function fmtError(err, name = 'sftp', eCode, retryCount) {
|
|
17
16
|
let msg = '';
|
|
18
17
|
let code = '';
|
|
19
18
|
let retry = retryCount
|
|
@@ -46,9 +45,6 @@ function formatError(err, name = 'sftp', eCode, retryCount) {
|
|
|
46
45
|
`${name}: Remote host has reset the connection: ` +
|
|
47
46
|
`${err.message}${retry}`;
|
|
48
47
|
break;
|
|
49
|
-
case 'ENOENT':
|
|
50
|
-
msg = `${name}: ${err.message}${retry}`;
|
|
51
|
-
break;
|
|
52
48
|
default:
|
|
53
49
|
msg = `${name}: ${err.message}${retry}`;
|
|
54
50
|
}
|
|
@@ -60,44 +56,6 @@ function formatError(err, name = 'sftp', eCode, retryCount) {
|
|
|
60
56
|
return newError;
|
|
61
57
|
}
|
|
62
58
|
|
|
63
|
-
/**
|
|
64
|
-
* Tests an error to see if it is one which has already been customised
|
|
65
|
-
* by this module or not. If not, applies appropriate customisation.
|
|
66
|
-
*
|
|
67
|
-
* @param {Error} err - an Error object
|
|
68
|
-
* @param {String} name - name to be used in customised error message
|
|
69
|
-
* @param {Function} reject - If defined, call this function instead of
|
|
70
|
-
* throwing the error
|
|
71
|
-
* @throws {Error}
|
|
72
|
-
*/
|
|
73
|
-
function handleError(err, name, reject) {
|
|
74
|
-
if (reject) {
|
|
75
|
-
if (err.custom) {
|
|
76
|
-
reject(err);
|
|
77
|
-
} else {
|
|
78
|
-
reject(formatError(err, name));
|
|
79
|
-
}
|
|
80
|
-
} else {
|
|
81
|
-
if (err.custom) {
|
|
82
|
-
throw err;
|
|
83
|
-
} else {
|
|
84
|
-
throw formatError(err, name, err.code);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Remove all ready, error and end listeners.
|
|
91
|
-
*
|
|
92
|
-
* @param {Emitter} emitter - The emitter object to remove listeners from
|
|
93
|
-
*/
|
|
94
|
-
function removeListeners(emitter) {
|
|
95
|
-
let listeners = emitter.eventNames();
|
|
96
|
-
listeners.forEach((name) => {
|
|
97
|
-
emitter.removeAllListeners(name);
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
|
|
101
59
|
let tempListeners = [];
|
|
102
60
|
|
|
103
61
|
/**
|
|
@@ -108,13 +66,13 @@ let tempListeners = [];
|
|
|
108
66
|
* @throws {Error} Throws new error
|
|
109
67
|
*/
|
|
110
68
|
function errorListener(client, name, reject) {
|
|
111
|
-
let fn =
|
|
69
|
+
let fn = (err) => {
|
|
112
70
|
if (!client.errorHandled) {
|
|
113
71
|
client.errorHandled = true;
|
|
114
72
|
if (reject) {
|
|
115
|
-
reject(
|
|
73
|
+
reject(fmtError(err, name, err.code));
|
|
116
74
|
} else {
|
|
117
|
-
throw
|
|
75
|
+
throw fmtError(err, name, err.code);
|
|
118
76
|
}
|
|
119
77
|
}
|
|
120
78
|
client.debugMsg(`Handled Error: ${err.message} ${err.code}`);
|
|
@@ -125,15 +83,15 @@ function errorListener(client, name, reject) {
|
|
|
125
83
|
|
|
126
84
|
function endListener(client, name, reject) {
|
|
127
85
|
let fn = function () {
|
|
86
|
+
client.debugMsg(`Handled end event for ${name}`);
|
|
128
87
|
if (!client.endCalled) {
|
|
88
|
+
client.sftp = undefined;
|
|
129
89
|
if (reject) {
|
|
130
|
-
reject(
|
|
90
|
+
reject(fmtError('Unexpected end event raised', name));
|
|
131
91
|
} else {
|
|
132
|
-
throw
|
|
92
|
+
throw fmtError('Unexpected end event raised', name);
|
|
133
93
|
}
|
|
134
94
|
}
|
|
135
|
-
client.debugMsg(`Handled end event for ${name}`);
|
|
136
|
-
client.sftp = undefined;
|
|
137
95
|
};
|
|
138
96
|
tempListeners.push(['end', fn]);
|
|
139
97
|
return fn;
|
|
@@ -141,15 +99,15 @@ function endListener(client, name, reject) {
|
|
|
141
99
|
|
|
142
100
|
function closeListener(client, name, reject) {
|
|
143
101
|
let fn = function () {
|
|
102
|
+
client.debugMsg(`handled close event for ${name}`);
|
|
144
103
|
if (!client.endCalled) {
|
|
104
|
+
client.sftp = undefined;
|
|
145
105
|
if (reject) {
|
|
146
|
-
reject(
|
|
106
|
+
reject(fmtError('Unexpected close event raised', name));
|
|
147
107
|
} else {
|
|
148
|
-
throw
|
|
108
|
+
throw fmtError('Unexpected close event raised', name);
|
|
149
109
|
}
|
|
150
110
|
}
|
|
151
|
-
client.debugMsg(`handled close event for ${name}`);
|
|
152
|
-
client.sftp = undefined;
|
|
153
111
|
};
|
|
154
112
|
tempListeners.push(['close', fn]);
|
|
155
113
|
return fn;
|
|
@@ -213,7 +171,7 @@ async function normalizeRemotePath(client, aPath) {
|
|
|
213
171
|
}
|
|
214
172
|
return aPath;
|
|
215
173
|
} catch (err) {
|
|
216
|
-
throw
|
|
174
|
+
throw fmtError(err, 'normalizeRemotePath');
|
|
217
175
|
}
|
|
218
176
|
}
|
|
219
177
|
|
|
@@ -229,7 +187,7 @@ async function normalizeRemotePath(client, aPath) {
|
|
|
229
187
|
*/
|
|
230
188
|
function haveConnection(client, name, reject) {
|
|
231
189
|
if (!client.sftp) {
|
|
232
|
-
let newError =
|
|
190
|
+
let newError = fmtError(
|
|
233
191
|
'No SFTP connection available',
|
|
234
192
|
name,
|
|
235
193
|
errorCode.connect
|
|
@@ -244,31 +202,8 @@ function haveConnection(client, name, reject) {
|
|
|
244
202
|
return true;
|
|
245
203
|
}
|
|
246
204
|
|
|
247
|
-
function dumpListeners(emitter) {
|
|
248
|
-
let eventNames = emitter.eventNames();
|
|
249
|
-
if (eventNames.length) {
|
|
250
|
-
console.log('Listener Data');
|
|
251
|
-
eventNames.map((n) => {
|
|
252
|
-
let listeners = emitter.listeners(n);
|
|
253
|
-
console.log(`${n}: ${emitter.listenerCount(n)}`);
|
|
254
|
-
console.dir(listeners);
|
|
255
|
-
listeners.map((l) => {
|
|
256
|
-
console.log(`listener name = ${l.name}`);
|
|
257
|
-
});
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
function hasListener(emitter, eventName, listenerName) {
|
|
263
|
-
let listeners = emitter.listeners(eventName);
|
|
264
|
-
let matches = listeners.filter((l) => l.name == listenerName);
|
|
265
|
-
return matches.length === 0 ? false : true;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
205
|
module.exports = {
|
|
269
|
-
|
|
270
|
-
handleError,
|
|
271
|
-
removeListeners,
|
|
206
|
+
fmtError,
|
|
272
207
|
errorListener,
|
|
273
208
|
endListener,
|
|
274
209
|
closeListener,
|
|
@@ -276,7 +211,5 @@ module.exports = {
|
|
|
276
211
|
removeTempListeners,
|
|
277
212
|
localExists,
|
|
278
213
|
normalizeRemotePath,
|
|
279
|
-
haveConnection
|
|
280
|
-
dumpListeners,
|
|
281
|
-
hasListener
|
|
214
|
+
haveConnection
|
|
282
215
|
};
|