Skip to content

Commit aa57a98

Browse files
committed
fix(sftp): stabilize connections and storage cleanup
1 parent 341c027 commit aa57a98

7 files changed

Lines changed: 245 additions & 111 deletions

File tree

‎src/fileSystem/sftp.js‎

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import Path from "utils/Path";
66
import Url from "utils/Url";
77
import internalFs from "./internalFs";
88

9+
let pendingConnection = null;
10+
let pendingConnectionID = null;
11+
912
class SftpClient {
1013
#MAX_TRY = 3;
1114
#hostname;
@@ -19,7 +22,6 @@ class SftpClient {
1922
#connectionID;
2023
#path;
2124
#stat;
22-
#retry = 0;
2325

2426
/**
2527
*
@@ -48,7 +50,7 @@ class SftpClient {
4850
},
4951
});
5052

51-
this.#connectionID = `${this.#username}@${this.#hostname}`;
53+
this.#connectionID = `${this.#username}@${this.#hostname}:${this.#port}`;
5254
}
5355

5456
setPath(path) {
@@ -398,20 +400,50 @@ class SftpClient {
398400
}
399401

400402
async connect() {
401-
await new Promise((resolve, reject) => {
402-
const retry = (err) => {
403-
if (settings.value.retryRemoteFsAfterFail) {
404-
if (++this.#retry > this.#MAX_TRY) {
405-
this.#retry = 0;
406-
reject(err);
407-
} else {
408-
this.connect().then(resolve).catch(reject);
409-
}
410-
} else {
411-
reject(err);
412-
}
413-
};
403+
if (pendingConnection) {
404+
if (pendingConnectionID === this.#connectionID) {
405+
return pendingConnection;
406+
}
407+
try {
408+
await pendingConnection;
409+
} catch {
410+
// The next profile should still get its own connection attempt.
411+
}
412+
return this.connect();
413+
}
414+
415+
pendingConnectionID = this.#connectionID;
416+
pendingConnection = this.#connectWithRetry();
414417

418+
try {
419+
return await pendingConnection;
420+
} finally {
421+
if (pendingConnectionID === this.#connectionID) {
422+
pendingConnection = null;
423+
pendingConnectionID = null;
424+
}
425+
}
426+
}
427+
428+
async #connectWithRetry() {
429+
const attempts = settings.value.retryRemoteFsAfterFail
430+
? this.#MAX_TRY + 1
431+
: 1;
432+
let lastError;
433+
434+
for (let attempt = 0; attempt < attempts; attempt++) {
435+
try {
436+
return await this.#connectOnce();
437+
} catch (error) {
438+
lastError = error;
439+
}
440+
}
441+
442+
throw lastError;
443+
}
444+
445+
#connectOnce() {
446+
return new Promise((resolve, reject) => {
415447
if (this.#authenticationType === "key") {
416448
sftp.connectUsingKeyFile(
417449
this.#hostname,
@@ -420,7 +452,7 @@ class SftpClient {
420452
this.#keyFile,
421453
this.#passPhrase,
422454
resolve,
423-
retry,
455+
reject,
424456
);
425457
return;
426458
}
@@ -431,7 +463,7 @@ class SftpClient {
431463
this.#username,
432464
this.#password,
433465
resolve,
434-
retry,
466+
reject,
435467
);
436468
});
437469
}

‎src/lib/openFolder.js‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,9 +1192,10 @@ openFolder.removeItem = (url) => {
11921192

11931193
openFolder.removeFolders = (url) => {
11941194
({ url } = Url.parse(url));
1195-
const regex = new RegExp("^" + escapeStringRegexp(url));
1196-
addedFolder.forEach((folder) => {
1197-
if (regex.test(folder.url)) {
1195+
// remove() mutates addedFolder, so iterate over a snapshot to avoid skipping
1196+
// adjacent folders that belong to the same remote storage.
1197+
[...addedFolder].forEach((folder) => {
1198+
if (Url.isSameOrDescendant(folder.url, url)) {
11981199
folder.remove();
11991200
}
12001201
});

‎src/lib/recents.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const recents = {
5555
removeFolder(url) {
5656
({ url } = Url.parse(url));
5757
this.folders = this.folders.filter((folder) => {
58-
return !new RegExp("^" + escapeStringRegexp(folder.url)).test(url);
58+
return !Url.isSameOrDescendant(folder.url, url);
5959
});
6060
},
6161

‎src/pages/fileBrowser/fileBrowser.js‎

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,7 +1087,7 @@ function FileBrowserInclude(mode, info, doesOpenLast = true) {
10871087

10881088
const confirmation = await confirm(strings.warning, message);
10891089
if (!confirmation) break;
1090-
deleteFunction();
1090+
await deleteFunction();
10911091
break;
10921092
}
10931093

@@ -1219,10 +1219,35 @@ function FileBrowserInclude(mode, info, doesOpenLast = true) {
12191219
}
12201220
}
12211221

1222-
function removeStorage() {
1223-
if (url) {
1224-
recents.removeFolder(url);
1225-
recents.removeFile(url);
1222+
async function removeStorage() {
1223+
const removedStorage = storageList.find(
1224+
(storage) => storage.uuid === uuid,
1225+
);
1226+
const storageUrl = removedStorage?.url || url;
1227+
1228+
if (storageUrl) {
1229+
recents.removeFolder(storageUrl);
1230+
recents.removeFile(storageUrl);
1231+
openFolder.removeFolders(storageUrl);
1232+
helpers.updateUriOfAllActiveFiles(storageUrl, null);
1233+
}
1234+
if (
1235+
storageUrl &&
1236+
removedStorage &&
1237+
(removedStorage.storageType === "sftp" ||
1238+
removedStorage.type === "sftp")
1239+
) {
1240+
const { username, hostname, port = 22 } = Url.decodeUrl(storageUrl);
1241+
const connectionID = `${username}@${hostname}:${port}`;
1242+
await new Promise((resolve) => {
1243+
sftp.isConnected((activeConnectionID) => {
1244+
if (activeConnectionID !== connectionID) {
1245+
resolve();
1246+
return;
1247+
}
1248+
sftp.close(resolve, resolve);
1249+
}, resolve);
1250+
});
12261251
}
12271252
storageList = storageList.filter((storage) => {
12281253
if (storage.uuid !== uuid) {
@@ -1234,13 +1259,12 @@ function FileBrowserInclude(mode, info, doesOpenLast = true) {
12341259
const keyFile = decodeURIComponent(
12351260
parsedUrl.query["keyFile"] || "",
12361261
);
1237-
if (keyFile) {
1238-
fsOperation(keyFile).delete();
1239-
}
1262+
if (keyFile) fsOperation(keyFile).delete().catch(console.warn);
12401263
}
12411264
return false;
12421265
});
12431266
localStorage.storageList = JSON.stringify(storageList);
1267+
acode.exec("save-state");
12441268
reload();
12451269
}
12461270

0 commit comments

Comments
 (0)