SessionMigration.sys.mjs (4484B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 const lazy = {}; 6 7 ChromeUtils.defineESModuleGetters(lazy, { 8 E10SUtils: "resource://gre/modules/E10SUtils.sys.mjs", 9 SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs", 10 TabGroupState: "resource:///modules/sessionstore/TabGroupState.sys.mjs", 11 }); 12 13 var SessionMigrationInternal = { 14 /** 15 * Convert the original session restore state into a minimal state. It will 16 * only contain: 17 * - open windows 18 * - with tabs 19 * - with history entries with only title, url, triggeringPrincipal 20 * - with pinned state 21 * - with tab group info 22 * - with selected tab info 23 * - with selected window info 24 * - saved tab groups 25 * 26 * The complete state is then wrapped into the "about:welcomeback" page as 27 * form field info to be restored when restoring the state. 28 */ 29 convertState(aStateObj) { 30 let state = { 31 selectedWindow: aStateObj.selectedWindow, 32 _closedWindows: [], 33 }; 34 let savedGroups = aStateObj.savedGroups || []; 35 state.windows = aStateObj.windows.map(function (oldWin) { 36 var win = { extData: {} }; 37 if (oldWin.groups) { 38 win.groups = oldWin.groups; 39 } 40 let groupsToSave = new Map(); 41 win.tabs = oldWin.tabs.map(function (oldTab) { 42 var tab = {}; 43 // Keep only titles, urls and triggeringPrincipals for history entries 44 tab.entries = oldTab.entries.map(function (entry) { 45 return { 46 url: entry.url, 47 triggeringPrincipal_base64: entry.triggeringPrincipal_base64, 48 title: entry.title, 49 }; 50 }); 51 tab.index = oldTab.index; 52 tab.hidden = oldTab.hidden; 53 tab.pinned = oldTab.pinned; 54 if (oldTab.groupId) { 55 tab.groupId = oldTab.groupId; 56 let groupStateToSave = oldWin.groups.find( 57 groupState => groupState.id == oldTab.groupId 58 ); 59 let groupToSave = groupsToSave.get(groupStateToSave.id); 60 if (!groupToSave) { 61 groupToSave = 62 lazy.TabGroupState.savedInClosedWindow(groupStateToSave); 63 // If the session is manually restored, these groups will be removed from the saved groups list 64 // to prevent duplication. 65 groupToSave.removeAfterRestore = true; 66 groupsToSave.set(groupStateToSave.id, groupToSave); 67 } 68 groupToSave.tabs.push( 69 lazy.SessionStore.formatTabStateForSavedGroup(tab) 70 ); 71 } 72 return tab; 73 }); 74 groupsToSave.forEach(groupState => { 75 const alreadySavedGroup = savedGroups.find( 76 existingGroup => existingGroup.id == groupState.id 77 ); 78 if (alreadySavedGroup) { 79 alreadySavedGroup.removeAfterRestore = true; 80 } else { 81 savedGroups.push(groupState); 82 } 83 }); 84 win.selected = oldWin.selected; 85 win._closedTabs = []; 86 return win; 87 }); 88 let url = "about:welcomeback"; 89 let formdata = { id: { sessionData: state }, url }; 90 let entry = { 91 url, 92 triggeringPrincipal_base64: lazy.E10SUtils.SERIALIZED_SYSTEMPRINCIPAL, 93 }; 94 return { 95 windows: [{ tabs: [{ entries: [entry], formdata }] }], 96 savedGroups, 97 }; 98 }, 99 /** 100 * Asynchronously read session restore state (JSON) from a path 101 */ 102 readState(aPath) { 103 return IOUtils.readJSON(aPath, { decompress: true }); 104 }, 105 /** 106 * Asynchronously write session restore state as JSON to a path 107 */ 108 writeState(aPath, aState) { 109 return IOUtils.writeJSON(aPath, aState, { 110 compress: true, 111 tmpPath: `${aPath}.tmp`, 112 }); 113 }, 114 }; 115 116 export var SessionMigration = { 117 /** 118 * Migrate a limited set of session data from one path to another. 119 */ 120 migrate(aFromPath, aToPath) { 121 return (async function () { 122 let inState = await SessionMigrationInternal.readState(aFromPath); 123 let outState = SessionMigrationInternal.convertState(inState); 124 // Unfortunately, we can't use SessionStore's own SessionFile to 125 // write out the data because it has a dependency on the profile dir 126 // being known. When the migration runs, there is no guarantee that 127 // that's true. 128 await SessionMigrationInternal.writeState(aToPath, outState); 129 })(); 130 }, 131 };