summaryrefslogtreecommitdiff
path: root/src
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
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')
-rw-r--r--src/webchannel/qmetaobjectpublisher.cpp140
-rw-r--r--src/webchannel/qmetaobjectpublisher_p.h33
-rw-r--r--src/webchannel/qqmlwebchannel.h4
-rw-r--r--src/webchannel/qwebchannel.cpp31
-rw-r--r--src/webchannel/qwebchannel.h2
-rw-r--r--src/webchannel/qwebchannel.js218
-rw-r--r--src/webchannel/qwebchannel_p.h2
-rw-r--r--src/webchannel/qwebchannelabstracttransport.h5
8 files changed, 198 insertions, 237 deletions
diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp
index 646398d..d9aa548 100644
--- a/src/webchannel/qmetaobjectpublisher.cpp
+++ b/src/webchannel/qmetaobjectpublisher.cpp
@@ -59,30 +59,11 @@ QT_BEGIN_NAMESPACE
namespace {
-// NOTE: keep in sync with corresponding maps in qwebchannel.js and WebChannelTest.qml
-enum Type {
- TypeInvalid = 0,
-
- TYPES_FIRST_VALUE = 1,
-
- TypeSignal = 1,
- TypePropertyUpdate = 2,
- TypeInit = 3,
- TypeIdle = 4,
- TypeDebug = 5,
- TypeInvokeMethod = 6,
- TypeConnectToSignal = 7,
- TypeDisconnectFromSignal = 8,
- TypeSetProperty = 9,
-
- TYPES_LAST_VALUE = 9
-};
-
-Type toType(const QJsonValue &value)
+MessageType toType(const QJsonValue &value)
{
int i = value.toInt(-1);
if (i >= TYPES_FIRST_VALUE && i <= TYPES_LAST_VALUE) {
- return static_cast<Type>(i);
+ return static_cast<MessageType>(i);
} else {
return TypeInvalid;
}
@@ -99,13 +80,11 @@ const QString KEY_OBJECT = QStringLiteral("object");
const QString KEY_DESTROYED = QStringLiteral("destroyed");
const QString KEY_SIGNAL = QStringLiteral("signal");
const QString KEY_TYPE = QStringLiteral("type");
-const QString KEY_MESSAGE = QStringLiteral("message");
const QString KEY_METHOD = QStringLiteral("method");
const QString KEY_ARGS = QStringLiteral("args");
const QString KEY_PROPERTY = QStringLiteral("property");
const QString KEY_VALUE = QStringLiteral("value");
-
QString objectId(const QObject *object)
{
return QString::number(quintptr(object), 16);
@@ -261,7 +240,10 @@ void QMetaObjectPublisher::initializeClients()
objectInfos[it.key()] = info;
}
}
- webChannel->sendMessage(TypeInit, objectInfos);
+ QJsonObject message;
+ message[KEY_TYPE] = TypeInit;
+ message[KEY_DATA] = objectInfos;
+ broadcastMessage(message);
propertyUpdatesInitialized = true;
pendingInit = false;
}
@@ -334,31 +316,34 @@ void QMetaObjectPublisher::sendPendingPropertyUpdates()
}
pendingPropertyUpdates.clear();
- webChannel->sendMessage(TypePropertyUpdate, data);
+ QJsonObject message;
+ message[KEY_TYPE] = TypePropertyUpdate;
+ message[KEY_DATA] = data;
+ broadcastMessage(message);
setClientIsIdle(false);
}
-QByteArray QMetaObjectPublisher::invokeMethod(QObject *const object, const int methodIndex,
- const QJsonArray &args, const QJsonValue &id)
+QJsonValue QMetaObjectPublisher::invokeMethod(QObject *const object, const int methodIndex,
+ const QJsonArray &args)
{
const QMetaMethod &method = object->metaObject()->method(methodIndex);
if (method.name() == QByteArrayLiteral("deleteLater")) {
// invoke `deleteLater` on wrapped QObject indirectly
deleteWrappedObject(object);
- return QByteArray();
+ return QJsonValue();
} else if (!method.isValid()) {
qWarning() << "Cannot invoke unknown method of index" << methodIndex << "on object" << object << '.';
- return QByteArray();
+ return QJsonValue();
} else if (method.access() != QMetaMethod::Public) {
qWarning() << "Cannot invoke non-public method" << method.name() << "on object" << object << '.';
- return QByteArray();
+ return QJsonValue();
} else if (method.methodType() != QMetaMethod::Method && method.methodType() != QMetaMethod::Slot) {
qWarning() << "Cannot invoke non-public method" << method.name() << "on object" << object << '.';
- return QByteArray();
+ return QJsonValue();
} else if (args.size() > 10) {
qWarning() << "Cannot invoke method" << method.name() << "on object" << object << "with more than 10 arguments, as that is not supported by QMetaMethod::invoke.";
- return QByteArray();
+ return QJsonValue();
} else if (args.size() > method.parameterCount()) {
qWarning() << "Ignoring additional arguments while invoking method" << method.name() << "on object" << object << ':'
<< args.size() << "arguments given, but method only takes" << method.parameterCount() << '.';
@@ -389,8 +374,7 @@ QByteArray QMetaObjectPublisher::invokeMethod(QObject *const object, const int m
arguments[0], arguments[1], arguments[2], arguments[3], arguments[4],
arguments[5], arguments[6], arguments[7], arguments[8], arguments[9]);
- // and send the return value to the client
- return generateJSONMessage(id, wrapResult(returnValue), true);
+ return wrapResult(returnValue);
}
void QMetaObjectPublisher::signalEmitted(const QObject *object, const int signalIndex, const QVariantList &arguments)
@@ -399,11 +383,11 @@ void QMetaObjectPublisher::signalEmitted(const QObject *object, const int signal
return;
}
if (!signalToPropertyMap.value(object).contains(signalIndex)) {
- QJsonObject data;
+ QJsonObject message;
const QString &objectName = registeredObjectIds.value(object);
Q_ASSERT(!objectName.isEmpty());
- data[KEY_OBJECT] = objectName;
- data[KEY_SIGNAL] = signalIndex;
+ message[KEY_OBJECT] = objectName;
+ message[KEY_SIGNAL] = signalIndex;
if (!arguments.isEmpty()) {
// TODO: wrap (new) objects on the fly
QJsonArray args;
@@ -419,9 +403,10 @@ void QMetaObjectPublisher::signalEmitted(const QObject *object, const int signal
#else
args = QJsonArray::fromVariantList(arguments);
#endif
- data[KEY_ARGS] = args;
+ message[KEY_ARGS] = args;
}
- webChannel->sendMessage(TypeSignal, data);
+ message[KEY_TYPE] = TypeSignal;
+ broadcastMessage(message);
if (signalIndex == s_destroyedSignalIndex) {
objectDestroyed(object);
@@ -486,78 +471,71 @@ void QMetaObjectPublisher::deleteWrappedObject(QObject *object) const
object->deleteLater();
}
-QByteArray QMetaObjectPublisher::handleRequest(const QJsonObject &message)
+void QMetaObjectPublisher::broadcastMessage(const QJsonObject &message) const
{
- if (!message.contains(KEY_DATA)) {
- return QByteArray();
+ if (webChannel->d_func()->transports.isEmpty()) {
+ qWarning("QWebChannel is not connected to any transports, cannot send messages.");
+ return;
+ }
+
+ foreach (QWebChannelAbstractTransport *transport, webChannel->d_func()->transports) {
+ transport->sendMessage(message);
}
+}
- const QJsonObject &payload = message.value(KEY_DATA).toObject();
- if (!payload.contains(KEY_TYPE)) {
- return QByteArray();
+void QMetaObjectPublisher::handleMessage(const QJsonObject &message, QWebChannelAbstractTransport *transport)
+{
+ if (!message.contains(KEY_TYPE)) {
+ qWarning("JSON message object is missing the type property: %s", QJsonDocument(message).toJson().constData());
+ return;
}
- const Type type = toType(payload.value(KEY_TYPE));
+ const MessageType type = toType(message.value(KEY_TYPE));
if (type == TypeIdle) {
setClientIsIdle(true);
- return QByteArray();
} else if (type == TypeInit) {
if (!blockUpdates) {
initializeClients();
} else {
pendingInit = true;
}
- return QByteArray();
} else if (type == TypeDebug) {
static QTextStream out(stdout);
- out << "DEBUG: " << payload.value(KEY_MESSAGE).toString() << endl;
- return QByteArray();
- } else if (payload.contains(KEY_OBJECT)) {
- const QString &objectName = payload.value(KEY_OBJECT).toString();
+ out << "DEBUG: " << message.value(KEY_DATA).toString() << endl;
+ } else if (message.contains(KEY_OBJECT)) {
+ const QString &objectName = message.value(KEY_OBJECT).toString();
QObject *object = registeredObjects.value(objectName);
if (!object) {
qWarning() << "Unknown object encountered" << objectName;
- return QByteArray();
+ return;
}
if (type == TypeInvokeMethod) {
- return invokeMethod(object, payload.value(KEY_METHOD).toInt(-1), payload.value(KEY_ARGS).toArray(), message.value(KEY_ID));
+ if (!message.contains(KEY_ID)) {
+ qWarning("JSON message object is missing the id property: %s",
+ QJsonDocument(message).toJson().constData());
+ return;
+ }
+ QJsonObject response;
+ response[KEY_TYPE] = TypeResponse;
+ response[KEY_ID] = message.value(KEY_ID);
+ response[KEY_DATA] = invokeMethod(object, message.value(KEY_METHOD).toInt(-1), message.value(KEY_ARGS).toArray());
+ transport->sendMessage(response);
} else if (type == TypeConnectToSignal) {
- signalHandler.connectTo(object, payload.value(KEY_SIGNAL).toInt(-1));
- return QByteArray();
+ signalHandler.connectTo(object, message.value(KEY_SIGNAL).toInt(-1));
} else if (type == TypeDisconnectFromSignal) {
- signalHandler.disconnectFrom(object, payload.value(KEY_SIGNAL).toInt(-1));
- return QByteArray();
+ signalHandler.disconnectFrom(object, message.value(KEY_SIGNAL).toInt(-1));
} else if (type == TypeSetProperty) {
- const int propertyIdx = payload.value(KEY_PROPERTY).toInt(-1);
+ const int propertyIdx = message.value(KEY_PROPERTY).toInt(-1);
QMetaProperty property = object->metaObject()->property(propertyIdx);
if (!property.isValid()) {
- qWarning() << "Cannot set unknown property" << payload.value(KEY_PROPERTY) << "of object" << objectName;
- return QByteArray();
- } else if (!object->metaObject()->property(propertyIdx).write(object, payload.value(KEY_VALUE).toVariant())) {
- qWarning() << "Could not write value " << payload.value(KEY_VALUE)
+ qWarning() << "Cannot set unknown property" << message.value(KEY_PROPERTY) << "of object" << objectName;
+ } else if (!object->metaObject()->property(propertyIdx).write(object, message.value(KEY_VALUE).toVariant())) {
+ qWarning() << "Could not write value " << message.value(KEY_VALUE)
<< "to property" << property.name() << "of object" << objectName;
- return QByteArray();
}
- return QByteArray();
}
}
- return QByteArray();
-}
-
-void QMetaObjectPublisher::handleMessage(const QString &message)
-{
- QWebChannelAbstractTransport *transport = qobject_cast<QWebChannelAbstractTransport*>(sender());
- Q_ASSERT(transport);
-
- const QJsonDocument doc = QJsonDocument::fromJson(message.toUtf8());
- if (!doc.isObject()) {
- return;
- }
- const QByteArray &response = handleRequest(doc.object());
- if (!response.isEmpty()) {
- transport->sendTextMessage(QString::fromUtf8(response));
- }
}
void QMetaObjectPublisher::setBlockUpdates(bool block)
diff --git a/src/webchannel/qmetaobjectpublisher_p.h b/src/webchannel/qmetaobjectpublisher_p.h
index 4da0c26..82afe57 100644
--- a/src/webchannel/qmetaobjectpublisher_p.h
+++ b/src/webchannel/qmetaobjectpublisher_p.h
@@ -54,7 +54,28 @@
QT_BEGIN_NAMESPACE
+// NOTE: keep in sync with corresponding maps in qwebchannel.js and WebChannelTest.qml
+enum MessageType {
+ TypeInvalid = 0,
+
+ TYPES_FIRST_VALUE = 1,
+
+ TypeSignal = 1,
+ TypePropertyUpdate = 2,
+ TypeInit = 3,
+ TypeIdle = 4,
+ TypeDebug = 5,
+ TypeInvokeMethod = 6,
+ TypeConnectToSignal = 7,
+ TypeDisconnectFromSignal = 8,
+ TypeSetProperty = 9,
+ TypeResponse = 10,
+
+ TYPES_LAST_VALUE = 10
+};
+
class QWebChannel;
+class QWebChannelAbstractTransport;
class Q_WEBCHANNEL_EXPORT QMetaObjectPublisher : public QObject
{
Q_OBJECT
@@ -75,11 +96,9 @@ public:
void registerObject(const QString &id, QObject *object);
/**
- * Handle the given WebChannel client request and potentially give a response.
- *
- * @return true if the request was handled, false otherwise.
+ * Send the given message to all known transports.
*/
- QByteArray handleRequest(const QJsonObject &message);
+ void broadcastMessage(const QJsonObject &message) const;
/**
* Serialize the QMetaObject of @p object and return it in JSON form.
@@ -125,7 +144,7 @@ public:
* The return value of the method invocation is then serialized and a response message
* is returned.
*/
- QByteArray invokeMethod(QObject *const object, const int methodIndex, const QJsonArray &args, const QJsonValue &id);
+ QJsonValue invokeMethod(QObject *const object, const int methodIndex, const QJsonArray &args);
/**
* Callback of the signalHandler which forwards the signal invocation to the webchannel clients.
@@ -164,9 +183,9 @@ Q_SIGNALS:
public Q_SLOTS:
/**
- * Parse the message as JSON and if it succeeds, call handleRequest with the obtained JSON object.
+ * Handle the @p message and if needed send a response to @p transport.
*/
- void handleMessage(const QString &message);
+ void handleMessage(const QJsonObject &message, QWebChannelAbstractTransport *transport);
protected:
void timerEvent(QTimerEvent *) Q_DECL_OVERRIDE;
diff --git a/src/webchannel/qqmlwebchannel.h b/src/webchannel/qqmlwebchannel.h
index 3bbd2a0..96ffdd3 100644
--- a/src/webchannel/qqmlwebchannel.h
+++ b/src/webchannel/qqmlwebchannel.h
@@ -89,9 +89,9 @@ private:
static void transports_clear(QQmlListProperty<QObject> *prop);
};
+QT_END_NAMESPACE
+
QML_DECLARE_TYPE( QQmlWebChannel )
QML_DECLARE_TYPEINFO( QQmlWebChannel, QML_HAS_ATTACHED_PROPERTIES )
-QT_END_NAMESPACE
-
#endif // QQMLWEBCHANNEL_H
diff --git a/src/webchannel/qwebchannel.cpp b/src/webchannel/qwebchannel.cpp
index d0b968e..3aebb14 100644
--- a/src/webchannel/qwebchannel.cpp
+++ b/src/webchannel/qwebchannel.cpp
@@ -50,20 +50,6 @@
QT_BEGIN_NAMESPACE
-QByteArray generateJSONMessage(const QJsonValue &id, const QJsonValue &data, bool response)
-{
- QJsonObject obj;
- if (response) {
- obj[QStringLiteral("response")] = true;
- }
- obj[QStringLiteral("id")] = id;
- if (!data.isNull()) {
- obj[QStringLiteral("data")] = data;
- }
- QJsonDocument doc(obj);
- return doc.toJson(QJsonDocument::Compact);
-}
-
void QWebChannelPrivate::_q_transportDestroyed(QObject *object)
{
const int idx = transports.indexOf(static_cast<QWebChannelAbstractTransport*>(object));
@@ -144,7 +130,7 @@ void QWebChannel::connectTo(QWebChannelAbstractTransport *transport)
Q_ASSERT(transport);
if (!d->transports.contains(transport)) {
d->transports << transport;
- connect(transport, &QWebChannelAbstractTransport::textMessageReceived,
+ connect(transport, &QWebChannelAbstractTransport::messageReceived,
d->publisher, &QMetaObjectPublisher::handleMessage,
Qt::UniqueConnection);
connect(transport, SIGNAL(destroyed(QObject*)),
@@ -162,21 +148,6 @@ void QWebChannel::disconnectFrom(QWebChannelAbstractTransport *transport)
}
}
-void QWebChannel::sendMessage(const QJsonValue &id, const QJsonValue &data) const
-{
- Q_D(const QWebChannel);
- if (d->transports.isEmpty()) {
- qWarning("QWebChannel is not connected to any transports, cannot send messages.");
- return;
- }
-
- const QByteArray &message = generateJSONMessage(id, data, false);
- const QString &messageText = QString::fromUtf8(message);
- foreach (QWebChannelAbstractTransport *transport, d->transports) {
- transport->sendTextMessage(messageText);
- }
-}
-
QT_END_NAMESPACE
#include "moc_qwebchannel.cpp"
diff --git a/src/webchannel/qwebchannel.h b/src/webchannel/qwebchannel.h
index a65a4ee..46d77a3 100644
--- a/src/webchannel/qwebchannel.h
+++ b/src/webchannel/qwebchannel.h
@@ -97,8 +97,6 @@ public Q_SLOTS:
void connectTo(QWebChannelAbstractTransport *transport);
void disconnectFrom(QWebChannelAbstractTransport *transport);
- void sendMessage(const QJsonValue &id, const QJsonValue &data = QJsonValue()) const;
-
private:
Q_DECLARE_PRIVATE(QWebChannel)
QWebChannel(QWebChannelPrivate &dd, QObject *parent = 0);
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
}
};
diff --git a/src/webchannel/qwebchannel_p.h b/src/webchannel/qwebchannel_p.h
index 62b2cd5..add55d1 100644
--- a/src/webchannel/qwebchannel_p.h
+++ b/src/webchannel/qwebchannel_p.h
@@ -53,8 +53,6 @@ class QJsonValue;
class QWebChannelAbstractTransport;
class QMetaObjectPublisher;
-Q_WEBCHANNEL_EXPORT QByteArray generateJSONMessage(const QJsonValue &id, const QJsonValue &data, bool response);
-
class Q_WEBCHANNEL_EXPORT QWebChannelPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QWebChannel)
diff --git a/src/webchannel/qwebchannelabstracttransport.h b/src/webchannel/qwebchannelabstracttransport.h
index 0062fab..a13851c 100644
--- a/src/webchannel/qwebchannelabstracttransport.h
+++ b/src/webchannel/qwebchannelabstracttransport.h
@@ -47,6 +47,7 @@
QT_BEGIN_NAMESPACE
+class QJsonObject;
class Q_WEBCHANNEL_EXPORT QWebChannelAbstractTransport : public QObject
{
Q_OBJECT
@@ -58,13 +59,13 @@ public Q_SLOTS:
/**
* Send a text @p message to the remote client.
*/
- virtual void sendTextMessage(const QString &message) = 0;
+ virtual void sendMessage(const QJsonObject &message) = 0;
Q_SIGNALS:
/**
* Emitted when a new text message was received from the remote client.
*/
- void textMessageReceived(const QString &message);
+ void messageReceived(const QJsonObject &message, QWebChannelAbstractTransport *transport);
};
QT_END_NAMESPACE