Bug 1944416: Restore individual tabs from closed groups in closed windows r=dao,sessi...
[gecko.git] / browser / components / sessionstore / SessionMigration.sys.mjs
blob7f2548890d8f748bbc5cbe3c4d153a9c38ccc013
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/. */
5 const lazy = {};
7 ChromeUtils.defineESModuleGetters(lazy, {
8   E10SUtils: "resource://gre/modules/E10SUtils.sys.mjs",
9 });
11 var SessionMigrationInternal = {
12   /**
13    * Convert the original session restore state into a minimal state. It will
14    * only contain:
15    * - open windows
16    *   - with tabs
17    *     - with history entries with only title, url, triggeringPrincipal
18    *     - with pinned state
19    *     - with tab group info (hidden + group id)
20    *     - with selected tab info
21    *   - with selected window info
22    *
23    * The complete state is then wrapped into the "about:welcomeback" page as
24    * form field info to be restored when restoring the state.
25    */
26   convertState(aStateObj) {
27     let state = {
28       selectedWindow: aStateObj.selectedWindow,
29       _closedWindows: [],
30     };
31     state.windows = aStateObj.windows.map(function (oldWin) {
32       var win = { extData: {} };
33       win.tabs = oldWin.tabs.map(function (oldTab) {
34         var tab = {};
35         // Keep only titles, urls and triggeringPrincipals for history entries
36         tab.entries = oldTab.entries.map(function (entry) {
37           return {
38             url: entry.url,
39             triggeringPrincipal_base64: entry.triggeringPrincipal_base64,
40             title: entry.title,
41           };
42         });
43         tab.index = oldTab.index;
44         tab.hidden = oldTab.hidden;
45         tab.pinned = oldTab.pinned;
46         return tab;
47       });
48       win.selected = oldWin.selected;
49       win._closedTabs = [];
50       return win;
51     });
52     let url = "about:welcomeback";
53     let formdata = { id: { sessionData: state }, url };
54     let entry = {
55       url,
56       triggeringPrincipal_base64: lazy.E10SUtils.SERIALIZED_SYSTEMPRINCIPAL,
57     };
58     return { windows: [{ tabs: [{ entries: [entry], formdata }] }] };
59   },
60   /**
61    * Asynchronously read session restore state (JSON) from a path
62    */
63   readState(aPath) {
64     return IOUtils.readJSON(aPath, { decompress: true });
65   },
66   /**
67    * Asynchronously write session restore state as JSON to a path
68    */
69   writeState(aPath, aState) {
70     return IOUtils.writeJSON(aPath, aState, {
71       compress: true,
72       tmpPath: `${aPath}.tmp`,
73     });
74   },
77 export var SessionMigration = {
78   /**
79    * Migrate a limited set of session data from one path to another.
80    */
81   migrate(aFromPath, aToPath) {
82     return (async function () {
83       let inState = await SessionMigrationInternal.readState(aFromPath);
84       let outState = SessionMigrationInternal.convertState(inState);
85       // Unfortunately, we can't use SessionStore's own SessionFile to
86       // write out the data because it has a dependency on the profile dir
87       // being known. When the migration runs, there is no guarantee that
88       // that's true.
89       await SessionMigrationInternal.writeState(aToPath, outState);
90     })();
91   },