diff options
Diffstat (limited to 'ext/mixed/js')
-rw-r--r-- | ext/mixed/js/api.js | 15 | ||||
-rw-r--r-- | ext/mixed/js/comm.js | 77 |
2 files changed, 66 insertions, 26 deletions
diff --git a/ext/mixed/js/api.js b/ext/mixed/js/api.js index 534154ef..4009c86e 100644 --- a/ext/mixed/js/api.js +++ b/ext/mixed/js/api.js @@ -212,16 +212,13 @@ const api = (() => { _createActionPort(timeout=5000) { return new Promise((resolve, reject) => { let timer = null; - const { - promise: portNamePromise, - resolve: portNameResolve, - reject: portNameReject - } = deferPromise(); + const portDetails = deferPromise(); const onConnect = async (port) => { try { - const portName = await portNamePromise; - if (port.name !== portName || timer === null) { return; } + const {name: expectedName, id: expectedId} = await portDetails.promise; + const {name, id} = JSON.parse(port.name); + if (name !== expectedName || id !== expectedId || timer === null) { return; } } catch (e) { return; } @@ -239,14 +236,14 @@ const api = (() => { timer = null; } chrome.runtime.onConnect.removeListener(onConnect); - portNameReject(e); + portDetails.reject(e); reject(e); }; timer = setTimeout(() => onError(new Error('Timeout')), timeout); chrome.runtime.onConnect.addListener(onConnect); - this._invoke('createActionPort').then(portNameResolve, onError); + this._invoke('createActionPort').then(portDetails.resolve, onError); }); } diff --git a/ext/mixed/js/comm.js b/ext/mixed/js/comm.js index 1516a98f..1264a33e 100644 --- a/ext/mixed/js/comm.js +++ b/ext/mixed/js/comm.js @@ -16,8 +16,9 @@ */ class CrossFrameAPIPort extends EventDispatcher { - constructor(otherFrameId, port, messageHandlers) { + constructor(otherTabId, otherFrameId, port, messageHandlers) { super(); + this._otherTabId = otherTabId; this._otherFrameId = otherFrameId; this._port = port; this._messageHandlers = messageHandlers; @@ -26,6 +27,10 @@ class CrossFrameAPIPort extends EventDispatcher { this._eventListeners = new EventListenerCollection(); } + get otherTabId() { + return this._otherTabId; + } + get otherFrameId() { return this._otherFrameId; } @@ -211,8 +216,12 @@ class CrossFrameAPI { chrome.runtime.onConnect.addListener(this._onConnect.bind(this)); } - async invoke(targetFrameId, action, params={}) { - const commPort = this._getOrCreateCommPort(targetFrameId); + invoke(targetFrameId, action, params={}) { + return this.invokeTab(null, targetFrameId, action, params); + } + + async invokeTab(targetTabId, targetFrameId, action, params={}) { + const commPort = this._getOrCreateCommPort(targetTabId, targetFrameId); return await commPort.invoke(action, params, this._ackTimeout, this._responseTimeout); } @@ -226,31 +235,65 @@ class CrossFrameAPI { } _onConnect(port) { - const match = /^cross-frame-communication-port-(\d+)$/.exec(`${port.name}`); - if (match === null) { return; } + try { + let details; + try { + details = JSON.parse(port.name); + } catch (e) { + return; + } + if (details.name !== 'cross-frame-communication-port') { return; } - const otherFrameId = parseInt(match[1], 10); - this._setupCommPort(otherFrameId, port); + const otherTabId = details.sourceTabId; + const otherFrameId = details.sourceFrameId; + this._setupCommPort(otherTabId, otherFrameId, port); + } catch (e) { + port.disconnect(); + yomichan.logError(e); + } } _onDisconnect(commPort) { commPort.off('disconnect', this._onDisconnectBind); - this._commPorts.delete(commPort.otherFrameId); + const {otherTabId, otherFrameId} = commPort; + const tabPorts = this._commPorts.get(otherTabId); + if (typeof tabPorts !== 'undefined') { + tabPorts.delete(otherFrameId); + if (tabPorts.size === 0) { + this._commPorts.delete(otherTabId); + } + } } - _getOrCreateCommPort(otherFrameId) { - const commPort = this._commPorts.get(otherFrameId); - return (typeof commPort !== 'undefined' ? commPort : this._createCommPort(otherFrameId)); + _getOrCreateCommPort(otherTabId, otherFrameId) { + const tabPorts = this._commPorts.get(otherTabId); + if (typeof tabPorts !== 'undefined') { + const commPort = tabPorts.get(otherFrameId); + if (typeof commPort !== 'undefined') { + return commPort; + } + } + return this._createCommPort(otherTabId, otherFrameId); } - _createCommPort(otherFrameId) { - const port = yomichan.connect(null, {name: `background-cross-frame-communication-port-${otherFrameId}`}); - return this._setupCommPort(otherFrameId, port); + _createCommPort(otherTabId, otherFrameId) { + const details = { + name: 'background-cross-frame-communication-port', + targetTabId: otherTabId, + targetFrameId: otherFrameId + }; + const port = yomichan.connect(null, {name: JSON.stringify(details)}); + return this._setupCommPort(otherTabId, otherFrameId, port); } - _setupCommPort(otherFrameId, port) { - const commPort = new CrossFrameAPIPort(otherFrameId, port, this._messageHandlers); - this._commPorts.set(otherFrameId, commPort); + _setupCommPort(otherTabId, otherFrameId, port) { + const commPort = new CrossFrameAPIPort(otherTabId, otherFrameId, port, this._messageHandlers); + let tabPorts = this._commPorts.get(otherTabId); + if (typeof tabPorts === 'undefined') { + tabPorts = new Map(); + this._commPorts.set(otherTabId, tabPorts); + } + tabPorts.set(otherFrameId, commPort); commPort.prepare(); commPort.on('disconnect', this._onDisconnectBind); return commPort; |