ssh2-sftp-client 8.1.0 → 9.0.2
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 +198 -131
- package/README.org +162 -56
- package/package.json +4 -4
- package/src/constants.js +1 -0
- package/src/index.js +825 -692
- package/src/utils.js +65 -115
package/src/utils.js
CHANGED
|
@@ -1,63 +1,7 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
1
|
const fs = require('fs');
|
|
4
2
|
const path = require('path');
|
|
5
|
-
|
|
6
3
|
const { errorCode } = require('./constants');
|
|
7
4
|
|
|
8
|
-
/**
|
|
9
|
-
* Generate a new Error object with a reformatted error message which
|
|
10
|
-
* is a little more informative and useful to users.
|
|
11
|
-
*
|
|
12
|
-
* @param {Error|string} err - The Error object the new error will be based on
|
|
13
|
-
* @param {number} retryCount - For those functions which use retry. Number of
|
|
14
|
-
* attempts to complete before giving up
|
|
15
|
-
* @returns {Error} New error with custom error message
|
|
16
|
-
*/
|
|
17
|
-
function fmtError(err, name = 'sftp', eCode, retryCount) {
|
|
18
|
-
let msg = '';
|
|
19
|
-
let code = '';
|
|
20
|
-
let retry = retryCount
|
|
21
|
-
? ` after ${retryCount} ${retryCount > 1 ? 'attempts' : 'attempt'}`
|
|
22
|
-
: '';
|
|
23
|
-
|
|
24
|
-
if (err === undefined) {
|
|
25
|
-
msg = `${name}: Undefined error - probably a bug!`;
|
|
26
|
-
code = errorCode.generic;
|
|
27
|
-
} else if (typeof err === 'string') {
|
|
28
|
-
msg = `${name}: ${err}${retry}`;
|
|
29
|
-
code = eCode ? eCode : errorCode.generic;
|
|
30
|
-
} else if (err.custom) {
|
|
31
|
-
msg = `${name}->${err.message}${retry}`;
|
|
32
|
-
code = err.code;
|
|
33
|
-
} else {
|
|
34
|
-
switch (err.code) {
|
|
35
|
-
case 'ENOTFOUND':
|
|
36
|
-
msg =
|
|
37
|
-
`${name}: ${err.level} error. ` +
|
|
38
|
-
`Address lookup failed for host ${err.hostname}${retry}`;
|
|
39
|
-
break;
|
|
40
|
-
case 'ECONNREFUSED':
|
|
41
|
-
msg =
|
|
42
|
-
`${name}: ${err.level} error. Remote host at ` +
|
|
43
|
-
`${err.address} refused connection${retry}`;
|
|
44
|
-
break;
|
|
45
|
-
case 'ECONNRESET':
|
|
46
|
-
msg =
|
|
47
|
-
`${name}: Remote host has reset the connection: ` +
|
|
48
|
-
`${err.message}${retry}`;
|
|
49
|
-
break;
|
|
50
|
-
default:
|
|
51
|
-
msg = `${name}: ${err.message}${retry}`;
|
|
52
|
-
}
|
|
53
|
-
code = err.code ? err.code : errorCode.generic;
|
|
54
|
-
}
|
|
55
|
-
let newError = new Error(msg);
|
|
56
|
-
newError.code = code;
|
|
57
|
-
newError.custom = true;
|
|
58
|
-
return newError;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
5
|
/**
|
|
62
6
|
* Simple default error listener. Will reformat the error message and
|
|
63
7
|
* throw a new error.
|
|
@@ -66,82 +10,94 @@ function fmtError(err, name = 'sftp', eCode, retryCount) {
|
|
|
66
10
|
* @throws {Error} Throws new error
|
|
67
11
|
*/
|
|
68
12
|
function errorListener(client, name, reject) {
|
|
69
|
-
|
|
13
|
+
const fn = (err) => {
|
|
70
14
|
if (client.endCalled || client.errorHandled) {
|
|
71
|
-
|
|
15
|
+
// error already handled or expected - ignore
|
|
16
|
+
client.debugMsg(`${name} errorListener - ignoring handled error`);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
client.errorHandled = true;
|
|
20
|
+
const newError = new Error(`${name}: ${err.message}`);
|
|
21
|
+
newError.code = err.code;
|
|
22
|
+
if (reject) {
|
|
23
|
+
reject(newError);
|
|
72
24
|
} else {
|
|
73
|
-
|
|
74
|
-
client.errorHandled = true;
|
|
75
|
-
if (reject) {
|
|
76
|
-
client.debugMsg(`${name} Error: handled error with reject`);
|
|
77
|
-
reject(fmtError(err, name, err.code));
|
|
78
|
-
} else {
|
|
79
|
-
client.debugMsg(`${name} Error: handling error with throw`);
|
|
80
|
-
throw fmtError(err, name, err.code);
|
|
81
|
-
}
|
|
25
|
+
throw newError;
|
|
82
26
|
}
|
|
83
27
|
};
|
|
84
28
|
return fn;
|
|
85
29
|
}
|
|
86
30
|
|
|
87
31
|
function endListener(client, name, reject) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
client.debugMsg(`${name}
|
|
93
|
-
|
|
94
|
-
client.endHandled = true;
|
|
95
|
-
if (reject) {
|
|
96
|
-
client.debugMsg(`${name} End: handling end event with reject'`);
|
|
97
|
-
reject(fmtError('Unexpected end event raised', name));
|
|
98
|
-
} else {
|
|
99
|
-
client.debugMsg(`${name} End: handling end event with throw`);
|
|
100
|
-
throw fmtError('Unexpected end event raised', name);
|
|
101
|
-
}
|
|
32
|
+
const fn = function () {
|
|
33
|
+
client.sftp = undefined;
|
|
34
|
+
if (client.endCalled || client.endHandled || client.errorHandled) {
|
|
35
|
+
// end event already handled - ignore
|
|
36
|
+
client.debugMsg(`${name} endListener - ignoring handled error`);
|
|
37
|
+
return;
|
|
102
38
|
}
|
|
39
|
+
client.endHandled = true;
|
|
40
|
+
client.debugMsg(`${name} Unexpected end event - ignoring`);
|
|
41
|
+
// Don't reject/throw error, just log it and move on
|
|
42
|
+
// after invalidating the connection
|
|
43
|
+
// const err = new Error(`${name} Unexpected end event raised`);
|
|
44
|
+
// if (reject) {
|
|
45
|
+
// reject(err);
|
|
46
|
+
// } else {
|
|
47
|
+
// throw err;
|
|
48
|
+
// }
|
|
103
49
|
};
|
|
104
50
|
return fn;
|
|
105
51
|
}
|
|
106
52
|
|
|
107
53
|
function closeListener(client, name, reject) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
client.
|
|
113
|
-
client.
|
|
114
|
-
client.
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
client.debugMsg(`${name} Close: handling close event with throw`);
|
|
120
|
-
throw fmtError('Unexpected close event raised', name);
|
|
121
|
-
}
|
|
54
|
+
const fn = function () {
|
|
55
|
+
client.sftp = undefined;
|
|
56
|
+
if (
|
|
57
|
+
client.endCalled ||
|
|
58
|
+
client.closeHandled ||
|
|
59
|
+
client.errorHandled ||
|
|
60
|
+
client.endHandled
|
|
61
|
+
) {
|
|
62
|
+
// handled or expected close event - ignore
|
|
63
|
+
client.debugMsg(`${name} closeListener - ignoring handled error`);
|
|
64
|
+
return;
|
|
122
65
|
}
|
|
66
|
+
client.closeHandled = true;
|
|
67
|
+
client.debugMsg(`${name} Unexpected close event raised - ignoring`);
|
|
68
|
+
// Don't throw/reject on close events. Just invalidate the connection
|
|
69
|
+
// and move on.
|
|
70
|
+
// const err = new Error(`${name}: Unexpected close event raised`);
|
|
71
|
+
// if (reject) {
|
|
72
|
+
// reject(err);
|
|
73
|
+
// } else {
|
|
74
|
+
// throw err;
|
|
75
|
+
// }
|
|
123
76
|
};
|
|
124
77
|
return fn;
|
|
125
78
|
}
|
|
126
79
|
|
|
127
80
|
function addTempListeners(client, name, reject) {
|
|
128
|
-
|
|
81
|
+
const listeners = {
|
|
129
82
|
end: endListener(client, name, reject),
|
|
130
83
|
close: closeListener(client, name, reject),
|
|
131
84
|
error: errorListener(client, name, reject),
|
|
132
85
|
};
|
|
133
|
-
client.debugMsg(`${name}: Adding temp event listeners`);
|
|
134
86
|
client.on('end', listeners.end);
|
|
135
87
|
client.on('close', listeners.close);
|
|
136
88
|
client.on('error', listeners.error);
|
|
89
|
+
client._resetEventFlags();
|
|
137
90
|
return listeners;
|
|
138
91
|
}
|
|
139
92
|
|
|
140
93
|
function removeTempListeners(client, listeners, name) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
94
|
+
try {
|
|
95
|
+
client.removeListener('end', listeners.end);
|
|
96
|
+
client.removeListener('close', listeners.close);
|
|
97
|
+
client.removeListener('error', listeners.error);
|
|
98
|
+
} catch (err) {
|
|
99
|
+
throw new Error(`${name}: Error removing temp listeners: ${err.message}`);
|
|
100
|
+
}
|
|
145
101
|
}
|
|
146
102
|
|
|
147
103
|
/**
|
|
@@ -165,11 +121,9 @@ function localExists(filePath) {
|
|
|
165
121
|
} else if (stats.isFile()) {
|
|
166
122
|
return '-';
|
|
167
123
|
} else {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
errorCode.badPath
|
|
172
|
-
);
|
|
124
|
+
const err = new Error(`Bad path: ${filePath}: target must be a file or directory`);
|
|
125
|
+
err.code = errorCode.badPath;
|
|
126
|
+
throw err;
|
|
173
127
|
}
|
|
174
128
|
}
|
|
175
129
|
|
|
@@ -284,15 +238,15 @@ function haveLocalCreate(filePath) {
|
|
|
284
238
|
async function normalizeRemotePath(client, aPath) {
|
|
285
239
|
try {
|
|
286
240
|
if (aPath.startsWith('..')) {
|
|
287
|
-
|
|
241
|
+
const root = await client.realPath('..');
|
|
288
242
|
return root + client.remotePathSep + aPath.slice(3);
|
|
289
243
|
} else if (aPath.startsWith('.')) {
|
|
290
|
-
|
|
244
|
+
const root = await client.realPath('.');
|
|
291
245
|
return root + client.remotePathSep + aPath.slice(2);
|
|
292
246
|
}
|
|
293
247
|
return aPath;
|
|
294
248
|
} catch (err) {
|
|
295
|
-
throw
|
|
249
|
+
throw new Error(`normalizeRemotePath: ${err.message}`);
|
|
296
250
|
}
|
|
297
251
|
}
|
|
298
252
|
|
|
@@ -308,11 +262,8 @@ async function normalizeRemotePath(client, aPath) {
|
|
|
308
262
|
*/
|
|
309
263
|
function haveConnection(client, name, reject) {
|
|
310
264
|
if (!client.sftp) {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
name,
|
|
314
|
-
errorCode.connect
|
|
315
|
-
);
|
|
265
|
+
const newError = new Error(`${name}: No SFTP connection available`);
|
|
266
|
+
newError.code = errorCode.connect;
|
|
316
267
|
if (reject) {
|
|
317
268
|
reject(newError);
|
|
318
269
|
return false;
|
|
@@ -336,7 +287,6 @@ function sleep(ms) {
|
|
|
336
287
|
}
|
|
337
288
|
|
|
338
289
|
module.exports = {
|
|
339
|
-
fmtError,
|
|
340
290
|
errorListener,
|
|
341
291
|
endListener,
|
|
342
292
|
closeListener,
|