feat: Make sure to search from other backups files when restoring, b=no-bug, c=no-component

This commit is contained in:
mr. m
2026-02-21 00:04:09 +01:00
parent 29eae92fcb
commit 97078b42ac
3 changed files with 53 additions and 16 deletions

View File

@@ -4,7 +4,7 @@
# GTK-specific preferences
- name: widget.gtk.rounded-bottom-corners.enabled
# Disabled for https://github.com/zen-browser/desktop/issues/6302,
# Disabled for https://github.com/zen-browser/desktop/issues/6302,
# also see https://bugzilla.mozilla.org/show_bug.cgi?id=1979083
value: false
condition: "defined(MOZ_WIDGET_GTK)"

View File

@@ -110,6 +110,23 @@ export class nsZenSessionManager {
return PathUtils.join(PathUtils.profileDir, "zen-sessions-backup");
}
async #getBackupRecoveryOrder() {
// Also add the most recent backup file to the recovery order
let backupFiles = [PathUtils.join(this.#backupFolderPath, "clean.jsonlz4")];
let prefix = PathUtils.join(this.#backupFolderPath, "zen-sessions-");
try {
let files = await IOUtils.getChildren(this.#backupFolderPath);
files = files
.filter((file) => file.startsWith(prefix))
.sort()
.reverse();
backupFiles.push(files[0]);
} catch {
/* ignore errors reading backup folder */
}
return backupFiles;
}
/**
* Gets the spaces data from the Places database for migration.
* This is only called once during the first run after updating
@@ -199,6 +216,31 @@ export class nsZenSessionManager {
}
}
async #readDataFromFile() {
try {
await this.#file.load();
this._dataFromFile = this.#file.data;
if (!this._dataFromFile?.spaces) {
// Go to the catch block to try to recover from backup files
// if the file is empty or has invalid data, as it can happen if the app
// crashes while writing the session file.
throw new Error("No data in session file");
}
} catch {
for (const backupFile of await this.#getBackupRecoveryOrder()) {
try {
let data = await IOUtils.readJSON(backupFile, { decompress: true });
this.log(`Recovered data from backup file ${backupFile}`);
this._dataFromFile = data;
break;
} catch (e) {
/* ignore errors reading backup files */
console.error(`Failed to read backup file ${backupFile}`, e);
}
}
}
}
/**
* Reads the session file and populates the sidebar object.
* This should be only called once at startup.
@@ -206,25 +248,14 @@ export class nsZenSessionManager {
* @see SessionFileInternal.read
*/
async readFile() {
let fileExists = await IOUtils.exists(this.#storeFilePath);
if (!fileExists) {
this.log("Session file does not exist, running migration", this.#storeFilePath);
this._shouldRunMigration = true;
}
this.init();
try {
this.log("Reading Zen session file from disk");
let promises = [];
promises.push(this.#file.load());
if (this._shouldRunMigration) {
promises.push(this.#getDataFromDBForMigration());
}
await Promise.all(promises);
await this.#readDataFromFile();
} catch (e) {
console.error("ZenSessionManager: Failed to read session file", e);
}
console.log(this.#file.dataReady)
this.#sidebar = this.#file.data || {};
this.#sidebar = this._dataFromFile || {};
if (!this.#sidebar.spaces?.length && !this._shouldRunMigration) {
this.log("No spaces data found in session file, running migration", this.#sidebar);
// If we have no spaces data, we should run migration
@@ -238,6 +269,7 @@ export class nsZenSessionManager {
this.log("Tab entry in session file:", tab);
}
}
delete this._dataFromFile;
}
get #shouldRestoreOnlyPinned() {
@@ -414,7 +446,7 @@ export class nsZenSessionManager {
];
}
for (const winData of initialState?.windows || []) {
winData.spaces = this._migrationData?.spaces || [];
winData.spaces = winData.spaces || this._migrationData?.spaces || [];
if (winData.tabs) {
for (const tabData of winData.tabs) {
let storeId = tabData.zenSyncId || tabData.zenPinnedId;
@@ -475,6 +507,11 @@ export class nsZenSessionManager {
// browsing mode. We also don't want to save if there are no windows.
return;
}
const cleanPath = PathUtils.join(this.#backupFolderPath, "clean.jsonlz4");
IOUtils.copy(this.#storeFilePath, cleanPath, { recursive: true }).catch(() => {
/* ignore errors creating clean backup, as it is not critical and
* we want to save the session even if we fail to create it */
});
this.#collectWindowData(windows);
// This would save the data to disk asynchronously or when quitting the app.
let sidebar = this.#sidebar;

View File

@@ -20,7 +20,7 @@
"brandShortName": "Zen",
"brandFullName": "Zen Browser",
"release": {
"displayVersion": "1.18.9b",
"displayVersion": "1.18.10b",
"github": {
"repo": "zen-browser/desktop"
},