diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 4ca2439996..b7d02cdb85 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -42,6 +42,7 @@ AssetServer::AssetServer(ReceivedMessage& message) : packetReceiver.registerListener(PacketType::AssetGet, this, "handleAssetGet"); packetReceiver.registerListener(PacketType::AssetGetInfo, this, "handleAssetGetInfo"); packetReceiver.registerListener(PacketType::AssetUpload, this, "handleAssetUpload"); + packetReceiver.registerListener(PacketType::AssetMappingOperation, this, "handleAssetMappingOperation"); } void AssetServer::run() { @@ -161,6 +162,67 @@ void AssetServer::completeSetup() { nodeList->addNodeTypeToInterestSet(NodeType::Agent); } + +void AssetServer::handleAssetMappingOperation(QSharedPointer message, SharedNodePointer senderNode) { + MessageID messageID; + message->readPrimitive(&messageID); + + AssetMappingOperationType operationType; + message->readPrimitive(&operationType); + + auto replyPacket = NLPacketList::create(PacketType::AssetMappingOperationReply, QByteArray(), true, true); + replyPacket->writePrimitive(messageID); + + switch (operationType) { + case AssetMappingOperationType::Get: { + QString assetPath = message->readString(); + + auto it = _fileMapping.find(assetPath); + if (it != _fileMapping.end()) { + auto assetHash = it->second; + qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; + replyPacket->writePrimitive(AssetServerError::NoError); + //replyPacket->write(assetHash.toLatin1().toHex()); + replyPacket->writeString(assetHash.toLatin1()); + } + else { + qDebug() << "Mapping not found for: " << assetPath; + replyPacket->writePrimitive(AssetServerError::AssetNotFound); + } + break; + } + case AssetMappingOperationType::GetAll: { + replyPacket->writePrimitive(AssetServerError::NoError); + auto count = _fileMapping.size(); + replyPacket->writePrimitive(count); + for (auto& kv : _fileMapping) { + replyPacket->writeString(kv.first); + replyPacket->writeString(kv.second); + } + break; + } + case AssetMappingOperationType::Set: { + QString assetPath = message->readString(); + //auto assetHash = message->read(SHA256_HASH_LENGTH); + auto assetHash = message->readString(); + _fileMapping[assetPath] = assetHash; + + replyPacket->writePrimitive(AssetServerError::NoError); + break; + } + case AssetMappingOperationType::Delete: { + QString assetPath = message->readString(); + bool removed = _fileMapping.erase(assetPath) > 0; + + replyPacket->writePrimitive(AssetServerError::NoError); + break; + } + } + + auto nodeList = DependencyManager::get(); + nodeList->sendPacketList(std::move(replyPacket), *senderNode); +} + void AssetServer::handleAssetGetInfo(QSharedPointer message, SharedNodePointer senderNode) { QByteArray assetHash; MessageID messageID; @@ -308,3 +370,9 @@ void AssetServer::sendStatsPacket() { // send off the stats packets ThreadedAssignment::addPacketStatsAndSendStatsPacket(serverStats); } + +void AssetServer::loadMappingFromFile() { +} + +void AssetServer::writeMappingToFile() { +} diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 7d6e26af08..e87c0797c8 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -34,11 +34,18 @@ private slots: void handleAssetGetInfo(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetGet(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetUpload(QSharedPointer packetList, SharedNodePointer senderNode); + void handleAssetMappingOperation(QSharedPointer message, SharedNodePointer senderNode); void sendStatsPacket(); private: + + void loadMappingFromFile(); + void writeMappingToFile(); + static void writeError(NLPacketList* packetList, AssetServerError error); + + AssetMapping _fileMapping; QDir _resourcesDirectory; QThreadPool _taskPool; }; diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 9591828fef..7631ec5292 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -30,6 +30,148 @@ MessageID AssetClient::_currentID = 0; +void MappingRequest::start() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); + return; + } + doStart(); +}; + +GetMappingRequest::GetMappingRequest(AssetPath path) : _path(path) { +}; + +void GetMappingRequest::doStart() { + + auto assetClient = DependencyManager::get(); + + // Check cache + auto it = assetClient->_mappingCache.constFind(_path); + if (it != assetClient->_mappingCache.constEnd()) { + _hash = it.value(); + emit finished(this); + return; + } + + assetClient->getAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { + if (!responseReceived) { + _error = NetworkError; + } else { + switch (error) { + case AssetServerError::NoError: + _error = NoError; + break; + case AssetServerError::AssetNotFound: + _error = NotFound; + break; + default: + _error = UnknownError; + break; + } + } + + if (!_error) { + //_hash = message->read(SHA256_HASH_HEX_LENGTH); + _hash = message->readString(); + assetClient->_mappingCache[_path] = _hash; + } + emit finished(this); + }); +}; + +GetAllMappingsRequest::GetAllMappingsRequest() { +}; + +void GetAllMappingsRequest::doStart() { + auto assetClient = DependencyManager::get(); + assetClient->getAllAssetMappings([this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { + if (!responseReceived) { + _error = NetworkError; + } else { + switch (error) { + case AssetServerError::NoError: + _error = NoError; + break; + default: + _error = UnknownError; + break; + } + } + + + if (!error) { + size_t numberOfMappings; + message->readPrimitive(&numberOfMappings); + assetClient->_mappingCache.clear(); + for (auto i = 0; i < numberOfMappings; ++i) { + auto path = message->readString(); + auto hash = message->readString(); + _mappings[path] = hash; + assetClient->_mappingCache[path] = hash; + } + } + emit finished(this); + }); +}; + +SetMappingRequest::SetMappingRequest(AssetPath path, AssetHash hash) : _path(path), _hash(hash) { +}; + +void SetMappingRequest::doStart() { + auto assetClient = DependencyManager::get(); + assetClient->setAssetMapping(_path, _hash, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { + if (!responseReceived) { + _error = NetworkError; + } else { + switch (error) { + case AssetServerError::NoError: + _error = NoError; + break; + case AssetServerError::PermissionDenied: + _error = PermissionDenied; + break; + default: + _error = UnknownError; + break; + } + } + + if (!error) { + assetClient->_mappingCache[_path] = _hash; + } + emit finished(this); + }); +}; + +DeleteMappingRequest::DeleteMappingRequest(AssetPath path) : _path(path) { +}; + +void DeleteMappingRequest::doStart() { + auto assetClient = DependencyManager::get(); + assetClient->deleteAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { + if (!responseReceived) { + _error = NetworkError; + } else { + switch (error) { + case AssetServerError::NoError: + _error = NoError; + break; + case AssetServerError::PermissionDenied: + _error = PermissionDenied; + break; + default: + _error = UnknownError; + break; + } + } + + if (!error) { + assetClient->_mappingCache.remove(_path); + } + emit finished(this); + }); +}; + AssetClient::AssetClient() { @@ -39,6 +181,7 @@ AssetClient::AssetClient() { auto nodeList = DependencyManager::get(); auto& packetReceiver = nodeList->getPacketReceiver(); + packetReceiver.registerListener(PacketType::AssetMappingOperationReply, this, "handleAssetMappingOperationReply"); packetReceiver.registerListener(PacketType::AssetGetInfoReply, this, "handleAssetGetInfoReply"); packetReceiver.registerListener(PacketType::AssetGetReply, this, "handleAssetGetReply", true); packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply"); @@ -89,6 +232,8 @@ void AssetClient::clearCache() { return; } + _mappingCache.clear(); + if (auto cache = NetworkAccessManager::getInstance().cache()) { qDebug() << "AssetClient::clearCache(): Clearing disk cache."; cache->clear(); @@ -97,6 +242,33 @@ void AssetClient::clearCache() { } } +void AssetClient::handleAssetMappingOperationReply(QSharedPointer message, SharedNodePointer senderNode) { + MessageID messageID; + message->readPrimitive(&messageID); + + AssetServerError error; + message->readPrimitive(&error); + + // Check if we have any pending requests for this node + auto messageMapIt = _pendingMappingRequests.find(senderNode); + if (messageMapIt != _pendingMappingRequests.end()) { + + // Found the node, get the MessageID -> Callback map + auto& messageCallbackMap = messageMapIt->second; + + // Check if we have this pending request + auto requestIt = messageCallbackMap.find(messageID); + if (requestIt != messageCallbackMap.end()) { + auto callback = requestIt->second; + callback(true, error, message); + messageCallbackMap.erase(requestIt); + } + + // Although the messageCallbackMap may now be empty, we won't delete the node until we have disconnected from + // it to avoid constantly creating/deleting the map on subsequent requests. + } +} + bool haveAssetServer() { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); @@ -109,8 +281,23 @@ bool haveAssetServer() { return true; } +GetMappingRequest* AssetClient::createGetMappingRequest(const AssetPath& path) { + return new GetMappingRequest(path); +} -AssetRequest* AssetClient::createRequest(const QString& hash, const QString& extension) { +GetAllMappingsRequest* AssetClient::createGetAllMappingsRequest() { + return new GetAllMappingsRequest(); +} + +DeleteMappingRequest* AssetClient::createDeleteMappingRequest(const AssetPath& path) { + return new DeleteMappingRequest(path); +} + +SetMappingRequest* AssetClient::createSetMappingRequest(const AssetPath& path, const AssetHash& hash) { + return new SetMappingRequest(path, hash); +} + +AssetRequest* AssetClient::createRequest(const AssetHash& hash, const QString& extension) { if (hash.length() != SHA256_HASH_HEX_LENGTH) { qCWarning(asset_client) << "Invalid hash size"; return nullptr; @@ -128,8 +315,6 @@ AssetRequest* AssetClient::createRequest(const QString& hash, const QString& ext } } - - AssetUpload* AssetClient::createUpload(const QString& filename) { if (haveAssetServer()) { @@ -305,6 +490,100 @@ void AssetClient::handleAssetGetReply(QSharedPointer message, S } } +bool AssetClient::getAssetMapping(const AssetPath& path, MappingOperationCallback callback) { + auto nodeList = DependencyManager::get(); + SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); + if (assetServer) { + auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true); + + auto messageID = ++_currentID; + packetList->writePrimitive(messageID); + + packetList->writePrimitive(AssetMappingOperationType::Get); + + packetList->writeString(path); + + nodeList->sendPacketList(std::move(packetList), *assetServer); + + _pendingMappingRequests[assetServer][messageID] = callback; + + return true; + } + + return false; +} + +bool AssetClient::getAllAssetMappings(MappingOperationCallback callback) { + auto nodeList = DependencyManager::get(); + SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); + + if (assetServer) { + auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true); + + auto messageID = ++_currentID; + packetList->writePrimitive(messageID); + + packetList->writePrimitive(AssetMappingOperationType::GetAll); + + nodeList->sendPacketList(std::move(packetList), *assetServer); + + _pendingMappingRequests[assetServer][messageID] = callback; + + return true; + } + + return false; +} + +bool AssetClient::deleteAssetMapping(const AssetPath& path, MappingOperationCallback callback) { + auto nodeList = DependencyManager::get(); + SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); + + if (assetServer) { + auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true); + + auto messageID = ++_currentID; + packetList->writePrimitive(messageID); + + packetList->writePrimitive(AssetMappingOperationType::Delete); + + packetList->writeString(path); + + nodeList->sendPacketList(std::move(packetList), *assetServer); + + _pendingMappingRequests[assetServer][messageID] = callback; + + return true; + } + + return false; +} + +bool AssetClient::setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback) { + auto nodeList = DependencyManager::get(); + SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); + + if (assetServer) { + auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true); + + auto messageID = ++_currentID; + packetList->writePrimitive(messageID); + + packetList->writePrimitive(AssetMappingOperationType::Set); + + packetList->writeString(path); + packetList->writeString(hash); + + nodeList->sendPacketList(std::move(packetList), *assetServer); + + _pendingMappingRequests[assetServer][messageID] = callback; + + return true; + } + + return false; +} + bool AssetClient::uploadAsset(const QByteArray& data, const QString& extension, UploadResultCallback callback) { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); @@ -404,6 +683,18 @@ void AssetClient::handleNodeKilled(SharedNodePointer node) { messageMapIt->second.clear(); } } + + { + auto messageMapIt = _pendingMappingRequests.find(node); + if (messageMapIt != _pendingMappingRequests.end()) { + for (const auto& value : messageMapIt->second) { + value.second(false, AssetServerError::NoError, QSharedPointer()); + } + messageMapIt->second.clear(); + } + } + + _mappingCache.clear(); } void AssetScriptingInterface::uploadData(QString data, QString extension, QScriptValue callback) { @@ -471,4 +762,75 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb }); assetRequest->start(); -} \ No newline at end of file +} + +void AssetScriptingInterface::setMapping(QString path, QString hash, QScriptValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createSetMappingRequest(path, hash); + + connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { + QScriptValueList args { uint8_t(request->getError()) }; + + callback.call(_engine->currentContext()->thisObject(), args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetScriptingInterface::getMapping(QString path, QScriptValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetMappingRequest(path); + + connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { + QScriptValueList args { uint8_t(request->getError()), request->getHash() }; + + callback.call(_engine->currentContext()->thisObject(), args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetScriptingInterface::deleteMapping(QString path, QScriptValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createDeleteMappingRequest(path); + + connect(request, &DeleteMappingRequest::finished, this, [this, callback](DeleteMappingRequest* request) mutable { + QScriptValueList args { uint8_t(request->getError()) }; + + callback.call(_engine->currentContext()->thisObject(), args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetScriptingInterface::getAllMappings(QScriptValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetAllMappingsRequest(); + + connect(request, &GetAllMappingsRequest::finished, this, [this, callback](GetAllMappingsRequest* request) mutable { + auto mappings = request->getMappings(); + auto map = callback.engine()->newObject(); + + for (auto& kv : mappings ) { + map.setProperty(kv.first, kv.second); + } + + QScriptValueList args { uint8_t(request->getError()), map }; + + callback.call(_engine->currentContext()->thisObject(), args); + + request->deleteLater(); + + }); + + request->start(); +} diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index f66fe8adcc..b51e7f5316 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -16,6 +16,8 @@ #include #include +#include + #include #include "AssetUtils.h" @@ -25,6 +27,8 @@ #include "ReceivedMessage.h" #include "ResourceCache.h" +class GetMappingRequest; +class SetMappingRequest; class AssetRequest; class AssetUpload; @@ -33,18 +37,114 @@ struct AssetInfo { int64_t size; }; +using MappingOperationCallback = std::function message)>; using ReceivedAssetCallback = std::function; using GetInfoCallback = std::function; using UploadResultCallback = std::function; using ProgressCallback = std::function; +class MappingRequest : public QObject { + Q_OBJECT +public: + enum Error { + NoError, + NotFound, + NetworkError, + PermissionDenied, + UnknownError + }; + + Q_INVOKABLE void start(); + Error getError() const { return _error; } + +protected: + Error _error { NoError }; + +private: + virtual void doStart() = 0; +}; + + +class GetMappingRequest : public MappingRequest { + Q_OBJECT +public: + GetMappingRequest(AssetPath path); + + AssetHash getHash() const { return _hash; } + +signals: + void finished(GetMappingRequest* thisRequest); + +private: + virtual void doStart() override; + + AssetPath _path; + AssetHash _hash; +}; + +class SetMappingRequest : public MappingRequest { + Q_OBJECT +public: + SetMappingRequest(AssetPath path, AssetHash hash); + + AssetHash getHash() const { return _hash; } + +signals: + void finished(SetMappingRequest* thisRequest); + +private: + virtual void doStart() override; + + AssetPath _path; + AssetHash _hash; +}; + +class DeleteMappingRequest : public MappingRequest { + Q_OBJECT +public: + DeleteMappingRequest(AssetPath path); + + Q_INVOKABLE void start(); + +signals: + void finished(DeleteMappingRequest* thisRequest); + +private: + virtual void doStart() override; + + AssetPath _path; +}; + +class GetAllMappingsRequest : public MappingRequest { + Q_OBJECT +public: + GetAllMappingsRequest(); + + Q_INVOKABLE void start(); + + AssetMapping getMappings() const { return _mappings; } + +signals: + void finished(GetAllMappingsRequest* thisRequest); + +private: + virtual void doStart() override; + + std::map _mappings; +}; + + class AssetClient : public QObject, public Dependency { Q_OBJECT public: AssetClient(); - Q_INVOKABLE AssetRequest* createRequest(const QString& hash, const QString& extension); + Q_INVOKABLE GetMappingRequest* createGetMappingRequest(const AssetPath& path); + Q_INVOKABLE GetAllMappingsRequest* createGetAllMappingsRequest(); + Q_INVOKABLE DeleteMappingRequest* createDeleteMappingRequest(const AssetPath& path); + Q_INVOKABLE SetMappingRequest* createSetMappingRequest(const AssetPath& path, const AssetHash& hash); + Q_INVOKABLE AssetRequest* createRequest(const AssetHash& hash, const QString& extension); Q_INVOKABLE AssetUpload* createUpload(const QString& filename); Q_INVOKABLE AssetUpload* createUpload(const QByteArray& data, const QString& extension); @@ -55,6 +155,7 @@ public slots: void clearCache(); private slots: + void handleAssetMappingOperationReply(QSharedPointer message, SharedNodePointer senderNode); void handleAssetGetInfoReply(QSharedPointer message, SharedNodePointer senderNode); void handleAssetGetReply(QSharedPointer message, SharedNodePointer senderNode); void handleAssetUploadReply(QSharedPointer message, SharedNodePointer senderNode); @@ -62,6 +163,11 @@ private slots: void handleNodeKilled(SharedNodePointer node); private: + bool getAssetMapping(const AssetHash& hash, MappingOperationCallback callback); + bool getAllAssetMappings(MappingOperationCallback callback); + bool setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback); + bool deleteAssetMapping(const AssetPath& path, MappingOperationCallback callback); + bool getAssetInfo(const QString& hash, const QString& extension, GetInfoCallback callback); bool getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback, ProgressCallback progressCallback); @@ -73,12 +179,19 @@ private: }; static MessageID _currentID; + std::unordered_map> _pendingMappingRequests; std::unordered_map> _pendingRequests; std::unordered_map> _pendingInfoRequests; std::unordered_map> _pendingUploads; + + QHash _mappingCache; friend class AssetRequest; friend class AssetUpload; + friend class GetMappingRequest; + friend class GetAllMappingsRequest; + friend class SetMappingRequest; + friend class DeleteMappingRequest; }; @@ -89,6 +202,10 @@ public: Q_INVOKABLE void uploadData(QString data, QString extension, QScriptValue callback); Q_INVOKABLE void downloadData(QString url, QScriptValue downloadComplete); + Q_INVOKABLE void setMapping(QString path, QString hash, QScriptValue callback); + Q_INVOKABLE void getMapping(QString path, QScriptValue callback); + Q_INVOKABLE void deleteMapping(QString path, QScriptValue callback); + Q_INVOKABLE void getAllMappings(QScriptValue callback); protected: QSet _pendingRequests; QScriptEngine* _engine; diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 19f91349fb..0665590902 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -21,7 +21,6 @@ #include "ResourceCache.h" AssetRequest::AssetRequest(const QString& hash, const QString& extension) : - QObject(), _hash(hash), _extension(extension) { diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index dac3329153..92a804d421 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -21,8 +21,6 @@ AssetResourceRequest::~AssetResourceRequest() { } void AssetResourceRequest::doSend() { - // Make request to atp - auto assetClient = DependencyManager::get(); auto parts = _url.path().split(".", QString::SkipEmptyParts); auto hash = parts.length() > 0 ? parts[0] : ""; auto extension = parts.length() > 1 ? parts[1] : ""; @@ -35,6 +33,8 @@ void AssetResourceRequest::doSend() { return; } + // Make request to atp + auto assetClient = DependencyManager::get(); _assetRequest = assetClient->createRequest(hash, extension); if (!_assetRequest) { diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 21b6b3f434..99e8fdc386 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -14,12 +14,18 @@ #include +#include + #include #include using MessageID = uint32_t; using DataOffset = int64_t; +using AssetPath = QString; +using AssetHash = QString; +using AssetMapping = std::map; + const size_t SHA256_HASH_LENGTH = 32; const size_t SHA256_HASH_HEX_LENGTH = 64; const uint64_t MAX_UPLOAD_SIZE = 1000 * 1000 * 1000; // 1GB @@ -32,6 +38,13 @@ enum AssetServerError : uint8_t { PermissionDenied }; +enum AssetMappingOperationType : uint8_t { + Get = 0, + GetAll, + Set, + Delete +}; + QUrl getATPUrl(const QString& hash, const QString& extension = QString()); QByteArray hashData(const QByteArray& data); diff --git a/libraries/networking/src/ReceivedMessage.cpp b/libraries/networking/src/ReceivedMessage.cpp index 651b856923..6ef2b7c7d4 100644 --- a/libraries/networking/src/ReceivedMessage.cpp +++ b/libraries/networking/src/ReceivedMessage.cpp @@ -107,6 +107,15 @@ QByteArray ReceivedMessage::readAll() { return read(getBytesLeftToRead()); } +QString ReceivedMessage::readString() { + uint32_t size; + readPrimitive(&size); + //Q_ASSERT(size <= _size - _position); + auto string = QString::fromUtf8(_data.constData() + _position, size); + _position += size; + return string; +} + QByteArray ReceivedMessage::readWithoutCopy(qint64 size) { QByteArray data { QByteArray::fromRawData(_data.constData() + _position, size) }; _position += size; diff --git a/libraries/networking/src/ReceivedMessage.h b/libraries/networking/src/ReceivedMessage.h index 1f797f1262..e9131c074f 100644 --- a/libraries/networking/src/ReceivedMessage.h +++ b/libraries/networking/src/ReceivedMessage.h @@ -63,6 +63,8 @@ public: QByteArray read(qint64 size); QByteArray readAll(); + QString readString(); + QByteArray readHead(qint64 size); // This will return a QByteArray referencing the underlying data _without_ refcounting that data. @@ -86,7 +88,6 @@ private: QByteArray _data; QByteArray _headData; - std::atomic _size { true }; std::atomic _position { 0 }; std::atomic _numPackets { 0 }; diff --git a/libraries/networking/src/udt/BasePacket.cpp b/libraries/networking/src/udt/BasePacket.cpp index 000573d241..dba241f221 100644 --- a/libraries/networking/src/udt/BasePacket.cpp +++ b/libraries/networking/src/udt/BasePacket.cpp @@ -150,6 +150,20 @@ QByteArray BasePacket::readWithoutCopy(qint64 maxSize) { return data; } +qint64 BasePacket::writeString(const QString& string) { + QByteArray data = string.toUtf8(); + writePrimitive(static_cast(data.length())); + return writeData(data.constData(), data.length()); +} + +QString BasePacket::readString() { + uint32_t size; + readPrimitive(&size); + auto string = QString::fromUtf8(getPayload() + pos(), size); + seek(pos() + size); + return string; +} + bool BasePacket::reset() { if (isWritable()) { _payloadSize = 0; diff --git a/libraries/networking/src/udt/BasePacket.h b/libraries/networking/src/udt/BasePacket.h index 392a7c4384..846c05ecbf 100644 --- a/libraries/networking/src/udt/BasePacket.h +++ b/libraries/networking/src/udt/BasePacket.h @@ -77,7 +77,10 @@ public: using QIODevice::read; // Bring QIODevice::read methods to scope, otherwise they are hidden by folling method QByteArray read(qint64 maxSize); QByteArray readWithoutCopy(qint64 maxSize); // this can only be used if packet will stay in scope - + + qint64 writeString(const QString& string); + QString readString(); + template qint64 peekPrimitive(T* data); template qint64 readPrimitive(T* data); template qint64 writePrimitive(const T& data); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 7840ecb17e..a2bd0d4d2d 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -91,7 +91,9 @@ public: MessagesData, MessagesSubscribe, MessagesUnsubscribe, - ICEServerHeartbeatDenied + ICEServerHeartbeatDenied, + AssetMappingOperation, + AssetMappingOperationReply }; }; diff --git a/libraries/networking/src/udt/PacketList.cpp b/libraries/networking/src/udt/PacketList.cpp index 978df9b9bb..b12b7e6938 100644 --- a/libraries/networking/src/udt/PacketList.cpp +++ b/libraries/networking/src/udt/PacketList.cpp @@ -158,6 +158,12 @@ void PacketList::preparePackets(MessageNumber messageNumber) { const qint64 PACKET_LIST_WRITE_ERROR = -1; +qint64 PacketList::writeString(const QString& string) { + QByteArray data = string.toUtf8(); + writePrimitive(static_cast(data.length())); + return writeData(data.constData(), data.length()); +} + qint64 PacketList::writeData(const char* data, qint64 maxSize) { auto sizeRemaining = maxSize; diff --git a/libraries/networking/src/udt/PacketList.h b/libraries/networking/src/udt/PacketList.h index 4f1e46e616..875eb70e45 100644 --- a/libraries/networking/src/udt/PacketList.h +++ b/libraries/networking/src/udt/PacketList.h @@ -59,6 +59,8 @@ public: template qint64 readPrimitive(T* data); template qint64 writePrimitive(const T& data); + + qint64 writeString(const QString& string); protected: PacketList(PacketType packetType, QByteArray extendedHeader = QByteArray(), bool isReliable = false, bool isOrdered = false);