aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortoasted-nutbread <toasted-nutbread@users.noreply.github.com>2020-07-18 14:16:35 -0400
committerGitHub <noreply@github.com>2020-07-18 14:16:35 -0400
commita13a68990eac548f8439050222ddf3cb97146199 (patch)
treecde32346ea25cc6fb685461ace3e1d512842f51b
parentdac33e696145ad3c2cfe076a7fadc82c05732102 (diff)
Port name details (#667)
* Use a stringified JSON details object for extension port names * Fix incorrect frame ID check * Add support for connecting to different tabs * Add function for invoking on a different tab
-rw-r--r--ext/bg/js/backend.js31
-rw-r--r--ext/mixed/js/api.js15
-rw-r--r--ext/mixed/js/comm.js77
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;