browser/components/sessionstore/src/SessionMigration.jsm

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:8b3eca7a5700
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 "use strict";
6
7 this.EXPORTED_SYMBOLS = ["SessionMigration"];
8
9 const Cu = Components.utils;
10 Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
11 Cu.import("resource://gre/modules/Task.jsm", this);
12 Cu.import("resource://gre/modules/osfile.jsm", this);
13
14 // An encoder to UTF-8.
15 XPCOMUtils.defineLazyGetter(this, "gEncoder", function () {
16 return new TextEncoder();
17 });
18
19 // A decoder.
20 XPCOMUtils.defineLazyGetter(this, "gDecoder", function () {
21 return new TextDecoder();
22 });
23
24 let SessionMigrationInternal = {
25 /**
26 * Convert the original session restore state into a minimal state. It will
27 * only contain:
28 * - open windows
29 * - with tabs
30 * - with history entries with only title, url
31 * - with pinned state
32 * - with tab group info (hidden + group id)
33 * - with selected tab info
34 * - with selected window info
35 * - with tabgroups info
36 *
37 * The complete state is then wrapped into the "about:welcomeback" page as
38 * form field info to be restored when restoring the state.
39 */
40 convertState: function(aStateObj) {
41 let state = {
42 selectedWindow: aStateObj.selectedWindow,
43 _closedWindows: []
44 };
45 state.windows = aStateObj.windows.map(function(oldWin) {
46 var win = {extData: {}};
47 win.tabs = oldWin.tabs.map(function(oldTab) {
48 var tab = {};
49 // Keep only titles and urls for history entries
50 tab.entries = oldTab.entries.map(function(entry) {
51 return {url: entry.url, title: entry.title};
52 });
53 tab.index = oldTab.index;
54 tab.hidden = oldTab.hidden;
55 tab.pinned = oldTab.pinned;
56 // The tabgroup info is in the extData, so we need to get it out.
57 if (oldTab.extData && "tabview-tab" in oldTab.extData) {
58 tab.extData = {"tabview-tab": oldTab.extData["tabview-tab"]};
59 }
60 return tab;
61 });
62 // There are various tabgroup-related attributes that we need to get out
63 // of the session restore data for the window, too.
64 if (oldWin.extData) {
65 for (let k of Object.keys(oldWin.extData)) {
66 if (k.startsWith("tabview-")) {
67 win.extData[k] = oldWin.extData[k];
68 }
69 }
70 }
71 win.selected = oldWin.selected;
72 win._closedTabs = [];
73 return win;
74 });
75 let wrappedState = {
76 url: "about:welcomeback",
77 formdata: {
78 id: {"sessionData": state},
79 xpath: {}
80 }
81 };
82 return {windows: [{tabs: [{entries: [wrappedState]}]}]};
83 },
84 /**
85 * Asynchronously read session restore state (JSON) from a path
86 */
87 readState: function(aPath) {
88 return Task.spawn(function() {
89 let bytes = yield OS.File.read(aPath);
90 let text = gDecoder.decode(bytes);
91 let state = JSON.parse(text);
92 throw new Task.Result(state);
93 });
94 },
95 /**
96 * Asynchronously write session restore state as JSON to a path
97 */
98 writeState: function(aPath, aState) {
99 let bytes = gEncoder.encode(JSON.stringify(aState));
100 return OS.File.writeAtomic(aPath, bytes, {tmpPath: aPath + ".tmp"});
101 }
102 }
103
104 let SessionMigration = {
105 /**
106 * Migrate a limited set of session data from one path to another.
107 */
108 migrate: function(aFromPath, aToPath) {
109 return Task.spawn(function() {
110 let inState = yield SessionMigrationInternal.readState(aFromPath);
111 let outState = SessionMigrationInternal.convertState(inState);
112 // Unfortunately, we can't use SessionStore's own SessionFile to
113 // write out the data because it has a dependency on the profile dir
114 // being known. When the migration runs, there is no guarantee that
115 // that's true.
116 yield SessionMigrationInternal.writeState(aToPath, outState);
117 });
118 }
119 };

mercurial