Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 /* | 1 /* |
2 * This Source Code is subject to the terms of the Mozilla Public License | 2 * This Source Code is subject to the terms of the Mozilla Public License |
3 * version 2.0 (the "License"). You can obtain a copy of the License at | 3 * version 2.0 (the "License"). You can obtain a copy of the License at |
4 * http://mozilla.org/MPL/2.0/. | 4 * http://mozilla.org/MPL/2.0/. |
5 */ | 5 */ |
6 | 6 |
7 /** | 7 /** |
8 * @module crawler | 8 * @module crawler |
9 */ | 9 */ |
10 | 10 |
(...skipping 23 matching lines...) Expand all Loading... | |
34 * @constructor | 34 * @constructor |
35 */ | 35 */ |
36 function TabAllocator(browser, maxtabs) | 36 function TabAllocator(browser, maxtabs) |
37 { | 37 { |
38 this._browser = browser; | 38 this._browser = browser; |
39 this._tabs = 0; | 39 this._tabs = 0; |
40 this._maxtabs = maxtabs; | 40 this._maxtabs = maxtabs; |
41 // The queue containing resolve functions of promises waiting for a tab. | 41 // The queue containing resolve functions of promises waiting for a tab. |
42 this._resolvers = []; | 42 this._resolvers = []; |
43 // Keep at least one tab alive to prevent browser from closing itself. | 43 // Keep at least one tab alive to prevent browser from closing itself. |
44 let tabToRemove = this._browser.tabs[0]; | 44 this._tabKeepingWindowAlive = this._browser.tabs[0]; |
45 this._browser.removeAllTabsBut(tabToRemove); | 45 this._browser.removeAllTabsBut(this._tabKeepingWindowAlive); |
46 // this._tab is a keep alive tab | |
47 this._tab = this._createTab().then(tab => | |
48 { | |
49 // Starting from Firefox 48 (nightly) the sequence of calls addTab and | |
50 // removeTab can cause a closing of the browser because a new tab is still | |
51 // not here. Because of that we need to remove the previous tab only after | |
52 // the new tab is ready. | |
53 this._browser.removeTab(tabToRemove); | |
54 return tab; | |
55 }); | |
Wladimir Palant
2016/09/14 15:00:13
There is little point pre-allocating a tab, you ca
sergei
2016/09/15 15:33:27
Done.
| |
56 } | 46 } |
57 TabAllocator.prototype = { | 47 TabAllocator.prototype = { |
48 _removeTabKeepingWindowAlive: function() | |
49 { | |
50 if (!this._tabKeepingWindowAlive) | |
51 return; | |
52 this._browser.removeTab(this._tabKeepingWindowAlive); | |
53 delete this._tabKeepingWindowAlive; | |
54 }, | |
55 | |
58 /** | 56 /** |
59 * Creates a blank tab in this._browser. | 57 * Creates a blank tab in this._browser. |
60 * | 58 * |
61 * @return {Promise.<tab>} promise which resolves once the tab is fully initia lized. | 59 * @return {Promise.<tab>} promise which resolves once the tab is fully initia lized. |
62 */ | 60 */ |
63 _createTab: function() | 61 _createTab: function() |
64 { | 62 { |
65 this._tabs++; | 63 this._tabs++; |
66 let tab = this._browser.addTab("about:blank"); | 64 let tab = this._browser.addTab("about:blank"); |
67 if (tab.linkedBrowser.outerWindowID) | 65 if (tab.linkedBrowser.outerWindowID) |
66 { | |
67 this._removeTabKeepingWindowAlive(); | |
68 return Promise.resolve(tab); | 68 return Promise.resolve(tab); |
69 } | |
69 return new Promise((resolve, reject) => | 70 return new Promise((resolve, reject) => |
70 { | 71 { |
71 let onBrowserInit = (msg) => | 72 let onBrowserInit = (msg) => |
72 { | 73 { |
73 // https://bugzilla.mozilla.org/show_bug.cgi?id=1256602#c1 | |
Wladimir Palant
2016/09/14 15:00:13
Please don't use URL-only comments, it should be o
sergei
2016/09/15 15:33:27
Done.
| |
74 tab.linkedBrowser.messageManager.removeMessageListener("Browser:Init", o nBrowserInit); | 74 tab.linkedBrowser.messageManager.removeMessageListener("Browser:Init", o nBrowserInit); |
75 this._removeTabKeepingWindowAlive(); | |
75 resolve(tab); | 76 resolve(tab); |
76 }; | 77 }; |
78 // "Browser:Init" message is sent once the browser is ready, see | |
79 // https://bugzil.la/1256602#c1 | |
77 tab.linkedBrowser.messageManager.addMessageListener("Browser:Init", onBrow serInit); | 80 tab.linkedBrowser.messageManager.addMessageListener("Browser:Init", onBrow serInit); |
78 }); | 81 }); |
79 }, | 82 }, |
80 | 83 |
81 /** | 84 /** |
82 * Returns a promise that will resolve into a tab once a tab is allocated. | 85 * Returns a promise that will resolve into a tab once a tab is allocated. |
83 * The tab cannot be used by other tasks until releaseTab() is called. | 86 * The tab cannot be used by other tasks until releaseTab() is called. |
84 * | 87 * |
85 * @result {Promise.<tab>} | 88 * @result {Promise.<tab>} |
86 */ | 89 */ |
87 getTab: function() | 90 getTab: function() |
88 { | 91 { |
89 if (this._tab) | |
90 { | |
91 let tab = this._tab; | |
92 delete this._tab; | |
93 return tab; | |
94 } | |
95 if (this._tabs < this._maxtabs) | 92 if (this._tabs < this._maxtabs) |
96 return this._createTab(); | 93 return this._createTab(); |
97 return new Promise((resolve, reject) => this._resolvers.push(resolve)); | 94 return new Promise((resolve, reject) => this._resolvers.push(resolve)); |
98 }, | 95 }, |
99 | 96 |
100 /** | 97 /** |
101 * Adds a tab back to the pool so that it can be used by other tasks. | 98 * Adds a tab back to the pool so that it can be used by other tasks. |
102 * | 99 * |
103 * @param {tab} tab | 100 * @param {tab} tab |
104 */ | 101 */ |
105 releaseTab: function(tab) | 102 releaseTab: function(tab) |
106 { | 103 { |
107 // If we are about to close last tab don't close it immediately rather | 104 // If we are about to close last tab don't close it immediately to keep |
108 // allocate a new blank tab and close the current one afterwards. | 105 // the window alive. It will be closed when a new tab is created. |
109 if (this._tabs == 1) | 106 if (this._tabs > 1) |
110 { | 107 this._browser.removeTab(tab); |
111 this._tab = this._createTab().then((resultTab) => | 108 else |
112 { | 109 { |
113 this.releaseTab(tab); | 110 // navigate away from early opened URL |
114 return resultTab; | 111 tab.linkedBrowser.loadURI('about:blank', null, null); |
115 }); | 112 this._tabKeepingWindowAlive = tab; |
116 return; | 113 } |
117 } | 114 |
118 | |
119 this._browser.removeTab(tab); | |
120 this._tabs--; | 115 this._tabs--; |
121 if (this._resolvers.length) | 116 if (this._resolvers.length && this._tabs < this._maxtabs) |
122 { | 117 { |
123 if (this._tab) | 118 this._resolvers.shift()(this._createTab()); |
124 { | |
125 this._resolvers.shift()(this._tab); | |
126 delete this._tab; | |
127 } | |
128 else if (this._tabs < this._maxtabs) | |
129 { | |
130 this._resolvers.shift()(this._createTab()); | |
131 } | |
132 } | 119 } |
133 }, | 120 }, |
134 }; | 121 }; |
135 | 122 |
136 /** | 123 /** |
137 * Observes page loads in a particular tabbed browser. | 124 * Observes page loads in a particular tabbed browser. |
138 * | 125 * |
139 * @param {tabbrowser} browser | 126 * @param {tabbrowser} browser |
140 * The tabbed browser to be observed | 127 * The tabbed browser to be observed |
141 * @param {int} timeout | 128 * @param {int} timeout |
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
407 | 394 |
408 function reportException(e) | 395 function reportException(e) |
409 { | 396 { |
410 let stack = ""; | 397 let stack = ""; |
411 if (e && typeof e == "object" && "stack" in e) | 398 if (e && typeof e == "object" && "stack" in e) |
412 stack = e.stack + "\n"; | 399 stack = e.stack + "\n"; |
413 | 400 |
414 Cu.reportError(e); | 401 Cu.reportError(e); |
415 dump(e + "\n" + stack + "\n"); | 402 dump(e + "\n" + stack + "\n"); |
416 } | 403 } |
LEFT | RIGHT |