Commit d1994f08 authored by Qt Forward Merge Bot's avatar Qt Forward Merge Bot
Browse files

Merge remote-tracking branch 'origin/5.12' into dev

Change-Id: I297fa8021bd7520851d139c16b97671d41156919
Showing with 99 additions and 139 deletions
requires(qtHaveModule(network))
load(qt_parts) load(qt_parts)
[
]
...@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 ...@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only. // It is used for QML tooling purposes only.
// //
// This file was auto-generated by: // This file was auto-generated by:
// 'qmlplugindump -nonrelocatable QtWebSockets 1.1' // 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtWebSockets 1.1'
Module { Module {
dependencies: [] dependencies: []
......
...@@ -12,6 +12,6 @@ SOURCES += qmlwebsockets_plugin.cpp \ ...@@ -12,6 +12,6 @@ SOURCES += qmlwebsockets_plugin.cpp \
OTHER_FILES += qmldir OTHER_FILES += qmldir
IMPORT_VERSION = 1.0 IMPORT_VERSION = 1.1
load(qml_plugin) load(qml_plugin)
...@@ -69,6 +69,10 @@ ...@@ -69,6 +69,10 @@
#include "qwebsocketdataprocessor_p.h" #include "qwebsocketdataprocessor_p.h"
#include "qdefaultmaskgenerator_p.h" #include "qdefaultmaskgenerator_p.h"
#ifdef Q_OS_WASM
#include <emscripten/val.h>
#endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QWebSocketHandshakeRequest; class QWebSocketHandshakeRequest;
...@@ -247,6 +251,9 @@ private: ...@@ -247,6 +251,9 @@ private:
QMap<QString, QString> m_headers; QMap<QString, QString> m_headers;
friend class QWebSocketServerPrivate; friend class QWebSocketServerPrivate;
#ifdef Q_OS_WASM
emscripten::val socketContext = emscripten::val::null();
#endif
}; };
QT_END_NAMESPACE QT_END_NAMESPACE
......
...@@ -42,92 +42,104 @@ ...@@ -42,92 +42,104 @@
#include <QtCore/qcoreapplication.h> #include <QtCore/qcoreapplication.h>
#include <emscripten.h> #include <emscripten.h>
#include <emscripten/html5.h>
#include <emscripten/bind.h> #include <emscripten/bind.h>
using namespace emscripten; using namespace emscripten;
QByteArray g_messageArray; static void q_onErrorCallback(val event)
// easiest way to transliterate binary data to js/wasm
val getBinaryMessage()
{ {
return val(typed_memory_view(g_messageArray.size(), val target = event["target"];
reinterpret_cast<const unsigned char *>(g_messageArray.constData())));
}
EMSCRIPTEN_BINDINGS(wasm_module) { QWebSocketPrivate *wsp = reinterpret_cast<QWebSocketPrivate*>(target["data-context"].as<quintptr>());
function("getBinaryMessage", &getBinaryMessage); Q_ASSERT (wsp);
emit wsp->q_func()->error(wsp->error());
} }
static void onOpenCallback(void *data) static void q_onCloseCallback(val event)
{ {
auto handler = reinterpret_cast<QWebSocketPrivate *>(data); val target = event["target"];
Q_ASSERT (handler);
emit handler->q_func()->connected(); QWebSocketPrivate *wsp = reinterpret_cast<QWebSocketPrivate*>(target["data-context"].as<quintptr>());
Q_ASSERT (wsp);
emit wsp->q_func()->disconnected();
} }
static void onCloseCallback(void *data, int message) static void q_onOpenCallback(val event)
{ {
Q_UNUSED(message); val target = event["target"];
auto handler = reinterpret_cast<QWebSocketPrivate *>(data);
Q_ASSERT (handler); QWebSocketPrivate *wsp = reinterpret_cast<QWebSocketPrivate*>(target["data-context"].as<quintptr>());
emit handler->q_func()->disconnected(); Q_ASSERT (wsp);
emit wsp->q_func()->connected();
} }
static void onErrorCallback(void *data, int message) static void q_onIncomingMessageCallback(val event)
{ {
Q_UNUSED(message); val target = event["target"];
auto handler = reinterpret_cast<QWebSocketPrivate *>(data);
Q_ASSERT (handler); if (event["data"].typeOf().as<std::string>() == "string") {
emit handler->q_func()->error(handler->error()); QWebSocketPrivate *wsp = reinterpret_cast<QWebSocketPrivate*>(target["data-context"].as<quintptr>());
Q_ASSERT (wsp);
const QString message = QString::fromStdString(event["data"].as<std::string>());
if (!message.isEmpty())
wsp->q_func()->textMessageReceived(message);
} else {
val reader = val::global("FileReader").new_();
reader.set("onload", val::module_property("QWebSocketPrivate_readBlob"));
reader.set("data-context", target["data-context"]);
reader.call<void>("readAsArrayBuffer", event["data"]);
}
} }
static void onIncomingMessageCallback(void *data, int message, int length, int dataType) static void q_readBlob(val event)
{ {
QWebSocketPrivate *handler = reinterpret_cast<QWebSocketPrivate *>(data); val fileReader = event["target"];
Q_ASSERT (handler);
QWebSocketPrivate *wsp = reinterpret_cast<QWebSocketPrivate*>(fileReader["data-context"].as<quintptr>());
QWebSocket *webSocket = handler->q_func(); Q_ASSERT (wsp);
const char *text = reinterpret_cast<const char *>(message);
// Set up source typed array
switch (dataType) { val result = fileReader["result"]; // ArrayBuffer
case 0: //string val Uint8Array = val::global("Uint8Array");
webSocket->textMessageReceived(QLatin1String(text)); val sourceTypedArray = Uint8Array.new_(result);
break;
case 1: //blob // Allocate and set up destination typed array
case 2: //arraybuffer const size_t size = result["byteLength"].as<size_t>();
webSocket->binaryMessageReceived(QByteArray::fromRawData(text, length)); QByteArray buffer(size, Qt::Uninitialized);
break;
}; val destinationTypedArray = Uint8Array.new_(val::module_property("HEAPU8")["buffer"],
reinterpret_cast<quintptr>(buffer.data()), size);
destinationTypedArray.call<void>("set", sourceTypedArray);
wsp->q_func()->binaryMessageReceived(buffer);
}
EMSCRIPTEN_BINDINGS(wasm_module) {
function("QWebSocketPrivate_onErrorCallback", q_onErrorCallback);
function("QWebSocketPrivate_onCloseCallback", q_onCloseCallback);
function("QWebSocketPrivate_onOpenCallback", q_onOpenCallback);
function("QWebSocketPrivate_onIncomingMessageCallback", q_onIncomingMessageCallback);
function("QWebSocketPrivate_readBlob", q_readBlob);
} }
qint64 QWebSocketPrivate::sendTextMessage(const QString &message) qint64 QWebSocketPrivate::sendTextMessage(const QString &message)
{ {
EM_ASM_ARGS({ socketContext.call<void>("send", message.toStdString());
if (window.qWebSocket === undefined)
console.log("cannot find websocket object");
else
window.qWebSocket.send(Pointer_stringify($0));
}, message.toLocal8Bit().constData());
return message.length(); return message.length();
} }
qint64 QWebSocketPrivate::sendBinaryMessage(const QByteArray &data) qint64 QWebSocketPrivate::sendBinaryMessage(const QByteArray &data)
{ {
g_messageArray = data; socketContext.call<void>("send",
EM_ASM({ val(typed_memory_view(data.size(),
if (window.qWebSocket === undefined) { reinterpret_cast<const unsigned char *>
console.log("cannot find websocket object"); (data.constData()))));
} else {
var array = Module.getBinaryMessage();
window.qWebSocket.binaryType = 'arraybuffer';
window.qWebSocket.send(array);
}
});
g_messageArray.clear();
return data.length(); return data.length();
} }
...@@ -136,19 +148,10 @@ void QWebSocketPrivate::close(QWebSocketProtocol::CloseCode closeCode, QString r ...@@ -136,19 +148,10 @@ void QWebSocketPrivate::close(QWebSocketProtocol::CloseCode closeCode, QString r
Q_Q(QWebSocket); Q_Q(QWebSocket);
m_closeCode = closeCode; m_closeCode = closeCode;
m_closeReason = reason; m_closeReason = reason;
const quint16 closeReason = (quint16)closeCode;
Q_EMIT q->aboutToClose(); Q_EMIT q->aboutToClose();
QCoreApplication::processEvents();
socketContext.call<void>("close", static_cast<quint16>(closeCode),
EM_ASM_ARGS({ reason.toLatin1().toStdString());
if (window.qWebSocket === undefined) {
console.log("cannot find websocket object");
} else {
var reasonMessage = Pointer_stringify($0);
window.qWebSocket.close($1, reasonMessage);
window.qWebSocket = undefined;
}
}, reason.toLatin1().data(), closeReason);
} }
void QWebSocketPrivate::open(const QNetworkRequest &request, bool mask) void QWebSocketPrivate::open(const QNetworkRequest &request, bool mask)
...@@ -162,74 +165,21 @@ void QWebSocketPrivate::open(const QNetworkRequest &request, bool mask) ...@@ -162,74 +165,21 @@ void QWebSocketPrivate::open(const QNetworkRequest &request, bool mask)
return; return;
} }
QByteArray urlbytes = url.toString().toUtf8(); const std::string urlbytes = url.toString().toStdString();
// HTML WebSockets do not support arbitrary request headers, but // HTML WebSockets do not support arbitrary request headers, but
// do support the WebSocket protocol header. This header is // do support the WebSocket protocol header. This header is
// required for some use cases like MQTT. // required for some use cases like MQTT.
QByteArray protocolHeaderValue = request.rawHeader("Sec-WebSocket-Protocol"); const std::string protocolHeaderValue = request.rawHeader("Sec-WebSocket-Protocol").toStdString();
val webSocket = val::global("WebSocket");
EM_ASM_ARGS({
if (window.qWebSocket != undefined) socketContext = !protocolHeaderValue.empty()
return; ? webSocket.new_(urlbytes, protocolHeaderValue)
: webSocket.new_(urlbytes);
var wsUri = Pointer_stringify($0);
var wsProtocol = Pointer_stringify($1); socketContext.set("onerror", val::module_property("QWebSocketPrivate_onErrorCallback"));
var handler = $2; socketContext.set("onclose", val::module_property("QWebSocketPrivate_onCloseCallback"));
var onOpenCb = $3; socketContext.set("onopen", val::module_property("QWebSocketPrivate_onOpenCallback"));
var onCloseCb = $4; socketContext.set("onmessage", val::module_property("QWebSocketPrivate_onIncomingMessageCallback"));
var onErrorCb = $5; socketContext.set("data-context", val(quintptr(reinterpret_cast<void *>(this))));
var onIncomingMessageCb = $6;
window.qWebSocket = wsProtocol.length > 0
? new WebSocket(wsUri, wsProtocol)
: new WebSocket(wsUri);
window.qWebSocket.onopen = function(event) {
Runtime.dynCall('vi', onOpenCb, [handler]);
};
window.qWebSocket.onclose = function(event) {
window.qWebSocket = undefined;
Runtime.dynCall('vii', onCloseCb, [handler, event.code]);
};
window.qWebSocket.onerror = function(event) {
Runtime.dynCall('vii', onErrorCb, [handler, event.error]);
};
window.qWebSocket.onmessage = function(event) {
var outgoingMessage;
var bufferLength = 0;
var dataType;
if (window.qWebSocket.binaryType == 'arraybuffer' && typeof event.data == 'object') {
var byteArray = new Uint8Array(event.data);
bufferLength = byteArray.length;
outgoingMessage = _malloc(byteArray.length);
HEAPU8.set(byteArray, outgoingMessage);
dataType = 2;
} else if (typeof event.data == 'string') {
dataType = 0;
outgoingMessage = allocate(intArrayFromString(event.data), 'i8', ALLOC_NORMAL);
} else if (window.qWebSocket.binaryType == 'blob') {
var byteArray = new Int8Array($0);
outgoingMessage = new Blob(byteArray.buffer);
dataType = 1;
}
Runtime.dynCall('viiii', onIncomingMessageCb, [handler, outgoingMessage, bufferLength, dataType]);
_free(outgoingMessage);
};
}, urlbytes.constData(),
protocolHeaderValue.data(),
this,
reinterpret_cast<void *>(onOpenCallback),
reinterpret_cast<void *>(onCloseCallback),
reinterpret_cast<void *>(onErrorCallback),
reinterpret_cast<void *>(onIncomingMessageCallback));
} }
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment