diff --git a/extension/extension-utils.js b/extension/extension-utils.js --- a/extension/extension-utils.js +++ b/extension/extension-utils.js @@ -20,6 +20,9 @@ var callbacks = {}; // TODO rename to "portCallbacks"? var runtimeCallbacks = {}; +let currentMessageSerial = 0; +let pendingMessageReplyResolvers = {}; + var storage = (IS_FIREFOX ? chrome.storage.local : chrome.storage.sync); let firefoxVersionMatch = navigator.userAgent.match(/Firefox\/(\d+)/) @@ -53,6 +56,19 @@ port.postMessage(message); } +function sendPortMessageWithReply(subsystem, event, payload) +{ + return new Promise((resolve, reject) => { + let message = payload || {}; + message.subsystem = subsystem; + message.event = event; + message.serial = ++currentMessageSerial; + pendingMessageReplyResolvers[message.serial] = resolve; + + port.postMessage(message); + }); +} + // Callback is called with following arguments (in that order); // - The actual message data/payload // - Information about the sender of the message (including tab and frameId) diff --git a/extension/extension.js b/extension/extension.js --- a/extension/extension.js +++ b/extension/extension.js @@ -104,13 +104,25 @@ port.onMessage.addListener(function (message) { var subsystem = message.subsystem; var action = message.action; + let replyToSerial = message.replyToSerial; - if (!subsystem || !action) { + if (!replyToSerial && (!subsystem || !action)) { return; } receivedMessageOnce = true; + if (replyToSerial === "number") { + let replyResolver = pendingMessageReplyResolvers[replyToSerial]; + if (replyResolver) { + replyResolver(message.payload); + delete pendingMessageReplyResolvers[replyToSerial]; + } else { + console.warn("There is no reply resolver for message with serial", replyToSerial); + } + return; + } + if (callbacks[subsystem] && callbacks[subsystem][action]) { callbacks[subsystem][action](message.payload, action); } else { diff --git a/host/abstractbrowserplugin.h b/host/abstractbrowserplugin.h --- a/host/abstractbrowserplugin.h +++ b/host/abstractbrowserplugin.h @@ -58,6 +58,7 @@ virtual bool onUnload(); void sendData(const QString &action, const QJsonObject &payload = QJsonObject()); + void sendReply(const QJsonObject &payload = QJsonObject()); QDebug debug() const; QJsonObject settings() const; @@ -69,4 +70,5 @@ int m_protocolVersion; bool m_loaded = false; + int m_currentRequestSerial = 0; }; diff --git a/host/abstractbrowserplugin.cpp b/host/abstractbrowserplugin.cpp --- a/host/abstractbrowserplugin.cpp +++ b/host/abstractbrowserplugin.cpp @@ -50,6 +50,21 @@ Connection::self()->sendData(data); } +void AbstractBrowserPlugin::sendReply(const QJsonObject &payload) +{ + Q_ASSERT(m_currentRequestSerial > 0); + + QJsonObject data{ + {QStringLiteral("replyToSerial"), m_currentRequestSerial}, + }; + + if (!payload.isEmpty()) { + data.insert(QStringLiteral("payload"), payload); + } + + Connection::self()->sendData(data); +} + bool AbstractBrowserPlugin::onLoad() { return true; diff --git a/host/pluginmanager.cpp b/host/pluginmanager.cpp --- a/host/pluginmanager.cpp +++ b/host/pluginmanager.cpp @@ -124,6 +124,12 @@ return; } + const int requestSerial = json.value(QStringLiteral("serial")).toInt(); + plugin->m_currentRequestSerial = requestSerial; + //design question, should we have a JSON of subsystem, event, payload, or have all data at the root level? plugin->handleData(event, json); + + // TODO would be cool to have a delayed reply kind of feature like QDBusContext + plugin->m_currentRequestSerial = 0; }