/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { E10SUtils: "resource://gre/modules/E10SUtils.sys.mjs", SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs", TabGroupState: "resource:///modules/sessionstore/TabGroupState.sys.mjs", }); var SessionMigrationInternal = { /** * Convert the original session restore state into a minimal state. It will * only contain: * - open windows * - with tabs * - with history entries with only title, url, triggeringPrincipal * - with pinned state * - with tab group info * - with selected tab info * - with selected window info * - saved tab groups * * The complete state is then wrapped into the "about:welcomeback" page as * form field info to be restored when restoring the state. */ convertState(aStateObj) { let state = { selectedWindow: aStateObj.selectedWindow, _closedWindows: [], }; let savedGroups = aStateObj.savedGroups || []; state.windows = aStateObj.windows.map(function (oldWin) { var win = { extData: {} }; if (oldWin.groups) { win.groups = oldWin.groups; } let groupsToSave = new Map(); win.tabs = oldWin.tabs.map(function (oldTab) { var tab = {}; // Keep only titles, urls and triggeringPrincipals for history entries tab.entries = oldTab.entries.map(function (entry) { return { url: entry.url, triggeringPrincipal_base64: entry.triggeringPrincipal_base64, title: entry.title, }; }); tab.index = oldTab.index; tab.hidden = oldTab.hidden; tab.pinned = oldTab.pinned; if (oldTab.groupId) { tab.groupId = oldTab.groupId; let groupStateToSave = oldWin.groups.find( groupState => groupState.id == oldTab.groupId ); let groupToSave = groupsToSave.get(groupStateToSave.id); if (!groupToSave) { groupToSave = lazy.TabGroupState.savedInClosedWindow(groupStateToSave); // If the session is manually restored, these groups will be removed from the saved groups list // to prevent duplication. groupToSave.removeAfterRestore = true; groupsToSave.set(groupStateToSave.id, groupToSave); } groupToSave.tabs.push( lazy.SessionStore.formatTabStateForSavedGroup(tab) ); } return tab; }); groupsToSave.forEach(groupState => { const alreadySavedGroup = savedGroups.find( existingGroup => existingGroup.id == groupState.id ); if (alreadySavedGroup) { alreadySavedGroup.removeAfterRestore = true; } else { savedGroups.push(groupState); } }); win.selected = oldWin.selected; win._closedTabs = []; return win; }); let url = "about:welcomeback"; let formdata = { id: { sessionData: state }, url }; let entry = { url, triggeringPrincipal_base64: lazy.E10SUtils.SERIALIZED_SYSTEMPRINCIPAL, }; return { windows: [{ tabs: [{ entries: [entry], formdata }] }], savedGroups, }; }, /** * Asynchronously read session restore state (JSON) from a path */ readState(aPath) { return IOUtils.readJSON(aPath, { decompress: true }); }, /** * Asynchronously write session restore state as JSON to a path */ writeState(aPath, aState) { return IOUtils.writeJSON(aPath, aState, { compress: true, tmpPath: `${aPath}.tmp`, }); }, }; export var SessionMigration = { /** * Migrate a limited set of session data from one path to another. */ migrate(aFromPath, aToPath) { return (async function () { let inState = await SessionMigrationInternal.readState(aFromPath); let outState = SessionMigrationInternal.convertState(inState); // Unfortunately, we can't use SessionStore's own SessionFile to // write out the data because it has a dependency on the profile dir // being known. When the migration runs, there is no guarantee that // that's true. await SessionMigrationInternal.writeState(aToPath, outState); })(); }, };