summaryrefslogtreecommitdiff
path: root/src/webchannel/qwebchannel.js
diff options
context:
space:
mode:
authorMilian Wolff <milian.wolff@kdab.com>2014-07-10 00:05:28 +0200
committerMilian Wolff <milian.wolff@kdab.com>2014-07-29 13:58:04 +0200
commit94912cf26ba70a2cadd23f1c931395be64c11eac (patch)
tree28cfa1d98bbcc7eeccba6de1e3317e30add56a2f /src/webchannel/qwebchannel.js
parent77a4c34bb0f3b8cc3107f9fc6be0f5f7b23bb9d6 (diff)
downloadqtwebchannel-94912cf26ba70a2cadd23f1c931395be64c11eac.tar.gz
Refactor and streamline API and IPC protocol.
This patch removes the obsolete API support to send raw messages using a QWebChannel. Instead, it is encouraged to directly use WebSockets or navigator.qt. By doing so, we can cleanup the code considerably. While at it, the transport API is adapted to work on QJsonObject messages, instead of QStrings. This will allow us to use more efficient formats in e.g. QtWebKit or QtWebEngine. One could also implement a JSONRPC interface using a custom transport then. Change-Id: Ia8c125a5558507b3cbecf128a46b19fdb013f47b Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
Diffstat (limited to 'src/webchannel/qwebchannel.js')
-rw-r--r--src/webchannel/qwebchannel.js218
1 files changed, 107 insertions, 111 deletions
diff --git a/src/webchannel/qwebchannel.js b/src/webchannel/qwebchannel.js
index dd6c4b3..3274d65 100644
--- a/src/webchannel/qwebchannel.js
+++ b/src/webchannel/qwebchannel.js
@@ -52,9 +52,12 @@ var QWebChannelMessageTypes = {
connectToSignal: 7,
disconnectFromSignal: 8,
setProperty: 9,
+ response: 10,
};
-var QWebChannel = function(baseUrlOrSocket, initCallback, rawChannel)
+// TODO: always expect an initialized transport object with a defined interface
+// to be passed in, remove automagic WebSocket code
+var QWebChannel = function(baseUrlOrSocket, initCallback)
{
var channel = this;
this.send = function(data)
@@ -64,33 +67,115 @@ var QWebChannel = function(baseUrlOrSocket, initCallback, rawChannel)
}
channel.socket.send(data);
}
- this.messageReceived = function(message)
+ this.onMessageReceived = function(message)
{
- var jsonData = JSON.parse(message.data);
- if (jsonData.id === undefined) {
- console.error("invalid message received:", message.data);
+ var data = message.data;
+ if (typeof data === "string") {
+ data = JSON.parse(data);
+ }
+ switch (data.type) {
+ case QWebChannelMessageTypes.signal:
+ channel.handleSignal(data);
+ break;
+ case QWebChannelMessageTypes.response:
+ channel.handleResponse(data);
+ break;
+ case QWebChannelMessageTypes.propertyUpdate:
+ channel.handlePropertyUpdate(data);
+ break;
+ case QWebChannelMessageTypes.init:
+ channel.handleInit(data);
+ break;
+ default:
+ console.error("invalid message received:", message.data);
+ break;
+ }
+ }
+
+ this.execCallbacks = {};
+ this.execId = 0;
+ this.exec = function(data, callback)
+ {
+ if (!callback) {
+ // if no callback is given, send directly
+ channel.send(data);
return;
}
- if (jsonData.data === undefined) {
- jsonData.data = {};
+ if (channel.execId === Number.MAX_VALUE) {
+ // wrap
+ channel.execId = Number.MIN_VALUE;
}
- if (jsonData.response) {
- channel.execCallbacks[jsonData.id](jsonData.data);
- delete channel.execCallbacks[jsonData.id];
- } else if (channel.subscriptions[jsonData.id]) {
- channel.subscriptions[jsonData.id].forEach(function(callback) {
- (callback)(jsonData.data); }
- );
+ if (data.hasOwnProperty("id")) {
+ console.error("Cannot exec message with property id: " + JSON.stringify(data));
+ return;
+ }
+ data.id = channel.execId++;
+ channel.execCallbacks[data.id] = callback;
+ channel.send(data);
+ };
+
+ this.objects = {};
+
+ this.handleSignal = function(message)
+ {
+ var object = channel.objects[message.object];
+ if (object) {
+ object.signalEmitted(message.signal, message.args);
+ } else {
+ console.warn("Unhandled signal: " + message.object + "::" + message.signal);
}
}
- this.initialized = function()
+ this.handleResponse = function(message)
{
- if (rawChannel) {
+ if (!message.hasOwnProperty("id")) {
+ console.error("Invalid response message received: ", JSON.stringify(message));
+ return;
+ }
+ channel.execCallbacks[message.id](message.data);
+ delete channel.execCallbacks[message.id];
+ }
+
+ this.handlePropertyUpdate = function(message)
+ {
+ for (var i in message.data) {
+ var data = message.data[i];
+ var object = channel.objects[data.object];
+ if (object) {
+ object.propertyUpdate(data.signals, data.properties);
+ } else {
+ console.warn("Unhandled property update: " + data.object + "::" + data.signal);
+ }
+ }
+ setTimeout(function() { channel.exec({type: QWebChannelMessageTypes.idle}); }, 0);
+ }
+
+ // prevent multiple initialization which might happen with multiple webchannel clients.
+ this.initialized = false;
+ this.handleInit = function(message)
+ {
+ if (channel.initialized) {
+ return;
+ }
+ channel.initialized = true;
+ for (var objectName in message.data) {
+ var data = message.data[objectName];
+ var object = new QObject(objectName, data, channel);
+ }
+ if (initCallback) {
initCallback(channel);
- } else {
- channel.initMetaObjectPublisher(initCallback);
}
+ setTimeout(function() { channel.exec({type: QWebChannelMessageTypes.idle}); }, 0);
+ }
+
+ this.debug = function(message)
+ {
+ channel.send({type: QWebChannelMessageTypes.debug, data: message});
+ };
+
+ this.onSocketReady = function(doneCallback)
+ {
+ channel.exec({type: QWebChannelMessageTypes.init});
}
if (typeof baseUrlOrSocket === 'object') {
@@ -99,13 +184,13 @@ var QWebChannel = function(baseUrlOrSocket, initCallback, rawChannel)
{
channel.socket.postMessage(data);
}
- this.socket.onmessage = this.messageReceived
- setTimeout(this.initialized, 0);
+ this.socket.onmessage = this.onMessageReceived
+ this.onSocketReady();
} else {
///TODO: use QWebChannel protocol, once custom protcols are supported by QtWebSocket
this.socket = new WebSocket(baseUrlOrSocket/*, "QWebChannel" */);
- this.socket.onopen = this.initialized
+ this.socket.onopen = this.onSocketReady
this.socket.onclose = function()
{
console.error("web channel closed");
@@ -114,96 +199,7 @@ var QWebChannel = function(baseUrlOrSocket, initCallback, rawChannel)
{
console.error("web channel error: " + error);
};
- this.socket.onmessage = this.messageReceived
- }
-
- this.subscriptions = {};
- this.subscribe = function(id, callback)
- {
- if (channel.subscriptions[id]) {
- channel.subscriptions[id].push(callback);
- } else {
- channel.subscriptions[id] = [callback];
- }
- };
-
- this.execCallbacks = {};
- this.execId = 0;
- this.exec = function(data, callback)
- {
- if (!callback) {
- // if no callback is given, send directly
- channel.send({data: data});
- return;
- }
- if (channel.execId === Number.MAX_VALUE) {
- // wrap
- channel.execId = Number.MIN_VALUE;
- }
- var id = channel.execId++;
- channel.execCallbacks[id] = callback;
- channel.send({"id": id, "data": data});
- };
-
- this.objects = {};
-
- this.initMetaObjectPublisher = function(doneCallback)
- {
- // prevent multiple initialization which might happen with multiple webchannel clients.
- var initialized = false;
-
- channel.subscribe(
- QWebChannelMessageTypes.signal,
- function(payload) {
- var object = channel.objects[payload.object];
- if (object) {
- object.signalEmitted(payload.signal, payload.args);
- } else {
- console.warn("Unhandled signal: " + payload.object + "::" + payload.signal);
- }
- }
- );
-
- channel.subscribe(
- QWebChannelMessageTypes.propertyUpdate,
- function(payload) {
- for (var i in payload) {
- var data = payload[i];
- var object = channel.objects[data.object];
- if (object) {
- object.propertyUpdate(data.signals, data.properties);
- } else {
- console.warn("Unhandled property update: " + data.object + "::" + data.signal);
- }
- }
- setTimeout(function() { channel.exec({type: QWebChannelMessageTypes.idle}); }, 0);
- }
- );
-
- channel.subscribe(
- QWebChannelMessageTypes.init,
- function(payload) {
- if (initialized) {
- return;
- }
- initialized = true;
- for (var objectName in payload) {
- var data = payload[objectName];
- var object = new QObject(objectName, data, channel);
- }
- if (doneCallback) {
- doneCallback(channel);
- }
- setTimeout(function() { channel.exec({type: QWebChannelMessageTypes.idle}); }, 0);
- }
- );
-
- channel.debug = function(message)
- {
- channel.send({"data" : {"type" : QWebChannelMessageTypes.debug, "message" : message}});
- };
-
- channel.exec({type: QWebChannelMessageTypes.init});
+ this.socket.onmessage = this.onMessageReceived
}
};