From 987f147ed4209394f6b65c3c717fee811c408c83 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 9 Feb 2017 20:39:55 -0800 Subject: [PATCH 1/4] implement support for binary data over messages --- .../src/messages/MessagesMixer.cpp | 7 ++- libraries/networking/src/MessagesClient.cpp | 60 +++++++++++++++++-- libraries/networking/src/MessagesClient.h | 9 ++- .../networking/src/udt/PacketHeaders.cpp | 2 + libraries/networking/src/udt/PacketHeaders.h | 4 ++ 5 files changed, 74 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/messages/MessagesMixer.cpp b/assignment-client/src/messages/MessagesMixer.cpp index 7622c78f35..4bf708cf34 100644 --- a/assignment-client/src/messages/MessagesMixer.cpp +++ b/assignment-client/src/messages/MessagesMixer.cpp @@ -37,8 +37,10 @@ void MessagesMixer::nodeKilled(SharedNodePointer killedNode) { void MessagesMixer::handleMessages(QSharedPointer receivedMessage, SharedNodePointer senderNode) { QString channel, message; + QByteArray data; QUuid senderID; - MessagesClient::decodeMessagesPacket(receivedMessage, channel, message, senderID); + bool isText; + MessagesClient::decodeMessagesPacket(receivedMessage, channel, isText, message, data, senderID); auto nodeList = DependencyManager::get(); @@ -47,7 +49,8 @@ void MessagesMixer::handleMessages(QSharedPointer receivedMessa return node->getActiveSocket() && _channelSubscribers[channel].contains(node->getUUID()); }, [&](const SharedNodePointer& node) { - auto packetList = MessagesClient::encodeMessagesPacket(channel, message, senderID); + auto packetList = isText ? MessagesClient::encodeMessagesPacket(channel, message, senderID) : + MessagesClient::encodeMessagesDataPacket(channel, data, senderID); nodeList->sendPacketList(std::move(packetList), *node); }); } diff --git a/libraries/networking/src/MessagesClient.cpp b/libraries/networking/src/MessagesClient.cpp index d8c63c4294..d7b2dc5e97 100644 --- a/libraries/networking/src/MessagesClient.cpp +++ b/libraries/networking/src/MessagesClient.cpp @@ -36,16 +36,23 @@ void MessagesClient::init() { } } -void MessagesClient::decodeMessagesPacket(QSharedPointer receivedMessage, QString& channel, QString& message, QUuid& senderID) { +void MessagesClient::decodeMessagesPacket(QSharedPointer receivedMessage, QString& channel, + bool& isText, QString& message, QByteArray& data, QUuid& senderID) { quint16 channelLength; receivedMessage->readPrimitive(&channelLength); auto channelData = receivedMessage->read(channelLength); channel = QString::fromUtf8(channelData); + receivedMessage->readPrimitive(&isText); + quint16 messageLength; receivedMessage->readPrimitive(&messageLength); auto messageData = receivedMessage->read(messageLength); - message = QString::fromUtf8(messageData); + if (isText) { + message = QString::fromUtf8(messageData); + } else { + data = messageData; + } QByteArray bytesSenderID = receivedMessage->read(NUM_BYTES_RFC4122_UUID); if (bytesSenderID.length() == NUM_BYTES_RFC4122_UUID) { @@ -64,6 +71,9 @@ std::unique_ptr MessagesClient::encodeMessagesPacket(QString chann packetList->writePrimitive(channelLength); packetList->write(channelUtf8); + bool isTextMessage = true; + packetList->writePrimitive(isTextMessage); + auto messageUtf8 = message.toUtf8(); quint16 messageLength = messageUtf8.length(); packetList->writePrimitive(messageLength); @@ -74,12 +84,38 @@ std::unique_ptr MessagesClient::encodeMessagesPacket(QString chann return packetList; } +std::unique_ptr MessagesClient::encodeMessagesDataPacket(QString channel, QByteArray data, QUuid senderID) { + auto packetList = NLPacketList::create(PacketType::MessagesData, QByteArray(), true, true); + + auto channelUtf8 = channel.toUtf8(); + quint16 channelLength = channelUtf8.length(); + packetList->writePrimitive(channelLength); + packetList->write(channelUtf8); + + bool isTextMessage = false; + packetList->writePrimitive(isTextMessage); + + quint16 dataLength = data.length(); + packetList->writePrimitive(dataLength); + packetList->write(data); + + packetList->write(senderID.toRfc4122()); + + return packetList; +} + void MessagesClient::handleMessagesPacket(QSharedPointer receivedMessage, SharedNodePointer senderNode) { QString channel, message; + QByteArray data; + bool isText { false }; QUuid senderID; - decodeMessagesPacket(receivedMessage, channel, message, senderID); - emit messageReceived(channel, message, senderID, false); + decodeMessagesPacket(receivedMessage, channel, isText, message, data, senderID); + if (isText) { + emit messageReceived(channel, message, senderID, false); + } else { + emit dataReceived(channel, data, senderID, false); + } } void MessagesClient::sendMessage(QString channel, QString message, bool localOnly) { @@ -98,6 +134,22 @@ void MessagesClient::sendMessage(QString channel, QString message, bool localOnl } } +void MessagesClient::sendData(QString channel, QByteArray data, bool localOnly) { + auto nodeList = DependencyManager::get(); + if (localOnly) { + QUuid senderID = nodeList->getSessionUUID(); + emit dataReceived(channel, data, senderID, true); + } else { + SharedNodePointer messagesMixer = nodeList->soloNodeOfType(NodeType::MessagesMixer); + + if (messagesMixer) { + QUuid senderID = nodeList->getSessionUUID(); + auto packetList = encodeMessagesDataPacket(channel, data, senderID); + nodeList->sendPacketList(std::move(packetList), *messagesMixer); + } + } +} + void MessagesClient::sendLocalMessage(QString channel, QString message) { sendMessage(channel, message, true); } diff --git a/libraries/networking/src/MessagesClient.h b/libraries/networking/src/MessagesClient.h index b624acccb7..51b468d646 100644 --- a/libraries/networking/src/MessagesClient.h +++ b/libraries/networking/src/MessagesClient.h @@ -14,6 +14,7 @@ #define hifi_MessagesClient_h #include +#include #include @@ -31,15 +32,19 @@ public: Q_INVOKABLE void sendMessage(QString channel, QString message, bool localOnly = false); Q_INVOKABLE void sendLocalMessage(QString channel, QString message); + Q_INVOKABLE void sendData(QString channel, QByteArray data, bool localOnly = false); Q_INVOKABLE void subscribe(QString channel); Q_INVOKABLE void unsubscribe(QString channel); - static void decodeMessagesPacket(QSharedPointer receivedMessage, QString& channel, QString& message, QUuid& senderID); - static std::unique_ptr encodeMessagesPacket(QString channel, QString message, QUuid senderID); + static void decodeMessagesPacket(QSharedPointer receivedMessage, QString& channel, + bool& isText, QString& message, QByteArray& data, QUuid& senderID); + static std::unique_ptr encodeMessagesPacket(QString channel, QString message, QUuid senderID); + static std::unique_ptr encodeMessagesDataPacket(QString channel, QByteArray data, QUuid senderID); signals: void messageReceived(QString channel, QString message, QUuid senderUUID, bool localOnly); + void dataReceived(QString channel, QByteArray data, QUuid senderUUID, bool localOnly); private slots: void handleMessagesPacket(QSharedPointer receivedMessage, SharedNodePointer senderNode); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index e2dc8d73e6..b13b21ba3b 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -57,6 +57,8 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::BulkAvatarData: case PacketType::KillAvatar: return static_cast(AvatarMixerPacketVersion::VariableAvatarData); + case PacketType::MessagesData: + return static_cast(MessageDataVersion::TextOrBinaryData); case PacketType::ICEServerHeartbeat: return 18; // ICE Server Heartbeat signing case PacketType::AssetGetInfo: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 88b5ec19ad..8c356e0078 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -262,4 +262,8 @@ enum class AudioVersion : PacketVersion { HighDynamicRangeVolume, }; +enum class MessageDataVersion : PacketVersion { + TextOrBinaryData = 18 +}; + #endif // hifi_PacketHeaders_h From 7fba30f0dd66800f3964616fea73545367494e75 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 9 Feb 2017 22:21:51 -0800 Subject: [PATCH 2/4] add a test script to show binary message passing --- scripts/developer/tests/messagesTests.js | 38 ++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 scripts/developer/tests/messagesTests.js diff --git a/scripts/developer/tests/messagesTests.js b/scripts/developer/tests/messagesTests.js new file mode 100644 index 0000000000..27ac33bc9d --- /dev/null +++ b/scripts/developer/tests/messagesTests.js @@ -0,0 +1,38 @@ + +var channelName = "com.highfidelity.example.dataMessages"; + +Messages.subscribe(channelName); + +//messageReceived(QString channel, QString message, QUuid senderUUID, bool localOnly); +Messages.messageReceived.connect(function(channel, message, sender, local) { + print("message recieved on ", channel, " message:", message, " from:", sender, " local:", local); +}); + +Messages.dataReceived.connect(function(channel, data, sender, local) { + var int8data = new Int8Array(data); + var dataAsString; + for (var i = 0; i < int8data.length; i++) { + if (i > 0) { + dataAsString += ", "; + } + dataAsString += int8data[i]; + } + print("data recieved on ", channel, " from:", sender, " local:", local, "length of data:", int8data.length, " data:", dataAsString); +}); + +var counter = 0; +Script.update.connect(function(){ + counter++; + if (counter == 100) { + Messages.sendMessage(channelName, "foo"); + } else if (counter == 200) { + var data = new Int8Array([0,1,10,2,20,3,30]); + print("about to call sendData() data.length:", data.length); + Messages.sendData(channelName, data.buffer); + counter = 0; + } +}); + +Script.scriptEnding.connect(function(){ + Messages.unsubscribe(channelName); +}); From f6d4dbb7a41c2e285dedb0c407dad5f966abd13e Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 10 Feb 2017 09:18:04 -0800 Subject: [PATCH 3/4] some debugging --- libraries/networking/src/MessagesClient.cpp | 23 +++++++++++++++++++++ libraries/script-engine/src/TypedArrays.cpp | 2 ++ scripts/developer/tests/messagesTests.js | 5 ++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/MessagesClient.cpp b/libraries/networking/src/MessagesClient.cpp index d7b2dc5e97..09d2e94380 100644 --- a/libraries/networking/src/MessagesClient.cpp +++ b/libraries/networking/src/MessagesClient.cpp @@ -114,6 +114,18 @@ void MessagesClient::handleMessagesPacket(QSharedPointer receiv if (isText) { emit messageReceived(channel, message, senderID, false); } else { + + // FIXME -- this is some super janky temporary debugging code, just to prove the data is going over the wire correctly + QString debugData; + for (int i = 0; i < data.size(); i++) { + auto byte = data[i]; + if (i > 0) { + debugData += ", "; + } + debugData += QString::number(byte); + } + qDebug() << __FUNCTION__ << "data:" << debugData; + emit dataReceived(channel, data, senderID, false); } } @@ -135,6 +147,17 @@ void MessagesClient::sendMessage(QString channel, QString message, bool localOnl } void MessagesClient::sendData(QString channel, QByteArray data, bool localOnly) { + // FIXME -- this is some super janky temporary debugging code, just to prove the data is going over the wire correctly + QString debugData; + for(int i = 0; i < data.size(); i++) { + auto byte = data[i]; + if (i > 0) { + debugData += ", "; + } + debugData += QString::number(byte); + } + qDebug() << __FUNCTION__ << "data:" << debugData; + auto nodeList = DependencyManager::get(); if (localOnly) { QUuid senderID = nodeList->getSessionUUID(); diff --git a/libraries/script-engine/src/TypedArrays.cpp b/libraries/script-engine/src/TypedArrays.cpp index 4d5181ff33..661f978426 100644 --- a/libraries/script-engine/src/TypedArrays.cpp +++ b/libraries/script-engine/src/TypedArrays.cpp @@ -62,6 +62,8 @@ QScriptValue TypedArray::newInstance(QScriptValue array) { } QScriptValue TypedArray::newInstance(QScriptValue buffer, quint32 byteOffset, quint32 length) { + qDebug() << __FUNCTION__ << "buffer:" << buffer.toVariant() << "byteOffset:" << byteOffset << "length:" << length; + QScriptValue data = engine()->newObject(); data.setProperty(_bufferName, buffer); data.setProperty(_byteOffsetName, byteOffset); diff --git a/scripts/developer/tests/messagesTests.js b/scripts/developer/tests/messagesTests.js index 27ac33bc9d..7b390f5caf 100644 --- a/scripts/developer/tests/messagesTests.js +++ b/scripts/developer/tests/messagesTests.js @@ -26,7 +26,10 @@ Script.update.connect(function(){ if (counter == 100) { Messages.sendMessage(channelName, "foo"); } else if (counter == 200) { - var data = new Int8Array([0,1,10,2,20,3,30]); + var data = new Int8Array(2); + //[0,1,10,2,20,3,30]); + data[0]=1; + data[1]=10; print("about to call sendData() data.length:", data.length); Messages.sendData(channelName, data.buffer); counter = 0; From 765500ebce792dbacfbc57014811f9a0128d08bd Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 10 Feb 2017 10:09:03 -0800 Subject: [PATCH 4/4] remove debug and fix bug in test script --- libraries/networking/src/MessagesClient.cpp | 23 --------------------- libraries/script-engine/src/TypedArrays.cpp | 2 -- scripts/developer/tests/messagesTests.js | 7 ++----- 3 files changed, 2 insertions(+), 30 deletions(-) diff --git a/libraries/networking/src/MessagesClient.cpp b/libraries/networking/src/MessagesClient.cpp index 09d2e94380..d7b2dc5e97 100644 --- a/libraries/networking/src/MessagesClient.cpp +++ b/libraries/networking/src/MessagesClient.cpp @@ -114,18 +114,6 @@ void MessagesClient::handleMessagesPacket(QSharedPointer receiv if (isText) { emit messageReceived(channel, message, senderID, false); } else { - - // FIXME -- this is some super janky temporary debugging code, just to prove the data is going over the wire correctly - QString debugData; - for (int i = 0; i < data.size(); i++) { - auto byte = data[i]; - if (i > 0) { - debugData += ", "; - } - debugData += QString::number(byte); - } - qDebug() << __FUNCTION__ << "data:" << debugData; - emit dataReceived(channel, data, senderID, false); } } @@ -147,17 +135,6 @@ void MessagesClient::sendMessage(QString channel, QString message, bool localOnl } void MessagesClient::sendData(QString channel, QByteArray data, bool localOnly) { - // FIXME -- this is some super janky temporary debugging code, just to prove the data is going over the wire correctly - QString debugData; - for(int i = 0; i < data.size(); i++) { - auto byte = data[i]; - if (i > 0) { - debugData += ", "; - } - debugData += QString::number(byte); - } - qDebug() << __FUNCTION__ << "data:" << debugData; - auto nodeList = DependencyManager::get(); if (localOnly) { QUuid senderID = nodeList->getSessionUUID(); diff --git a/libraries/script-engine/src/TypedArrays.cpp b/libraries/script-engine/src/TypedArrays.cpp index 661f978426..4d5181ff33 100644 --- a/libraries/script-engine/src/TypedArrays.cpp +++ b/libraries/script-engine/src/TypedArrays.cpp @@ -62,8 +62,6 @@ QScriptValue TypedArray::newInstance(QScriptValue array) { } QScriptValue TypedArray::newInstance(QScriptValue buffer, quint32 byteOffset, quint32 length) { - qDebug() << __FUNCTION__ << "buffer:" << buffer.toVariant() << "byteOffset:" << byteOffset << "length:" << length; - QScriptValue data = engine()->newObject(); data.setProperty(_bufferName, buffer); data.setProperty(_byteOffsetName, byteOffset); diff --git a/scripts/developer/tests/messagesTests.js b/scripts/developer/tests/messagesTests.js index 7b390f5caf..18beafa4cc 100644 --- a/scripts/developer/tests/messagesTests.js +++ b/scripts/developer/tests/messagesTests.js @@ -10,7 +10,7 @@ Messages.messageReceived.connect(function(channel, message, sender, local) { Messages.dataReceived.connect(function(channel, data, sender, local) { var int8data = new Int8Array(data); - var dataAsString; + var dataAsString = ""; for (var i = 0; i < int8data.length; i++) { if (i > 0) { dataAsString += ", "; @@ -26,10 +26,7 @@ Script.update.connect(function(){ if (counter == 100) { Messages.sendMessage(channelName, "foo"); } else if (counter == 200) { - var data = new Int8Array(2); - //[0,1,10,2,20,3,30]); - data[0]=1; - data[1]=10; + var data = new Int8Array([0,1,10,2,20,3,30]); print("about to call sendData() data.length:", data.length); Messages.sendData(channelName, data.buffer); counter = 0;