diff options
| -rw-r--r-- | ext/bg/js/backend.js | 31 | ||||
| -rw-r--r-- | ext/mixed/js/api.js | 15 | ||||
| -rw-r--r-- | ext/mixed/js/comm.js | 77 | 
3 files changed, 89 insertions, 34 deletions
| diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index f6c2ef74..f0ed986c 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -305,20 +305,32 @@ class Backend {      _onConnect(port) {          try { -            const match = /^background-cross-frame-communication-port-(\d+)$/.exec(`${port.name}`); -            if (match === null) { return; } +            let details; +            try { +                details = JSON.parse(port.name); +            } catch (e) { +                return; +            } +            if (details.name !== 'background-cross-frame-communication-port') { return; }              const tabId = (port.sender && port.sender.tab ? port.sender.tab.id : null);              if (typeof tabId !== 'number') {                  throw new Error('Port does not have an associated tab ID');              }              const senderFrameId = port.sender.frameId; -            if (typeof tabId !== 'number') { +            if (typeof senderFrameId !== 'number') {                  throw new Error('Port does not have an associated frame ID');              } -            const targetFrameId = parseInt(match[1], 10); +            let {targetTabId, targetFrameId} = details; +            if (typeof targetTabId !== 'number') { +                targetTabId = tabId; +            } -            let forwardPort = chrome.tabs.connect(tabId, {frameId: targetFrameId, name: `cross-frame-communication-port-${senderFrameId}`}); +            const details2 = { +                name: 'cross-frame-communication-port', +                sourceFrameId: senderFrameId +            }; +            let forwardPort = chrome.tabs.connect(targetTabId, {frameId: targetFrameId, name: JSON.stringify(details2)});              const cleanup = () => {                  this._checkLastError(chrome.runtime.lastError); @@ -720,9 +732,12 @@ class Backend {          const frameId = sender.frameId;          const id = yomichan.generateId(16); -        const portName = `action-port-${id}`; +        const details = { +            name: 'action-port', +            id +        }; -        const port = chrome.tabs.connect(tabId, {name: portName, frameId}); +        const port = chrome.tabs.connect(tabId, {name: JSON.stringify(details), frameId});          try {              this._createActionListenerPort(port, sender, this._messageHandlersWithProgress);          } catch (e) { @@ -730,7 +745,7 @@ class Backend {              throw e;          } -        return portName; +        return details;      }      async _onApiImportDictionaryArchive({archiveContent, details}, sender, onProgress) { 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; |