From f9f42a085ac185fa58573fbc2e5baf3e112c1024 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 14:43:55 -0800 Subject: [PATCH 1/5] add client side handling for mapping rename --- libraries/networking/src/AssetClient.cpp | 88 +++++++++++++++++++++++- libraries/networking/src/AssetClient.h | 19 +++++ libraries/networking/src/AssetUtils.h | 3 +- 3 files changed, 108 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 8b4ff50d89..21e72f56a9 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -174,6 +174,46 @@ void DeleteMappingsRequest::doStart() { }); }; +RenameMappingRequest::RenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath) : + _oldPath(oldPath), + _newPath(newPath) +{ + +} + +void RenameMappingRequest::doStart() { + auto assetClient = DependencyManager::get(); + assetClient->renameAssetMapping(_oldPath, _newPath, [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) { + // take the hash mapped for the old path from the cache + auto hash = assetClient->_mappingCache.take(_oldPath); + if (!hash.isEmpty()) { + // use the hash mapped for the old path for the new path + assetClient->_mappingCache[_newPath] = hash; + } + } + emit finished(this); + }); +} + AssetClient::AssetClient() { @@ -300,6 +340,10 @@ SetMappingRequest* AssetClient::createSetMappingRequest(const AssetPath& path, c return new SetMappingRequest(path, hash); } +RenameMappingRequest* AssetClient::createRenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath) { + return new RenameMappingRequest(oldPath, newPath); +} + AssetRequest* AssetClient::createRequest(const AssetHash& hash) { if (hash.length() != SHA256_HASH_HEX_LENGTH) { qCWarning(asset_client) << "Invalid hash size"; @@ -573,7 +617,7 @@ bool AssetClient::setAssetMapping(const QString& path, const AssetHash& hash, Ma packetList->writePrimitive(AssetMappingOperationType::Set); - packetList->writeString(path.toUtf8()); + packetList->writeString(path); packetList->write(QByteArray::fromHex(hash.toUtf8())); nodeList->sendPacketList(std::move(packetList), *assetServer); @@ -586,6 +630,32 @@ bool AssetClient::setAssetMapping(const QString& path, const AssetHash& hash, Ma return false; } +bool AssetClient::renameAssetMapping(const AssetPath& oldPath, const AssetPath& newPath, 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::Rename); + + packetList->writeString(oldPath); + packetList->writeString(newPath); + + nodeList->sendPacketList(std::move(packetList), *assetServer); + + _pendingMappingRequests[assetServer][messageID] = callback; + + return true; + + } + + return false; +} + bool AssetClient::uploadAsset(const QByteArray& data, UploadResultCallback callback) { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); @@ -832,3 +902,19 @@ void AssetScriptingInterface::getAllMappings(QScriptValue callback) { request->start(); } + +void AssetScriptingInterface::renameMapping(QString oldPath, QString newPath, QScriptValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createRenameMappingRequest(oldPath, newPath); + + connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { + QScriptValueList args { uint8_t(request->getError()) }; + + 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 8eba65ecc5..58f13d8c1e 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -113,6 +113,21 @@ private: AssetPathList _paths; }; +class RenameMappingRequest : public MappingRequest { + Q_OBJECT +public: + RenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath); + +signals: + void finished(RenameMappingRequest* thisRequest); + +private: + virtual void doStart() override; + + AssetPath _oldPath; + AssetPath _newPath; +}; + class GetAllMappingsRequest : public MappingRequest { Q_OBJECT public: @@ -138,6 +153,7 @@ public: Q_INVOKABLE GetAllMappingsRequest* createGetAllMappingsRequest(); Q_INVOKABLE DeleteMappingsRequest* createDeleteMappingsRequest(const AssetPathList& paths); Q_INVOKABLE SetMappingRequest* createSetMappingRequest(const AssetPath& path, const AssetHash& hash); + Q_INVOKABLE RenameMappingRequest* createRenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath); Q_INVOKABLE AssetRequest* createRequest(const AssetHash& hash); Q_INVOKABLE AssetUpload* createUpload(const QString& filename); Q_INVOKABLE AssetUpload* createUpload(const QByteArray& data); @@ -161,6 +177,7 @@ private: bool getAllAssetMappings(MappingOperationCallback callback); bool setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback); bool deleteAssetMappings(const AssetPathList& paths, MappingOperationCallback callback); + bool renameAssetMapping(const AssetPath& oldPath, const AssetPath& newPath, MappingOperationCallback callback); bool getAssetInfo(const QString& hash, GetInfoCallback callback); bool getAsset(const QString& hash, DataOffset start, DataOffset end, @@ -186,6 +203,7 @@ private: friend class GetAllMappingsRequest; friend class SetMappingRequest; friend class DeleteMappingsRequest; + friend class RenameMappingRequest; }; @@ -200,6 +218,7 @@ public: Q_INVOKABLE void getMapping(QString path, QScriptValue callback); Q_INVOKABLE void deleteMappings(QStringList paths, QScriptValue callback); Q_INVOKABLE void getAllMappings(QScriptValue callback); + Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QScriptValue callback); protected: QSet _pendingRequests; QScriptEngine* _engine; diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 8925238b0e..2495326b67 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -44,7 +44,8 @@ enum AssetMappingOperationType : uint8_t { Get = 0, GetAll, Set, - Delete + Delete, + Rename }; QUrl getATPUrl(const QString& hash); From 181b20f6739eee47b4cddf8bb47ebb8ff9e0dbf4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 14:46:15 -0800 Subject: [PATCH 2/5] move the AssetScriptInterface to script-engine --- libraries/networking/src/AssetClient.cpp | 153 ---------------- libraries/networking/src/AssetClient.h | 20 -- .../src/AssetScriptingInterface.cpp | 172 ++++++++++++++++++ .../src/AssetScriptingInterface.h | 39 ++++ libraries/script-engine/src/ScriptEngine.h | 4 +- 5 files changed, 213 insertions(+), 175 deletions(-) create mode 100644 libraries/script-engine/src/AssetScriptingInterface.cpp create mode 100644 libraries/script-engine/src/AssetScriptingInterface.h diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 21e72f56a9..9f3358bcda 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -765,156 +765,3 @@ void AssetClient::handleNodeKilled(SharedNodePointer node) { _mappingCache.clear(); } - -void AssetScriptingInterface::uploadData(QString data, QScriptValue callback) { - QByteArray dataByteArray = data.toUtf8(); - auto upload = DependencyManager::get()->createUpload(dataByteArray); - if (!upload) { - qCWarning(asset_client) << "Error uploading file to asset server"; - return; - } - - QObject::connect(upload, &AssetUpload::finished, this, [this, callback](AssetUpload* upload, const QString& hash) mutable { - if (callback.isFunction()) { - QString url = "atp://" + hash; - QScriptValueList args { url }; - callback.call(_engine->currentContext()->thisObject(), args); - } - }); - upload->start(); -} - -AssetScriptingInterface::AssetScriptingInterface(QScriptEngine* engine) : - _engine(engine) -{ -} - -void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callback) { - const QString ATP_SCHEME { "atp://" }; - - if (!urlString.startsWith(ATP_SCHEME)) { - return; - } - - // Make request to atp - auto path = urlString.right(urlString.length() - ATP_SCHEME.length()); - auto parts = path.split(".", QString::SkipEmptyParts); - auto hash = parts.length() > 0 ? parts[0] : ""; - - if (hash.length() != SHA256_HASH_HEX_LENGTH) { - return; - } - - auto assetClient = DependencyManager::get(); - auto assetRequest = assetClient->createRequest(hash); - - if (!assetRequest) { - return; - } - - _pendingRequests << assetRequest; - - connect(assetRequest, &AssetRequest::finished, this, [this, callback](AssetRequest* request) mutable { - Q_ASSERT(request->getState() == AssetRequest::Finished); - - if (request->getError() == AssetRequest::Error::NoError) { - if (callback.isFunction()) { - QString data = QString::fromUtf8(request->getData()); - QScriptValueList args { data }; - callback.call(_engine->currentContext()->thisObject(), args); - } - } - - request->deleteLater(); - _pendingRequests.remove(request); - }); - - assetRequest->start(); -} - -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::deleteMappings(QStringList paths, QScriptValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createDeleteMappingsRequest(paths); - - connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* 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(); -} - -void AssetScriptingInterface::renameMapping(QString oldPath, QString newPath, QScriptValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createRenameMappingRequest(oldPath, newPath); - - connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { - QScriptValueList args { uint8_t(request->getError()) }; - - 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 58f13d8c1e..1e9ad2afcd 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -14,7 +14,6 @@ #define hifi_AssetClient_h #include -#include #include @@ -206,23 +205,4 @@ private: friend class RenameMappingRequest; }; - -class AssetScriptingInterface : public QObject { - Q_OBJECT -public: - AssetScriptingInterface(QScriptEngine* engine); - - Q_INVOKABLE void uploadData(QString data, 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 deleteMappings(QStringList paths, QScriptValue callback); - Q_INVOKABLE void getAllMappings(QScriptValue callback); - Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QScriptValue callback); -protected: - QSet _pendingRequests; - QScriptEngine* _engine; -}; - - #endif diff --git a/libraries/script-engine/src/AssetScriptingInterface.cpp b/libraries/script-engine/src/AssetScriptingInterface.cpp new file mode 100644 index 0000000000..4f539d5021 --- /dev/null +++ b/libraries/script-engine/src/AssetScriptingInterface.cpp @@ -0,0 +1,172 @@ +// +// AssetScriptingInterface.cpp +// libraries/script-engine/src +// +// Created by Stephen Birarda on 2016-03-08. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "AssetScriptingInterface.h" + +#include + +#include +#include +#include + +AssetScriptingInterface::AssetScriptingInterface(QScriptEngine* engine) : + _engine(engine) +{ + +} + +void AssetScriptingInterface::uploadData(QString data, QScriptValue callback) { + QByteArray dataByteArray = data.toUtf8(); + auto upload = DependencyManager::get()->createUpload(dataByteArray); + if (!upload) { + qCWarning(asset_client) << "Error uploading file to asset server"; + return; + } + + QObject::connect(upload, &AssetUpload::finished, this, [this, callback](AssetUpload* upload, const QString& hash) mutable { + if (callback.isFunction()) { + QString url = "atp://" + hash; + QScriptValueList args { url }; + callback.call(_engine->currentContext()->thisObject(), args); + } + }); + upload->start(); +} + +void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callback) { + const QString ATP_SCHEME { "atp://" }; + + if (!urlString.startsWith(ATP_SCHEME)) { + return; + } + + // Make request to atp + auto path = urlString.right(urlString.length() - ATP_SCHEME.length()); + auto parts = path.split(".", QString::SkipEmptyParts); + auto hash = parts.length() > 0 ? parts[0] : ""; + + if (hash.length() != SHA256_HASH_HEX_LENGTH) { + return; + } + + auto assetClient = DependencyManager::get(); + auto assetRequest = assetClient->createRequest(hash); + + if (!assetRequest) { + return; + } + + _pendingRequests << assetRequest; + + connect(assetRequest, &AssetRequest::finished, this, [this, callback](AssetRequest* request) mutable { + Q_ASSERT(request->getState() == AssetRequest::Finished); + + if (request->getError() == AssetRequest::Error::NoError) { + if (callback.isFunction()) { + QString data = QString::fromUtf8(request->getData()); + QScriptValueList args { data }; + callback.call(_engine->currentContext()->thisObject(), args); + } + } + + request->deleteLater(); + _pendingRequests.remove(request); + }); + + assetRequest->start(); +} + +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::deleteMappings(QStringList paths, QScriptValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createDeleteMappingsRequest(paths); + + connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* 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(); +} + +void AssetScriptingInterface::renameMapping(QString oldPath, QString newPath, QScriptValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createRenameMappingRequest(oldPath, newPath); + + connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { + QScriptValueList args { uint8_t(request->getError()) }; + + callback.call(_engine->currentContext()->thisObject(), args); + + request->deleteLater(); + + }); + + request->start(); +} diff --git a/libraries/script-engine/src/AssetScriptingInterface.h b/libraries/script-engine/src/AssetScriptingInterface.h new file mode 100644 index 0000000000..287300cac8 --- /dev/null +++ b/libraries/script-engine/src/AssetScriptingInterface.h @@ -0,0 +1,39 @@ +// +// AssetScriptingInterface.h +// libraries/script-engine/src +// +// Created by Stephen Birarda on 2016-03-08. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once + +#ifndef hifi_AssetScriptingInterface_h +#define hifi_AssetScriptingInterface_h + +#include +#include + +#include + +class AssetScriptingInterface : public QObject { + Q_OBJECT +public: + AssetScriptingInterface(QScriptEngine* engine); + + Q_INVOKABLE void uploadData(QString data, 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 deleteMappings(QStringList paths, QScriptValue callback); + Q_INVOKABLE void getAllMappings(QScriptValue callback); + Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QScriptValue callback); +protected: + QSet _pendingRequests; + QScriptEngine* _engine; +}; + +#endif // hifi_AssetScriptingInterface_h diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 91d4c3f5a5..8e0d2c2f4a 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -23,7 +23,6 @@ #include #include -#include #include #include #include @@ -32,6 +31,7 @@ #include "MouseEvent.h" #include "ArrayBufferClass.h" +#include "AssetScriptingInterface.h" #include "AudioScriptingInterface.h" #include "Quat.h" #include "ScriptCache.h" @@ -219,4 +219,4 @@ protected: static std::atomic _stoppingAllScripts; }; -#endif // hifi_ScriptEngine_h \ No newline at end of file +#endif // hifi_ScriptEngine_h From 33cadb36dadbde6963ae81014fd35b6e54f6c4e8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 14:57:22 -0800 Subject: [PATCH 3/5] add server side handling for mapping rename --- assignment-client/src/assets/AssetServer.cpp | 43 +++++++++++++++++++- assignment-client/src/assets/AssetServer.h | 6 ++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 52a019aff6..59b9e9fc47 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -203,6 +203,10 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me handleDeleteMappingsOperation(*message, senderNode, *replyPacket); break; } + case AssetMappingOperationType::Rename: { + handleRenameMappingOperation(*message, senderNode, *replyPacket); + break; + } } auto nodeList = DependencyManager::get(); @@ -274,6 +278,21 @@ void AssetServer::handleDeleteMappingsOperation(ReceivedMessage& message, Shared } } +void AssetServer::handleRenameMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket) { + if (senderNode->getCanRez()) { + QString oldPath = message.readString(); + QString newPath = message.readString(); + + if (renameMapping(oldPath, newPath)) { + replyPacket.writePrimitive(AssetServerError::NoError); + } else { + replyPacket.writePrimitive(AssetServerError::MappingOperationFailed); + } + } else { + replyPacket.writePrimitive(AssetServerError::PermissionDenied); + } +} + void AssetServer::handleAssetGetInfo(QSharedPointer message, SharedNodePointer senderNode) { QByteArray assetHash; MessageID messageID; @@ -468,7 +487,7 @@ bool AssetServer::writeMappingsToFile() { return false; } -bool AssetServer::setMapping(AssetPath path, AssetHash hash) { +bool AssetServer::setMapping(const AssetPath& path, const AssetHash& hash) { // remember what the old mapping was in case persistence fails auto oldMapping = _fileMappings.value(path).toString(); @@ -516,3 +535,25 @@ bool AssetServer::deleteMappings(const AssetPathList& paths) { return false; } } + +bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPath) { + // take the old hash to remove the old mapping + auto oldMapping = _fileMappings[oldPath].toString(); + + if (!oldMapping.isEmpty()) { + _fileMappings[newPath] = oldMapping; + + if (writeMappingsToFile()) { + // persisted the renamed mapping, return success + return true; + } else { + // we couldn't persist the renamed mapping, rollback and return failure + _fileMappings[oldPath] = oldMapping; + + return false; + } + } else { + // failed to find a mapping that was to be renamed, return failure + return false; + } +} diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index f81fcf46b3..f8597c3688 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -45,17 +45,21 @@ private: void handleGetAllMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); void handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); void handleDeleteMappingsOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); + void handleRenameMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); // Mapping file operations must be called from main assignment thread only void loadMappingsFromFile(); bool writeMappingsToFile(); /// Set the mapping for path to hash - bool setMapping(AssetPath path, AssetHash hash); + bool setMapping(const AssetPath& path, const AssetHash& hash); /// Delete mapping `path`. Returns `true` if deletion of mappings succeeds, else `false`. bool deleteMappings(const AssetPathList& paths); + /// Rename mapping from `oldPath` to `newPath`. Returns true if successful + bool renameMapping(const AssetPath& oldPath, const AssetPath& newPath); + static void writeError(NLPacketList* packetList, AssetServerError error); void performMappingMigration(); From 8d5111a332e0582a0ca7dcb6bd864118ace8117a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 15:30:21 -0800 Subject: [PATCH 4/5] move MappingRequest and subclasses to separate file --- libraries/networking/src/AssetClient.cpp | 186 +--------------- libraries/networking/src/AssetClient.h | 105 +-------- .../networking/src/AssetResourceRequest.cpp | 1 + libraries/networking/src/MappingRequest.cpp | 202 ++++++++++++++++++ libraries/networking/src/MappingRequest.h | 123 +++++++++++ .../src/AssetScriptingInterface.cpp | 1 + 6 files changed, 331 insertions(+), 287 deletions(-) create mode 100644 libraries/networking/src/MappingRequest.cpp create mode 100644 libraries/networking/src/MappingRequest.h diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 9f3358bcda..7c967e681a 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -22,6 +22,7 @@ #include "AssetRequest.h" #include "AssetUpload.h" #include "AssetUtils.h" +#include "MappingRequest.h" #include "NetworkAccessManager.h" #include "NetworkLogging.h" #include "NodeList.h" @@ -30,191 +31,6 @@ MessageID AssetClient::_currentID = 0; -void MappingRequest::start() { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); - return; - } - doStart(); -}; - -GetMappingRequest::GetMappingRequest(const 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_LENGTH).toHex(); - 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) { - int 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(const AssetPath& path, const 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); - }); -}; - -DeleteMappingsRequest::DeleteMappingsRequest(const AssetPathList& paths) : _paths(paths) { -}; - -void DeleteMappingsRequest::doStart() { - auto assetClient = DependencyManager::get(); - assetClient->deleteAssetMappings(_paths, [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) { - // enumerate the paths and remove them from the cache - for (auto& path : _paths) { - assetClient->_mappingCache.remove(path); - } - } - emit finished(this); - }); -}; - -RenameMappingRequest::RenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath) : - _oldPath(oldPath), - _newPath(newPath) -{ - -} - -void RenameMappingRequest::doStart() { - auto assetClient = DependencyManager::get(); - assetClient->renameAssetMapping(_oldPath, _newPath, [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) { - // take the hash mapped for the old path from the cache - auto hash = assetClient->_mappingCache.take(_oldPath); - if (!hash.isEmpty()) { - // use the hash mapped for the old path for the new path - assetClient->_mappingCache[_newPath] = hash; - } - } - emit finished(this); - }); -} - - AssetClient::AssetClient() { setCustomDeleter([](Dependency* dependency){ diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 1e9ad2afcd..87b8646be1 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -9,7 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - #ifndef hifi_AssetClient_h #define hifi_AssetClient_h @@ -28,6 +27,9 @@ class GetMappingRequest; class SetMappingRequest; +class GetAllMappingsRequest; +class DeleteMappingsRequest; +class RenameMappingRequest; class AssetRequest; class AssetUpload; @@ -42,107 +44,6 @@ using GetInfoCallback = 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(const 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(const AssetPath& path, const AssetHash& hash); - - AssetHash getHash() const { return _hash; } - -signals: - void finished(SetMappingRequest* thisRequest); - -private: - virtual void doStart() override; - - AssetPath _path; - AssetHash _hash; -}; - -class DeleteMappingsRequest : public MappingRequest { - Q_OBJECT -public: - DeleteMappingsRequest(const AssetPathList& path); - -signals: - void finished(DeleteMappingsRequest* thisRequest); - -private: - virtual void doStart() override; - - AssetPathList _paths; -}; - -class RenameMappingRequest : public MappingRequest { - Q_OBJECT -public: - RenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath); - -signals: - void finished(RenameMappingRequest* thisRequest); - -private: - virtual void doStart() override; - - AssetPath _oldPath; - AssetPath _newPath; -}; - -class GetAllMappingsRequest : public MappingRequest { - Q_OBJECT -public: - GetAllMappingsRequest(); - - 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: diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index fcc4e12456..a588bfb0d8 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -13,6 +13,7 @@ #include "AssetClient.h" #include "AssetUtils.h" +#include "MappingRequest.h" AssetResourceRequest::~AssetResourceRequest() { if (_assetMappingRequest) { diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp new file mode 100644 index 0000000000..187694e134 --- /dev/null +++ b/libraries/networking/src/MappingRequest.cpp @@ -0,0 +1,202 @@ +// +// MappingRequest.cpp +// libraries/networking/src +// +// Created by Stephen Birarda on 2016-03-08. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "MappingRequest.h" + +#include + +#include + +#include "AssetClient.h" + +void MappingRequest::start() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); + return; + } + doStart(); +}; + +GetMappingRequest::GetMappingRequest(const 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_LENGTH).toHex(); + 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) { + int 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(const AssetPath& path, const 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); + }); +}; + +DeleteMappingsRequest::DeleteMappingsRequest(const AssetPathList& paths) : _paths(paths) { +}; + +void DeleteMappingsRequest::doStart() { + auto assetClient = DependencyManager::get(); + assetClient->deleteAssetMappings(_paths, [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) { + // enumerate the paths and remove them from the cache + for (auto& path : _paths) { + assetClient->_mappingCache.remove(path); + } + } + emit finished(this); + }); +}; + +RenameMappingRequest::RenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath) : +_oldPath(oldPath), +_newPath(newPath) +{ + +} + +void RenameMappingRequest::doStart() { + auto assetClient = DependencyManager::get(); + assetClient->renameAssetMapping(_oldPath, _newPath, [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) { + // take the hash mapped for the old path from the cache + auto hash = assetClient->_mappingCache.take(_oldPath); + if (!hash.isEmpty()) { + // use the hash mapped for the old path for the new path + assetClient->_mappingCache[_newPath] = hash; + } + } + emit finished(this); + }); +} diff --git a/libraries/networking/src/MappingRequest.h b/libraries/networking/src/MappingRequest.h new file mode 100644 index 0000000000..b9bd867712 --- /dev/null +++ b/libraries/networking/src/MappingRequest.h @@ -0,0 +1,123 @@ +// +// MappingRequest.h +// libraries/networking/src +// +// Created by Stephen Birarda on 2016-03-08. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once + +#ifndef hifi_MappingRequest_h +#define hifi_MappingRequest_h + +#include + +#include "AssetUtils.h" + +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(const 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(const AssetPath& path, const AssetHash& hash); + + AssetHash getHash() const { return _hash; } + +signals: + void finished(SetMappingRequest* thisRequest); + +private: + virtual void doStart() override; + + AssetPath _path; + AssetHash _hash; +}; + +class DeleteMappingsRequest : public MappingRequest { + Q_OBJECT +public: + DeleteMappingsRequest(const AssetPathList& path); + +signals: + void finished(DeleteMappingsRequest* thisRequest); + +private: + virtual void doStart() override; + + AssetPathList _paths; +}; + +class RenameMappingRequest : public MappingRequest { + Q_OBJECT +public: + RenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath); + +signals: + void finished(RenameMappingRequest* thisRequest); + +private: + virtual void doStart() override; + + AssetPath _oldPath; + AssetPath _newPath; +}; + +class GetAllMappingsRequest : public MappingRequest { + Q_OBJECT +public: + GetAllMappingsRequest(); + + AssetMapping getMappings() const { return _mappings; } + +signals: + void finished(GetAllMappingsRequest* thisRequest); + +private: + virtual void doStart() override; + + std::map _mappings; +}; + + +#endif // hifi_MappingRequest_h diff --git a/libraries/script-engine/src/AssetScriptingInterface.cpp b/libraries/script-engine/src/AssetScriptingInterface.cpp index 4f539d5021..db29008976 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetScriptingInterface.cpp @@ -15,6 +15,7 @@ #include #include +#include #include AssetScriptingInterface::AssetScriptingInterface(QScriptEngine* engine) : From 6abd1c50b27b238169145f04d2daa811a825adbd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 15:45:13 -0800 Subject: [PATCH 5/5] remove the inlined writeError in AssetServer --- assignment-client/src/assets/AssetServer.cpp | 3 ++- assignment-client/src/assets/AssetServer.h | 10 ++-------- assignment-client/src/assets/SendAssetTask.cpp | 6 +++--- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 59b9e9fc47..13257967ac 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -21,11 +21,12 @@ #include #include +#include + #include "NetworkLogging.h" #include "NodeType.h" #include "SendAssetTask.h" #include "UploadAssetTask.h" -#include const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server"; diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index f8597c3688..094ea58d41 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -12,10 +12,10 @@ #ifndef hifi_AssetServer_h #define hifi_AssetServer_h -#include +#include +#include #include -#include #include "AssetUtils.h" #include "ReceivedMessage.h" @@ -60,8 +60,6 @@ private: /// Rename mapping from `oldPath` to `newPath`. Returns true if successful bool renameMapping(const AssetPath& oldPath, const AssetPath& newPath); - static void writeError(NLPacketList* packetList, AssetServerError error); - void performMappingMigration(); Mappings _fileMappings; @@ -71,8 +69,4 @@ private: QThreadPool _taskPool; }; -inline void writeError(NLPacketList* packetList, AssetServerError error) { - packetList->writePrimitive(error); -} - #endif diff --git a/assignment-client/src/assets/SendAssetTask.cpp b/assignment-client/src/assets/SendAssetTask.cpp index 33e1ab0fb8..d2b3c6c256 100644 --- a/assignment-client/src/assets/SendAssetTask.cpp +++ b/assignment-client/src/assets/SendAssetTask.cpp @@ -56,7 +56,7 @@ void SendAssetTask::run() { replyPacketList->writePrimitive(messageID); if (end <= start) { - writeError(replyPacketList.get(), AssetServerError::InvalidByteRange); + replyPacketList->writePrimitive(AssetServerError::InvalidByteRange); } else { QString filePath = _resourcesDir.filePath(QString(hexHash)); @@ -64,7 +64,7 @@ void SendAssetTask::run() { if (file.open(QIODevice::ReadOnly)) { if (file.size() < end) { - writeError(replyPacketList.get(), AssetServerError::InvalidByteRange); + replyPacketList->writePrimitive(AssetServerError::InvalidByteRange); qCDebug(networking) << "Bad byte range: " << hexHash << " " << start << ":" << end; } else { auto size = end - start; @@ -77,7 +77,7 @@ void SendAssetTask::run() { file.close(); } else { qCDebug(networking) << "Asset not found: " << filePath << "(" << hexHash << ")"; - writeError(replyPacketList.get(), AssetServerError::AssetNotFound); + replyPacketList->writePrimitive(AssetServerError::AssetNotFound); } }