| 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 |