ssh2-scp 1.0.1 → 1.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/dist/cjs/package.json +3 -0
- package/dist/cjs/ssh-fs.cjs +324 -0
- package/dist/cjs/transfer.cjs +151 -0
- package/package.json +11 -11
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
class SshFs {
|
|
4
|
+
session;
|
|
5
|
+
constructor(session, _options) {
|
|
6
|
+
this.session = session;
|
|
7
|
+
}
|
|
8
|
+
getExecOpts() {
|
|
9
|
+
return {};
|
|
10
|
+
}
|
|
11
|
+
getMonthIndex(month) {
|
|
12
|
+
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
13
|
+
return months.indexOf(month);
|
|
14
|
+
}
|
|
15
|
+
runCmd(cmd, timeout = 3e4) {
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
let timeoutId;
|
|
18
|
+
const cleanup = () => {
|
|
19
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
20
|
+
};
|
|
21
|
+
timeoutId = setTimeout(() => {
|
|
22
|
+
cleanup();
|
|
23
|
+
reject(new Error(`Command timed out: ${cmd}`));
|
|
24
|
+
}, timeout);
|
|
25
|
+
this.session.exec(cmd, (err, stream) => {
|
|
26
|
+
cleanup();
|
|
27
|
+
if (err) {
|
|
28
|
+
reject(err);
|
|
29
|
+
} else {
|
|
30
|
+
let out = Buffer.from("");
|
|
31
|
+
stream.on("end", () => {
|
|
32
|
+
resolve(out.toString());
|
|
33
|
+
}).on("data", (data) => {
|
|
34
|
+
out = Buffer.concat([out, data]);
|
|
35
|
+
}).stderr.on("data", (data) => {
|
|
36
|
+
reject(data.toString());
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
rmFolderCmd(remotePath) {
|
|
43
|
+
return this.runCmd(`rmdir "${remotePath}"`);
|
|
44
|
+
}
|
|
45
|
+
rmCmd(remotePath) {
|
|
46
|
+
return this.runCmd(`rm "${remotePath}"`);
|
|
47
|
+
}
|
|
48
|
+
async getHomeDir() {
|
|
49
|
+
return this.realpath(".");
|
|
50
|
+
}
|
|
51
|
+
async rmdir(remotePath) {
|
|
52
|
+
try {
|
|
53
|
+
return await this.rmrf(remotePath);
|
|
54
|
+
} catch (err) {
|
|
55
|
+
console.error("rm -rf dir error", err);
|
|
56
|
+
return this.removeDirectoryRecursively(remotePath);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async removeDirectoryRecursively(remotePath) {
|
|
60
|
+
try {
|
|
61
|
+
const contents = await this.listFiles(remotePath);
|
|
62
|
+
for (const item of contents) {
|
|
63
|
+
if (item.name === "." || item.name === "..") continue;
|
|
64
|
+
const itemPath = `${remotePath}/${item.name}`;
|
|
65
|
+
if (item.type === "d") {
|
|
66
|
+
await this.removeDirectoryRecursively(itemPath);
|
|
67
|
+
} else {
|
|
68
|
+
await this.rmCmd(itemPath);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
await this.rmFolderCmd(remotePath);
|
|
72
|
+
} catch (e) {
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
rmrf(remotePath) {
|
|
76
|
+
return this.runCmd(`rm -rf "${remotePath}"`);
|
|
77
|
+
}
|
|
78
|
+
touch(remotePath) {
|
|
79
|
+
return this.runCmd(`touch "${remotePath}"`);
|
|
80
|
+
}
|
|
81
|
+
cp(from, to) {
|
|
82
|
+
return new Promise((resolve, reject) => {
|
|
83
|
+
const cmd = `cp -r "${from}" "${to}"`;
|
|
84
|
+
this.session.exec(cmd, this.getExecOpts(), (err) => {
|
|
85
|
+
if (err) reject(err);
|
|
86
|
+
else resolve(1);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
mv(from, to) {
|
|
91
|
+
return new Promise((resolve, reject) => {
|
|
92
|
+
const cmd = `mv "${from}" "${to}"`;
|
|
93
|
+
this.session.exec(cmd, this.getExecOpts(), (err) => {
|
|
94
|
+
if (err) reject(err);
|
|
95
|
+
else resolve(1);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
runExec(cmd) {
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
this.session.exec(cmd, this.getExecOpts(), (err, stream) => {
|
|
102
|
+
if (err) {
|
|
103
|
+
reject(err);
|
|
104
|
+
} else {
|
|
105
|
+
let out = Buffer.from("");
|
|
106
|
+
stream.on("end", () => {
|
|
107
|
+
resolve(out.toString());
|
|
108
|
+
}).on("data", (data) => {
|
|
109
|
+
out = Buffer.concat([out, data]);
|
|
110
|
+
}).stderr.on("data", (data) => {
|
|
111
|
+
reject(data.toString());
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
async getFolderSize(folderPath) {
|
|
118
|
+
const output = await this.runExec(`du -sh "${folderPath}" && find "${folderPath}" -type f | wc -l`);
|
|
119
|
+
const lines = output.trim().split("\n");
|
|
120
|
+
const size = lines[0]?.split(" ")[0] || "0";
|
|
121
|
+
const count = parseInt(lines[1] || "0", 10);
|
|
122
|
+
return { size, count };
|
|
123
|
+
}
|
|
124
|
+
async listFiles(remotePath) {
|
|
125
|
+
const output = await this.runCmd(`ls -la "${remotePath}"`);
|
|
126
|
+
const lines = output.trim().split("\n");
|
|
127
|
+
const result = [];
|
|
128
|
+
for (let i = 0; i < lines.length; i++) {
|
|
129
|
+
const line = lines[i].trim();
|
|
130
|
+
if (!line || i === 0) continue;
|
|
131
|
+
const parts = line.split(/\s+/);
|
|
132
|
+
if (parts.length < 9) continue;
|
|
133
|
+
const name = parts.slice(8).join(" ");
|
|
134
|
+
if (name === "." || name === "..") continue;
|
|
135
|
+
const type = parts[0].charAt(0);
|
|
136
|
+
const mode = parseInt(parts[0].slice(1), 8);
|
|
137
|
+
const owner = parseInt(parts[2], 10);
|
|
138
|
+
const group = parseInt(parts[3], 10);
|
|
139
|
+
const size = parseInt(parts[4], 10);
|
|
140
|
+
const month = parts[5];
|
|
141
|
+
const day = parts[6];
|
|
142
|
+
const timeOrYear = parts[7];
|
|
143
|
+
let mtime = 0;
|
|
144
|
+
const now = /* @__PURE__ */ new Date();
|
|
145
|
+
const year = now.getFullYear();
|
|
146
|
+
if (timeOrYear.includes(":")) {
|
|
147
|
+
const [hour, minute] = timeOrYear.split(":").map(Number);
|
|
148
|
+
mtime = new Date(year, this.getMonthIndex(month), parseInt(day, 10), hour, minute).getTime();
|
|
149
|
+
} else {
|
|
150
|
+
mtime = new Date(parseInt(timeOrYear, 10), this.getMonthIndex(month), parseInt(day, 10)).getTime();
|
|
151
|
+
}
|
|
152
|
+
result.push({
|
|
153
|
+
type,
|
|
154
|
+
name,
|
|
155
|
+
size,
|
|
156
|
+
modifyTime: mtime,
|
|
157
|
+
accessTime: mtime,
|
|
158
|
+
mode,
|
|
159
|
+
rights: {
|
|
160
|
+
user: parts[0].substring(1, 4),
|
|
161
|
+
group: parts[0].substring(4, 7),
|
|
162
|
+
other: parts[0].substring(7, 10)
|
|
163
|
+
},
|
|
164
|
+
owner,
|
|
165
|
+
group
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
170
|
+
list(remotePath) {
|
|
171
|
+
return this.listFiles(remotePath);
|
|
172
|
+
}
|
|
173
|
+
async mkdir(remotePath, options = {}) {
|
|
174
|
+
const cmd = options.mode ? `mkdir -m ${options.mode.toString(8)} -p "${remotePath}"` : `mkdir -p "${remotePath}"`;
|
|
175
|
+
return this.runCmd(cmd);
|
|
176
|
+
}
|
|
177
|
+
async stat(remotePath) {
|
|
178
|
+
const isSymlink = await this.runCmd(`test -L "${remotePath}" && echo 1 || echo 0`).then((r) => r.trim() === "1");
|
|
179
|
+
const output = await this.runCmd(`stat -c '%s %h %u %g %Y %Y %a' "${remotePath}"`);
|
|
180
|
+
const parts = output.trim().split(/\s+/);
|
|
181
|
+
if (parts.length < 7) {
|
|
182
|
+
return {
|
|
183
|
+
size: 0,
|
|
184
|
+
mode: 0,
|
|
185
|
+
uid: 0,
|
|
186
|
+
gid: 0,
|
|
187
|
+
atime: 0,
|
|
188
|
+
mtime: 0,
|
|
189
|
+
isFile: () => false,
|
|
190
|
+
isDirectory: () => false,
|
|
191
|
+
isSymbolicLink: () => false,
|
|
192
|
+
isBlockDevice: () => false,
|
|
193
|
+
isCharacterDevice: () => false,
|
|
194
|
+
isFIFO: () => false,
|
|
195
|
+
isSocket: () => false
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
const [size, _nlink, uid, gid, atime, mtime, modeOct] = parts;
|
|
199
|
+
const mode = parseInt(modeOct, 8);
|
|
200
|
+
return {
|
|
201
|
+
size: parseInt(size, 10),
|
|
202
|
+
mode,
|
|
203
|
+
uid: parseInt(uid, 10),
|
|
204
|
+
gid: parseInt(gid, 10),
|
|
205
|
+
atime: parseInt(atime, 10) * 1e3,
|
|
206
|
+
mtime: parseInt(mtime, 10) * 1e3,
|
|
207
|
+
isFile: () => (mode & 61440) === 32768,
|
|
208
|
+
isDirectory: () => (mode & 61440) === 16384,
|
|
209
|
+
isSymbolicLink: () => isSymlink,
|
|
210
|
+
isBlockDevice: () => (mode & 61440) === 24576,
|
|
211
|
+
isCharacterDevice: () => (mode & 61440) === 8192,
|
|
212
|
+
isFIFO: () => (mode & 61440) === 4096,
|
|
213
|
+
isSocket: () => (mode & 61440) === 49152
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
readlink(remotePath) {
|
|
217
|
+
return this.runCmd(`readlink "${remotePath}"`).then((output) => output.trim());
|
|
218
|
+
}
|
|
219
|
+
realpath(remotePath) {
|
|
220
|
+
return this.runCmd(`realpath "${remotePath}"`).then((output) => output.trim());
|
|
221
|
+
}
|
|
222
|
+
async lstat(remotePath) {
|
|
223
|
+
const output = await this.runCmd(`ls -ld "${remotePath}"`);
|
|
224
|
+
const isSymlink = output.trim().startsWith("l");
|
|
225
|
+
const statOutput = await this.runCmd(`stat -c '%s %h %u %g %Y %Y %a' "${remotePath}"`);
|
|
226
|
+
const parts = statOutput.trim().split(/\s+/);
|
|
227
|
+
if (parts.length < 7) {
|
|
228
|
+
return {
|
|
229
|
+
size: 0,
|
|
230
|
+
mode: 0,
|
|
231
|
+
uid: 0,
|
|
232
|
+
gid: 0,
|
|
233
|
+
atime: 0,
|
|
234
|
+
mtime: 0,
|
|
235
|
+
isFile: () => false,
|
|
236
|
+
isDirectory: () => false,
|
|
237
|
+
isSymbolicLink: () => false,
|
|
238
|
+
isBlockDevice: () => false,
|
|
239
|
+
isCharacterDevice: () => false,
|
|
240
|
+
isFIFO: () => false,
|
|
241
|
+
isSocket: () => false
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
const [size, _nlink, uid, gid, atime, mtime, modeOct] = parts;
|
|
245
|
+
const mode = parseInt(modeOct, 8);
|
|
246
|
+
return {
|
|
247
|
+
size: parseInt(size, 10),
|
|
248
|
+
mode,
|
|
249
|
+
uid: parseInt(uid, 10),
|
|
250
|
+
gid: parseInt(gid, 10),
|
|
251
|
+
atime: parseInt(atime, 10) * 1e3,
|
|
252
|
+
mtime: parseInt(mtime, 10) * 1e3,
|
|
253
|
+
isFile: () => !isSymlink && (mode & 61440) === 32768,
|
|
254
|
+
isDirectory: () => !isSymlink && (mode & 61440) === 16384,
|
|
255
|
+
isSymbolicLink: () => isSymlink,
|
|
256
|
+
isBlockDevice: () => (mode & 61440) === 24576,
|
|
257
|
+
isCharacterDevice: () => (mode & 61440) === 8192,
|
|
258
|
+
isFIFO: () => (mode & 61440) === 4096,
|
|
259
|
+
isSocket: () => (mode & 61440) === 49152
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
chmod(remotePath, mode) {
|
|
263
|
+
return this.runCmd(`chmod ${mode.toString(8)} "${remotePath}"`);
|
|
264
|
+
}
|
|
265
|
+
rename(remotePath, remotePathNew) {
|
|
266
|
+
return this.runCmd(`mv "${remotePath}" "${remotePathNew}"`);
|
|
267
|
+
}
|
|
268
|
+
rmFolder(remotePath) {
|
|
269
|
+
return this.rmFolderCmd(remotePath);
|
|
270
|
+
}
|
|
271
|
+
rm(remotePath) {
|
|
272
|
+
return this.rmCmd(remotePath);
|
|
273
|
+
}
|
|
274
|
+
async readFile(remotePath, options) {
|
|
275
|
+
const chunkSize = options?.chunkSize ?? 64 * 1024;
|
|
276
|
+
const fileSizeOutput = await this.runCmd(`stat -c %s "${remotePath}"`);
|
|
277
|
+
const fileSize = parseInt(fileSizeOutput.trim(), 10);
|
|
278
|
+
if (fileSize <= chunkSize) {
|
|
279
|
+
const output = await this.runCmd(`cat "${remotePath}"`);
|
|
280
|
+
return Buffer.from(output, "binary");
|
|
281
|
+
}
|
|
282
|
+
const chunks = [];
|
|
283
|
+
for (let offset = 0; offset < fileSize; offset += chunkSize) {
|
|
284
|
+
const cmd = `dd if="${remotePath}" bs=1K skip=${Math.floor(offset / 1024)} count=${Math.ceil(chunkSize / 1024)} 2>/dev/null`;
|
|
285
|
+
const chunkOutput = await this.runCmd(cmd);
|
|
286
|
+
if (chunkOutput) {
|
|
287
|
+
chunks.push(Buffer.from(chunkOutput, "binary"));
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return Buffer.concat(chunks);
|
|
291
|
+
}
|
|
292
|
+
async writeFile(remotePath, str, mode, _options) {
|
|
293
|
+
const data = typeof str === "string" ? Buffer.from(str) : str;
|
|
294
|
+
const sizeThreshold = 64 * 1024;
|
|
295
|
+
if (data.length <= sizeThreshold) {
|
|
296
|
+
const escapedContent = data.toString("binary").replace(/'/g, "'\\''");
|
|
297
|
+
const cmd = `printf '%s' '${escapedContent}' > "${remotePath}"`;
|
|
298
|
+
await this.runCmd(cmd);
|
|
299
|
+
} else {
|
|
300
|
+
const tempBase = `/tmp/ssh-fs-${Date.now()}`;
|
|
301
|
+
await this.runCmd(`mkdir -p "${tempBase}"`);
|
|
302
|
+
try {
|
|
303
|
+
const chunkSize = 64 * 1024;
|
|
304
|
+
for (let i = 0; i < data.length; i += chunkSize) {
|
|
305
|
+
const chunk = data.slice(i, i + chunkSize);
|
|
306
|
+
const chunkFile = `${tempBase}/c${Math.floor(i / chunkSize)}`;
|
|
307
|
+
const escapedChunk = chunk.toString("binary").replace(/'/g, "'\\''");
|
|
308
|
+
await this.runCmd(`printf '%s' '${escapedChunk}' > "${chunkFile}"`);
|
|
309
|
+
}
|
|
310
|
+
await this.runCmd(`cat ${tempBase}/c* > "${remotePath}"`);
|
|
311
|
+
} finally {
|
|
312
|
+
await this.runCmd(`rm -rf "${tempBase}"`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
if (mode) {
|
|
316
|
+
await this.runCmd(`chmod ${mode.toString(8)} "${remotePath}"`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
function createSshFs(session, options) {
|
|
321
|
+
return new SshFs(session, options);
|
|
322
|
+
}
|
|
323
|
+
exports.SshFs = SshFs;
|
|
324
|
+
exports.createSshFs = createSshFs;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
function _interopNamespaceDefault(e) {
|
|
6
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
7
|
+
if (e) {
|
|
8
|
+
for (const k in e) {
|
|
9
|
+
if (k !== "default") {
|
|
10
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
11
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: () => e[k]
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
n.default = e;
|
|
19
|
+
return Object.freeze(n);
|
|
20
|
+
}
|
|
21
|
+
const fs__namespace = /* @__PURE__ */ _interopNamespaceDefault(fs);
|
|
22
|
+
const path__namespace = /* @__PURE__ */ _interopNamespaceDefault(path);
|
|
23
|
+
class Transfer {
|
|
24
|
+
session;
|
|
25
|
+
options;
|
|
26
|
+
chunkSize;
|
|
27
|
+
state;
|
|
28
|
+
aborted = false;
|
|
29
|
+
constructor(sshFs, options) {
|
|
30
|
+
this.session = sshFs.session;
|
|
31
|
+
this.options = options;
|
|
32
|
+
this.chunkSize = options.chunkSize || 32768;
|
|
33
|
+
this.state = {
|
|
34
|
+
transferred: 0,
|
|
35
|
+
total: 0,
|
|
36
|
+
paused: false,
|
|
37
|
+
completed: false
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
async startTransfer() {
|
|
41
|
+
if (this.state.completed || this.state.error || this.aborted) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const isDownload = this.options.type === "download";
|
|
45
|
+
try {
|
|
46
|
+
if (isDownload) {
|
|
47
|
+
await this.download();
|
|
48
|
+
} else {
|
|
49
|
+
await this.upload();
|
|
50
|
+
}
|
|
51
|
+
this.state.completed = true;
|
|
52
|
+
} catch (err) {
|
|
53
|
+
this.state.error = err;
|
|
54
|
+
throw err;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async getRemoteFileSize(remotePath) {
|
|
58
|
+
const output = await this.runExec(`stat -c %s "${remotePath}" 2>/dev/null || stat -f %z "${remotePath}" 2>/dev/null`);
|
|
59
|
+
return parseInt(output.trim(), 10) || 0;
|
|
60
|
+
}
|
|
61
|
+
runExec(cmd, stdinData) {
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
this.session.exec(cmd, (err, stream) => {
|
|
64
|
+
if (err) {
|
|
65
|
+
return reject(err);
|
|
66
|
+
}
|
|
67
|
+
if (stdinData) {
|
|
68
|
+
stream.stdin.write(stdinData);
|
|
69
|
+
stream.stdin.end();
|
|
70
|
+
}
|
|
71
|
+
let out = Buffer.from("");
|
|
72
|
+
stream.on("close", () => {
|
|
73
|
+
resolve(out.toString());
|
|
74
|
+
}).on("data", (data) => {
|
|
75
|
+
out = Buffer.concat([out, data]);
|
|
76
|
+
}).stderr.on("data", (data) => {
|
|
77
|
+
console.error("stderr:", data.toString());
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
async download() {
|
|
83
|
+
const { remotePath, localPath, onProgress, onData } = this.options;
|
|
84
|
+
const dir = path__namespace.dirname(localPath);
|
|
85
|
+
if (!fs__namespace.existsSync(dir)) {
|
|
86
|
+
fs__namespace.mkdirSync(dir, { recursive: true });
|
|
87
|
+
}
|
|
88
|
+
this.state.total = await this.getRemoteFileSize(remotePath);
|
|
89
|
+
return new Promise((resolve, reject) => {
|
|
90
|
+
const cmd = `dd if="${remotePath}" bs=${this.chunkSize} 2>/dev/null`;
|
|
91
|
+
this.session.exec(cmd, (err, stream) => {
|
|
92
|
+
if (err) {
|
|
93
|
+
return reject(err);
|
|
94
|
+
}
|
|
95
|
+
const writeStream = fs__namespace.createWriteStream(localPath);
|
|
96
|
+
let localTransferred = 0;
|
|
97
|
+
stream.on("data", (data) => {
|
|
98
|
+
if (this.state.paused || this.aborted) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
writeStream.write(data);
|
|
102
|
+
localTransferred += data.length;
|
|
103
|
+
this.state.transferred = localTransferred;
|
|
104
|
+
if (onProgress) {
|
|
105
|
+
onProgress(localTransferred, this.state.total);
|
|
106
|
+
}
|
|
107
|
+
if (onData) {
|
|
108
|
+
onData(data.length);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
stream.on("close", () => {
|
|
112
|
+
writeStream.end(() => {
|
|
113
|
+
resolve();
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
stream.on("error", (err2) => {
|
|
117
|
+
this.state.error = err2;
|
|
118
|
+
writeStream.end();
|
|
119
|
+
reject(err2);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
async upload() {
|
|
125
|
+
const { remotePath, localPath, onProgress, onData } = this.options;
|
|
126
|
+
const fileContent = fs__namespace.readFileSync(localPath);
|
|
127
|
+
this.state.total = fileContent.length;
|
|
128
|
+
await this.runExec(`dd of="${remotePath}" bs=${this.chunkSize} 2>/dev/null`, fileContent);
|
|
129
|
+
this.state.transferred = this.state.total;
|
|
130
|
+
if (onProgress) {
|
|
131
|
+
onProgress(this.state.total, this.state.total);
|
|
132
|
+
}
|
|
133
|
+
if (onData) {
|
|
134
|
+
onData(fileContent.length);
|
|
135
|
+
}
|
|
136
|
+
this.state.completed = true;
|
|
137
|
+
}
|
|
138
|
+
pause() {
|
|
139
|
+
this.state.paused = true;
|
|
140
|
+
}
|
|
141
|
+
resume() {
|
|
142
|
+
this.state.paused = false;
|
|
143
|
+
}
|
|
144
|
+
getState() {
|
|
145
|
+
return { ...this.state };
|
|
146
|
+
}
|
|
147
|
+
destroy() {
|
|
148
|
+
this.aborted = true;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
exports.Transfer = Transfer;
|
package/package.json
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ssh2-scp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Remote file system operations over SSH2 session without SFTP",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "npm run build:esm && npm run build:cjs",
|
|
7
|
+
"build:esm": "vite build --config build/vite.config.ts --outDir dist/esm",
|
|
8
|
+
"build:cjs": "vite build --config build/vite.config.cjs.ts --outDir dist/cjs",
|
|
9
|
+
"test": "node test/ssh2-fs.test.mjs && node test/transfer.test.mjs",
|
|
10
|
+
"lint": "echo \"Lint not configured\" && exit 0",
|
|
11
|
+
"typecheck": "tsc --noEmit"
|
|
12
|
+
},
|
|
5
13
|
"homepage": "https://github.com/electerm/ssh2-scp#readme",
|
|
6
14
|
"bugs": {
|
|
7
15
|
"url": "https://github.com/electerm/ssh2-scp/issues"
|
|
@@ -19,12 +27,12 @@
|
|
|
19
27
|
"exports": {
|
|
20
28
|
".": {
|
|
21
29
|
"import": "./dist/esm/ssh-fs.js",
|
|
22
|
-
"require": "./dist/cjs/ssh-fs.
|
|
30
|
+
"require": "./dist/cjs/ssh-fs.cjs",
|
|
23
31
|
"types": "./dist/esm/ssh-fs.d.ts"
|
|
24
32
|
},
|
|
25
33
|
"./transfer": {
|
|
26
34
|
"import": "./dist/esm/transfer.js",
|
|
27
|
-
"require": "./dist/cjs/transfer.
|
|
35
|
+
"require": "./dist/cjs/transfer.cjs",
|
|
28
36
|
"types": "./dist/esm/transfer.d.ts"
|
|
29
37
|
}
|
|
30
38
|
},
|
|
@@ -34,14 +42,6 @@
|
|
|
34
42
|
"README-CN.md",
|
|
35
43
|
"LICENSE"
|
|
36
44
|
],
|
|
37
|
-
"scripts": {
|
|
38
|
-
"build": "vite build --config build/vite.config.ts",
|
|
39
|
-
"build:esm": "vite build --config build/vite.config.ts --outDir dist/esm",
|
|
40
|
-
"build:cjs": "vite build --config build/vite.config.cjs.ts --outDir dist/cjs",
|
|
41
|
-
"test": "node test/ssh2-fs.test.mjs && node test/transfer.test.mjs",
|
|
42
|
-
"lint": "echo \"Lint not configured\" && exit 0",
|
|
43
|
-
"typecheck": "tsc --noEmit"
|
|
44
|
-
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/node": "^20.10.0",
|
|
47
47
|
"@types/ssh2": "^1.11.0",
|