From 7b179ab91aac3ec14b26cb17ccf7b46f348985fc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 29 Feb 2016 16:57:24 -0800 Subject: [PATCH 001/209] First draft for mapping requests --- assignment-client/src/assets/AssetServer.cpp | 27 +++++++ assignment-client/src/assets/AssetServer.h | 7 ++ libraries/networking/src/AssetClient.cpp | 79 ++++++++++++++++++- libraries/networking/src/AssetClient.h | 6 +- libraries/networking/src/AssetRequest.cpp | 5 +- libraries/networking/src/AssetRequest.h | 7 +- .../networking/src/AssetResourceRequest.cpp | 14 +--- libraries/networking/src/udt/PacketHeaders.h | 4 +- 8 files changed, 128 insertions(+), 21 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 4ca2439996..ab86787769 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -39,6 +39,7 @@ AssetServer::AssetServer(ReceivedMessage& message) : _taskPool.setMaxThreadCount(TASK_POOL_THREAD_COUNT); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); + packetReceiver.registerListener(PacketType::AssetGetMapping, this, "handleAssetGetMapping"); packetReceiver.registerListener(PacketType::AssetGet, this, "handleAssetGet"); packetReceiver.registerListener(PacketType::AssetGetInfo, this, "handleAssetGetInfo"); packetReceiver.registerListener(PacketType::AssetUpload, this, "handleAssetUpload"); @@ -161,6 +162,32 @@ void AssetServer::completeSetup() { nodeList->addNodeTypeToInterestSet(NodeType::Agent); } + +void AssetServer::handleAssetGetMapping(QSharedPointer packet, SharedNodePointer senderNode) { + MessageID messageID; + message->readPrimitive(&messageID); + QString assetPath = message->readAll(); + + auto replyPacket = NLPacket::create(PacketType::AssetGetMappingReply); + + replyPacket->writePrimitive(messageID); + + auto it = _fileMapping.find(assetPath.toStdString()); + + if (it != _fileMapping.end()) { + auto assetHash = QString::fromStdString(it.second); + qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; + replyPacket->writePrimitive(AssetServerError::NoError); + replyPacket->write(assetHash.toHex()); + } else { + qDebug() << "Mapping not found for: " << assetPath; + replyPacket->writePrimitive(AssetServerError::AssetNotFound); + } + + auto nodeList = DependencyManager::get(); + nodeList->sendPacket(std::move(replyPacket), *senderNode); +} + void AssetServer::handleAssetGetInfo(QSharedPointer message, SharedNodePointer senderNode) { QByteArray assetHash; MessageID messageID; diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 7d6e26af08..90e1eb8f34 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -31,6 +31,7 @@ public slots: private slots: void completeSetup(); + void handleAssetGetMapping(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetGetInfo(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetGet(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetUpload(QSharedPointer packetList, SharedNodePointer senderNode); @@ -39,6 +40,12 @@ private slots: private: static void writeError(NLPacketList* packetList, AssetServerError error); + + using Path = std::string; + using Hash = std::string; + using Mapping = std::map; + + Mapping _fileMapping; QDir _resourcesDirectory; QThreadPool _taskPool; }; diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 9591828fef..a61e30a8c1 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -39,6 +39,7 @@ AssetClient::AssetClient() { auto nodeList = DependencyManager::get(); auto& packetReceiver = nodeList->getPacketReceiver(); + packetReceiver.registerListener(PacketType::AssetGetMappingReply, this, "handleAssetGetMappingReply"); packetReceiver.registerListener(PacketType::AssetGetInfoReply, this, "handleAssetGetInfoReply"); packetReceiver.registerListener(PacketType::AssetGetReply, this, "handleAssetGetReply", true); packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply"); @@ -110,7 +111,22 @@ bool haveAssetServer() { return true; } -AssetRequest* AssetClient::createRequest(const QString& hash, const QString& extension) { +AssetRequest* AssetClient::createRequest(const QUrl& url) { + + auto parts = _url.path().split(".", QString::SkipEmptyParts); + auto hash = parts.length() > 0 ? parts[0] : ""; + auto extension = parts.length() > 1 ? parts[1] : ""; + + if (hash.length() != SHA256_HASH_HEX_LENGTH) { + _result = InvalidURL; + _state = Finished; + + emit finished(); + return; + } + + + if (hash.length() != SHA256_HASH_HEX_LENGTH) { qCWarning(asset_client) << "Invalid hash size"; return nullptr; @@ -155,6 +171,34 @@ AssetUpload* AssetClient::createUpload(const QByteArray& data, const QString& ex } } +bool AssetClient::getAssetMapping(const QString& path, GetMappingCallback callback) { + auto nodeList = DependencyManager::get(); + SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); + + if (assetServer) { + auto messageID = ++_currentID; + + auto payload = path.toLatin1(); + auto payloadSize = sizeof(messageID) + payload.size(); + auto packet = NLPacket::create(PacketType::AssetGetMapping, payloadSize, true); + + qCDebug(asset_client) << "Requesting mapping for" << path << "from asset-server."; + + packet->writePrimitive(messageID); + + auto bytesWritten = packet->write(payload); + Q_ASSERT(bytesWritten == payload.size()); + + nodeList->sendPacket(std::move(packet), *assetServer); + + _pendingMappingRequests[assetServer][messageID] = callback; + + return true; + } + + return false; +} + bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback, ProgressCallback progressCallback) { if (hash.length() != SHA256_HASH_HEX_LENGTH) { @@ -220,6 +264,39 @@ bool AssetClient::getAssetInfo(const QString& hash, const QString& extension, Ge return false; } + +void AssetClient::handleAssetGetMappingReply(QSharedPointer message, SharedNodePointer senderNode) { + MessageID messageID; + message->readPrimitive(&messageID); + + AssetServerError error; + message->readPrimitive(&error); + + QString assetHash; + if (error == AssetServerError::NoError) { + assetHash = message->read(SHA256_HASH_LENGTH); + } + + // 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, assetHash); + 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. + } +} + void AssetClient::handleAssetGetInfoReply(QSharedPointer message, SharedNodePointer senderNode) { MessageID messageID; message->readPrimitive(&messageID); diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index f66fe8adcc..cbbf603de6 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -34,6 +34,7 @@ struct AssetInfo { }; using ReceivedAssetCallback = std::function; +using GetMappingCallback = std::function; using GetInfoCallback = std::function; using UploadResultCallback = std::function; using ProgressCallback = std::function; @@ -44,7 +45,7 @@ class AssetClient : public QObject, public Dependency { public: AssetClient(); - Q_INVOKABLE AssetRequest* createRequest(const QString& hash, const QString& extension); + Q_INVOKABLE AssetRequest* createRequest(const QUrl& url); Q_INVOKABLE AssetUpload* createUpload(const QString& filename); Q_INVOKABLE AssetUpload* createUpload(const QByteArray& data, const QString& extension); @@ -55,6 +56,7 @@ public slots: void clearCache(); private slots: + void handleAssetGetMappingReply(QSharedPointer message, SharedNodePointer senderNode); void handleAssetGetInfoReply(QSharedPointer message, SharedNodePointer senderNode); void handleAssetGetReply(QSharedPointer message, SharedNodePointer senderNode); void handleAssetUploadReply(QSharedPointer message, SharedNodePointer senderNode); @@ -62,6 +64,7 @@ private slots: void handleNodeKilled(SharedNodePointer node); private: + bool getAssetMapping(const QString& path, GetMappingCallback 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,6 +76,7 @@ private: }; static MessageID _currentID; + std::unordered_map> _pendingMappingRequests; std::unordered_map> _pendingRequests; std::unordered_map> _pendingInfoRequests; std::unordered_map> _pendingUploads; diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 19f91349fb..505b64e080 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -20,9 +20,8 @@ #include "NodeList.h" #include "ResourceCache.h" -AssetRequest::AssetRequest(const QString& hash, const QString& extension) : - QObject(), - _hash(hash), +AssetRequest::AssetRequest(const QString& url, const QString& extension) : + _url(url), _extension(extension) { } diff --git a/libraries/networking/src/AssetRequest.h b/libraries/networking/src/AssetRequest.h index 3c3459b15d..288caac6df 100644 --- a/libraries/networking/src/AssetRequest.h +++ b/libraries/networking/src/AssetRequest.h @@ -39,7 +39,7 @@ public: UnknownError }; - AssetRequest(const QString& hash, const QString& extension); + AssetRequest(const QString& url, const QString& extension); Q_INVOKABLE void start(); @@ -52,12 +52,15 @@ signals: void finished(AssetRequest* thisRequest); void progress(qint64 totalReceived, qint64 total); +private slots: + void getAssetCallback(bool responseReceived, AssetServerError serverError, const QByteArray& data); + private: State _state = NotStarted; Error _error = NoError; AssetInfo _info; uint64_t _totalReceived { 0 }; - QString _hash; + QString _url; QString _extension; QByteArray _data; int _numPendingRequests { 0 }; diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index dac3329153..0025ba565a 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -23,19 +23,7 @@ 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] : ""; - - if (hash.length() != SHA256_HASH_HEX_LENGTH) { - _result = InvalidURL; - _state = Finished; - - emit finished(); - return; - } - - _assetRequest = assetClient->createRequest(hash, extension); + _assetRequest = assetClient->createRequest(_url); if (!_assetRequest) { _result = ServerUnavailable; diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 0f586018db..3d92aa1285 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -90,7 +90,9 @@ public: DomainServerRemovedNode, MessagesData, MessagesSubscribe, - MessagesUnsubscribe + MessagesUnsubscribe, + AssetGetMapping, + AssetGetMappingReply }; }; From db98e46bb8f3379bff5d938d4b15592c00fcec7b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Mar 2016 16:18:35 -0800 Subject: [PATCH 002/209] Update atp mapping operations to use a single packet --- assignment-client/src/assets/AssetServer.cpp | 58 +++++++++++++++----- assignment-client/src/assets/AssetServer.h | 19 +++++-- libraries/networking/src/AssetClient.cpp | 2 +- libraries/networking/src/AssetClient.h | 6 +- libraries/networking/src/AssetUtils.h | 6 ++ libraries/networking/src/ReceivedMessage.cpp | 9 +++ libraries/networking/src/ReceivedMessage.h | 2 + libraries/networking/src/udt/PacketHeaders.h | 4 +- 8 files changed, 82 insertions(+), 24 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index ab86787769..50723c77c0 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -39,10 +39,10 @@ AssetServer::AssetServer(ReceivedMessage& message) : _taskPool.setMaxThreadCount(TASK_POOL_THREAD_COUNT); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - packetReceiver.registerListener(PacketType::AssetGetMapping, this, "handleAssetGetMapping"); packetReceiver.registerListener(PacketType::AssetGet, this, "handleAssetGet"); packetReceiver.registerListener(PacketType::AssetGetInfo, this, "handleAssetGetInfo"); packetReceiver.registerListener(PacketType::AssetUpload, this, "handleAssetUpload"); + packetReceiver.registerListener(PacketType::AssetMappingOperation, this, "handleAssetMappingOpertation"); } void AssetServer::run() { @@ -163,25 +163,45 @@ void AssetServer::completeSetup() { } -void AssetServer::handleAssetGetMapping(QSharedPointer packet, SharedNodePointer senderNode) { +void AssetServer::handleAssetMappingOperation(QSharedPointer message, SharedNodePointer senderNode) { MessageID messageID; message->readPrimitive(&messageID); - QString assetPath = message->readAll(); - auto replyPacket = NLPacket::create(PacketType::AssetGetMappingReply); + AssetMappingOperationType operationType; + message->readPrimitive(&operationType); + auto replyPacket = NLPacket::create(PacketType::AssetMappingOperationReply); replyPacket->writePrimitive(messageID); - auto it = _fileMapping.find(assetPath.toStdString()); + switch (operationType) { + case AssetMappingOperationType::Get: { + QString assetPath = message->readString(); - if (it != _fileMapping.end()) { - auto assetHash = QString::fromStdString(it.second); - qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; - replyPacket->writePrimitive(AssetServerError::NoError); - replyPacket->write(assetHash.toHex()); - } else { - qDebug() << "Mapping not found for: " << assetPath; - replyPacket->writePrimitive(AssetServerError::AssetNotFound); + 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()); + } + else { + qDebug() << "Mapping not found for: " << assetPath; + replyPacket->writePrimitive(AssetServerError::AssetNotFound); + } + } + case AssetMappingOperationType::Set: { + QString assetPath = message->readString(); + auto assetHash = message->read(SHA256_HASH_LENGTH); + _fileMapping[assetPath] = assetHash; + + replyPacket->writePrimitive(AssetServerError::NoError); + } + case AssetMappingOperationType::Delete: { + QString assetPath = message->readString(); + bool removed = _fileMapping.erase(assetPath) > 0; + + replyPacket->writePrimitive(AssetServerError::NoError); + } } auto nodeList = DependencyManager::get(); @@ -335,3 +355,15 @@ void AssetServer::sendStatsPacket() { // send off the stats packets ThreadedAssignment::addPacketStatsAndSendStatsPacket(serverStats); } + +AssetServer::Hash AssetServer::getMapping(Path path) { + return _fileMapping[path]; +} + +void AssetServer::setMapping(Path path, Hash hash) { + _fileMapping[path] = hash; +} + +bool AssetServer::deleteMapping(Path path) { + return _fileMapping.erase(path) > 0; +} diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 90e1eb8f34..5287c222aa 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -31,19 +31,28 @@ public slots: private slots: void completeSetup(); - void handleAssetGetMapping(QSharedPointer packet, SharedNodePointer senderNode); 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: - static void writeError(NLPacketList* packetList, AssetServerError error); + using Path = QString; + using Hash = QString; + using Mapping = std::unordered_map; - using Path = std::string; - using Hash = std::string; - using Mapping = std::map; + /// Return the hash mapping for Path `path` + Hash getMapping(Path path); + + /// Set the mapping for path to hash + void setMapping(Path path, Hash hash); + + /// Delete mapping `path`. Return `true` if mapping existed, else `false`. + bool deleteMapping(Path path); + + static void writeError(NLPacketList* packetList, AssetServerError error); Mapping _fileMapping; QDir _resourcesDirectory; diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index a61e30a8c1..22671b729d 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -39,7 +39,7 @@ AssetClient::AssetClient() { auto nodeList = DependencyManager::get(); auto& packetReceiver = nodeList->getPacketReceiver(); - packetReceiver.registerListener(PacketType::AssetGetMappingReply, this, "handleAssetGetMappingReply"); + packetReceiver.registerListener(PacketType::AssetMappingOperationReply, this, "handleAssetMappingReply"); packetReceiver.registerListener(PacketType::AssetGetInfoReply, this, "handleAssetGetInfoReply"); packetReceiver.registerListener(PacketType::AssetGetReply, this, "handleAssetGetReply", true); packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply"); diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index cbbf603de6..1b74a47f99 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -34,7 +34,7 @@ struct AssetInfo { }; using ReceivedAssetCallback = std::function; -using GetMappingCallback = std::function; +using MappingOperationCallback = std::function; using GetInfoCallback = std::function; using UploadResultCallback = std::function; using ProgressCallback = std::function; @@ -64,7 +64,7 @@ private slots: void handleNodeKilled(SharedNodePointer node); private: - bool getAssetMapping(const QString& path, GetMappingCallback callback); + bool getAssetMapping(const QString& 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); @@ -76,7 +76,7 @@ private: }; static MessageID _currentID; - std::unordered_map> _pendingMappingRequests; + std::unordered_map> _pendingMappingRequests; std::unordered_map> _pendingRequests; std::unordered_map> _pendingInfoRequests; std::unordered_map> _pendingUploads; diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 21b6b3f434..58e7aa6146 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -32,6 +32,12 @@ enum AssetServerError : uint8_t { PermissionDenied }; +enum AssetMappingOperationType : uint8_t { + Get = 0, + 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..eed275dc1a 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(), 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..b813149bed 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. diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 3d92aa1285..c830978e92 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -91,8 +91,8 @@ public: MessagesData, MessagesSubscribe, MessagesUnsubscribe, - AssetGetMapping, - AssetGetMappingReply + AssetMappingOperation, + AssetMappingOperationReply }; }; From 9148db2612a4b801ba2579b93a03af89bbc4515d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 13:22:23 -0800 Subject: [PATCH 003/209] Clean up AssetServer mapping handling --- assignment-client/src/assets/AssetServer.cpp | 23 +++++++++++++++----- assignment-client/src/assets/AssetServer.h | 15 +++++++------ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 50723c77c0..f685bbe1a9 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -42,7 +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, "handleAssetMappingOpertation"); + packetReceiver.registerListener(PacketType::AssetMappingOperation, this, "handleAssetMappingOperation"); } void AssetServer::run() { @@ -182,25 +182,30 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me auto assetHash = it->second; qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; replyPacket->writePrimitive(AssetServerError::NoError); - replyPacket->write(assetHash.toLatin1().toHex()); + //replyPacket->write(assetHash.toLatin1().toHex()); + replyPacket->writeString(assetHash.toLatin1()); } else { qDebug() << "Mapping not found for: " << assetPath; replyPacket->writePrimitive(AssetServerError::AssetNotFound); } + break; } case AssetMappingOperationType::Set: { QString assetPath = message->readString(); - auto assetHash = message->read(SHA256_HASH_LENGTH); + //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; } } @@ -356,14 +361,20 @@ void AssetServer::sendStatsPacket() { ThreadedAssignment::addPacketStatsAndSendStatsPacket(serverStats); } -AssetServer::Hash AssetServer::getMapping(Path path) { +void AssetServer::loadMappingFromFile() { +} + +void AssetServer::writeMappingToFile() { +} + +AssetHash AssetServer::getMapping(AssetPath path) { return _fileMapping[path]; } -void AssetServer::setMapping(Path path, Hash hash) { +void AssetServer::setMapping(AssetPath path, AssetHash hash) { _fileMapping[path] = hash; } -bool AssetServer::deleteMapping(Path path) { +bool AssetServer::deleteMapping(AssetPath path) { return _fileMapping.erase(path) > 0; } diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 5287c222aa..1eee4feb94 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -39,18 +39,19 @@ private slots: void sendStatsPacket(); private: - using Path = QString; - using Hash = QString; - using Mapping = std::unordered_map; + using Mapping = std::map; - /// Return the hash mapping for Path `path` - Hash getMapping(Path path); + void loadMappingFromFile(); + void writeMappingToFile(); + + /// Return the hash mapping for AssetPath `path` + AssetHash getMapping(AssetPath path); /// Set the mapping for path to hash - void setMapping(Path path, Hash hash); + void setMapping(AssetPath path, AssetHash hash); /// Delete mapping `path`. Return `true` if mapping existed, else `false`. - bool deleteMapping(Path path); + bool deleteMapping(AssetPath path); static void writeError(NLPacketList* packetList, AssetServerError error); From 4e7b63c72e363579a6ebc6bc568fc317f7bd74d6 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 13:23:00 -0800 Subject: [PATCH 004/209] Add get/set mapping request --- libraries/networking/src/AssetClient.cpp | 227 +++++++++++++++-------- 1 file changed, 149 insertions(+), 78 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 22671b729d..f3d677a98a 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -30,6 +30,43 @@ MessageID AssetClient::_currentID = 0; +GetMappingRequest::GetMappingRequest(AssetPath path) : _path(path) { +}; + +void GetMappingRequest::start() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); + return; + } + + auto assetClient = DependencyManager::get(); + assetClient->getAssetMapping(_path, [this](bool responseReceived, AssetServerError error, QSharedPointer message) { + // read message + _error = error; + if (!error) { + //_hash = message->read(SHA256_HASH_HEX_LENGTH); + _hash = message->readString(); + } + emit finished(this); + }); +}; +SetMappingRequest::SetMappingRequest(AssetPath path, AssetHash hash) : _path(path), _hash(hash) { +}; + +void SetMappingRequest::start() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); + return; + } + + auto assetClient = DependencyManager::get(); + assetClient->setAssetMapping(_path, _hash, [this](bool responseReceived, AssetServerError error, QSharedPointer message) { + // read message + _error = error; + emit finished(this); + }); +}; + AssetClient::AssetClient() { @@ -39,7 +76,7 @@ AssetClient::AssetClient() { auto nodeList = DependencyManager::get(); auto& packetReceiver = nodeList->getPacketReceiver(); - packetReceiver.registerListener(PacketType::AssetMappingOperationReply, this, "handleAssetMappingReply"); + 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"); @@ -98,6 +135,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); @@ -111,22 +175,15 @@ bool haveAssetServer() { return true; } -AssetRequest* AssetClient::createRequest(const QUrl& url) { - - auto parts = _url.path().split(".", QString::SkipEmptyParts); - auto hash = parts.length() > 0 ? parts[0] : ""; - auto extension = parts.length() > 1 ? parts[1] : ""; - - if (hash.length() != SHA256_HASH_HEX_LENGTH) { - _result = InvalidURL; - _state = Finished; - - emit finished(); - return; - } - +GetMappingRequest* AssetClient::createGetMappingRequest(const AssetPath& path) { + return new GetMappingRequest(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; @@ -144,8 +201,6 @@ AssetRequest* AssetClient::createRequest(const QUrl& url) { } } - - AssetUpload* AssetClient::createUpload(const QString& filename) { if (haveAssetServer()) { @@ -171,34 +226,34 @@ AssetUpload* AssetClient::createUpload(const QByteArray& data, const QString& ex } } -bool AssetClient::getAssetMapping(const QString& path, GetMappingCallback callback) { - auto nodeList = DependencyManager::get(); - SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); - - if (assetServer) { - auto messageID = ++_currentID; - - auto payload = path.toLatin1(); - auto payloadSize = sizeof(messageID) + payload.size(); - auto packet = NLPacket::create(PacketType::AssetGetMapping, payloadSize, true); - - qCDebug(asset_client) << "Requesting mapping for" << path << "from asset-server."; - - packet->writePrimitive(messageID); - - auto bytesWritten = packet->write(payload); - Q_ASSERT(bytesWritten == payload.size()); - - nodeList->sendPacket(std::move(packet), *assetServer); - - _pendingMappingRequests[assetServer][messageID] = callback; - - return true; - } - - return false; -} - +//bool AssetClient::setAssetMapping(const QString& path, MappingOperationCallback callback) { +// auto nodeList = DependencyManager::get(); +// SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); +// +// if (assetServer) { +// auto messageID = ++_currentID; +// +// auto payload = path.toLatin1(); +// auto payloadSize = sizeof(messageID) + payload.size(); +// auto packet = NLPacket::create(PacketType::AssetMappingOperation, payloadSize, true); +// +// qCDebug(asset_client) << "Requesting mapping for" << path << "from asset-server."; +// +// packet->writePrimitive(messageID); +// +// auto bytesWritten = packet->write(payload); +// Q_ASSERT(bytesWritten == payload.size()); +// +// nodeList->sendPacket(std::move(packet), *assetServer); +// +// _pendingMappingRequests[assetServer][messageID] = callback; +// +// return true; +// } +// +// return false; +//} +// bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback, ProgressCallback progressCallback) { if (hash.length() != SHA256_HASH_HEX_LENGTH) { @@ -264,39 +319,6 @@ bool AssetClient::getAssetInfo(const QString& hash, const QString& extension, Ge return false; } - -void AssetClient::handleAssetGetMappingReply(QSharedPointer message, SharedNodePointer senderNode) { - MessageID messageID; - message->readPrimitive(&messageID); - - AssetServerError error; - message->readPrimitive(&error); - - QString assetHash; - if (error == AssetServerError::NoError) { - assetHash = message->read(SHA256_HASH_LENGTH); - } - - // 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, assetHash); - 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. - } -} - void AssetClient::handleAssetGetInfoReply(QSharedPointer message, SharedNodePointer senderNode) { MessageID messageID; message->readPrimitive(&messageID); @@ -382,6 +404,55 @@ void AssetClient::handleAssetGetReply(QSharedPointer message, S } } +bool AssetClient::getAssetMapping(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::Get); + + packetList->writeString(hash.toUtf8()); + + 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.toUtf8()); + packetList->writeString(hash.toUtf8()); + + 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); From 6dd3b1b4ee642117dd4f49e493d5639b6eeff513 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 13:23:27 -0800 Subject: [PATCH 005/209] Add AssetScriptingInterface methods for mapping --- libraries/networking/src/AssetClient.cpp | 37 ++++++++++++++- libraries/networking/src/AssetClient.h | 60 ++++++++++++++++++++++-- 2 files changed, 92 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index f3d677a98a..93139af2d0 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -619,4 +619,39 @@ 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::getAllMappings(QString path, QScriptValue callback) { +} diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 1b74a47f99..0face50367 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -25,6 +25,8 @@ #include "ReceivedMessage.h" #include "ResourceCache.h" +class GetMappingRequest; +class SetMappingRequest; class AssetRequest; class AssetUpload; @@ -33,19 +35,61 @@ struct AssetInfo { int64_t size; }; +using MappingOperationCallback = std::function message)>; using ReceivedAssetCallback = std::function; -using MappingOperationCallback = std::function; using GetInfoCallback = std::function; using UploadResultCallback = std::function; using ProgressCallback = std::function; +class GetMappingRequest : public QObject { + Q_OBJECT +public: + GetMappingRequest(AssetPath path); + + Q_INVOKABLE void start(); + + AssetHash getHash() { return _hash; } + AssetServerError getError() { return _error; } + +signals: + void finished(GetMappingRequest* thisRequest); + +private: + AssetPath _path; + AssetHash _hash; + AssetServerError _error { AssetServerError::NoError }; +}; + + +class SetMappingRequest : public QObject { + Q_OBJECT +public: + SetMappingRequest(AssetPath path, AssetHash hash); + + Q_INVOKABLE void start(); + + AssetHash getHash() { return _hash; } + AssetServerError getError() { return _error; } + +signals: + void finished(SetMappingRequest* thisRequest); + +private: + AssetPath _path; + AssetHash _hash; + AssetServerError _error { AssetServerError::NoError }; +}; + + class AssetClient : public QObject, public Dependency { Q_OBJECT public: AssetClient(); - Q_INVOKABLE AssetRequest* createRequest(const QUrl& url); + Q_INVOKABLE GetMappingRequest* createGetMappingRequest(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); @@ -56,7 +100,7 @@ public slots: void clearCache(); private slots: - void handleAssetGetMappingReply(QSharedPointer message, SharedNodePointer senderNode); + void handleAssetMappingOperationReply(QSharedPointer message, SharedNodePointer senderNode); void handleAssetGetInfoReply(QSharedPointer message, SharedNodePointer senderNode); void handleAssetGetReply(QSharedPointer message, SharedNodePointer senderNode); void handleAssetUploadReply(QSharedPointer message, SharedNodePointer senderNode); @@ -64,7 +108,10 @@ private slots: void handleNodeKilled(SharedNodePointer node); private: - bool getAssetMapping(const QString& path, MappingOperationCallback callback); + bool getAssetMapping(const AssetHash& hash, MappingOperationCallback callback); + bool setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback); + bool deleteAssetMapping(const AssetHash& hash, 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); @@ -83,6 +130,8 @@ private: friend class AssetRequest; friend class AssetUpload; + friend class GetMappingRequest; + friend class SetMappingRequest; }; @@ -93,6 +142,9 @@ 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 getAllMappings(QString path, QScriptValue callback); protected: QSet _pendingRequests; QScriptEngine* _engine; From 2986aa1937e23203b1db21ce42279b3d6c08230f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 13:23:47 -0800 Subject: [PATCH 006/209] Revert AssetRequest back to using hash --- libraries/networking/src/AssetRequest.cpp | 4 ++-- libraries/networking/src/AssetRequest.h | 8 ++++---- libraries/networking/src/AssetResourceRequest.cpp | 14 +++++++++++++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 505b64e080..0665590902 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -20,8 +20,8 @@ #include "NodeList.h" #include "ResourceCache.h" -AssetRequest::AssetRequest(const QString& url, const QString& extension) : - _url(url), +AssetRequest::AssetRequest(const QString& hash, const QString& extension) : + _hash(hash), _extension(extension) { } diff --git a/libraries/networking/src/AssetRequest.h b/libraries/networking/src/AssetRequest.h index 288caac6df..049ab19ef4 100644 --- a/libraries/networking/src/AssetRequest.h +++ b/libraries/networking/src/AssetRequest.h @@ -39,7 +39,7 @@ public: UnknownError }; - AssetRequest(const QString& url, const QString& extension); + AssetRequest(const QString& hash, const QString& extension); Q_INVOKABLE void start(); @@ -52,15 +52,15 @@ signals: void finished(AssetRequest* thisRequest); void progress(qint64 totalReceived, qint64 total); -private slots: - void getAssetCallback(bool responseReceived, AssetServerError serverError, const QByteArray& data); +//private slots: + //void getAssetCallback(bool responseReceived, AssetServerError serverError, const QByteArray& data); private: State _state = NotStarted; Error _error = NoError; AssetInfo _info; uint64_t _totalReceived { 0 }; - QString _url; + QString _hash; QString _extension; QByteArray _data; int _numPendingRequests { 0 }; diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 0025ba565a..92a804d421 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -21,9 +21,21 @@ AssetResourceRequest::~AssetResourceRequest() { } void AssetResourceRequest::doSend() { + auto parts = _url.path().split(".", QString::SkipEmptyParts); + auto hash = parts.length() > 0 ? parts[0] : ""; + auto extension = parts.length() > 1 ? parts[1] : ""; + + if (hash.length() != SHA256_HASH_HEX_LENGTH) { + _result = InvalidURL; + _state = Finished; + + emit finished(); + return; + } + // Make request to atp auto assetClient = DependencyManager::get(); - _assetRequest = assetClient->createRequest(_url); + _assetRequest = assetClient->createRequest(hash, extension); if (!_assetRequest) { _result = ServerUnavailable; From 292bc12f3740d8ca76bd0633b538204cb46addfa Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 13:24:12 -0800 Subject: [PATCH 007/209] Add read/writeString to PacketList and Packet --- libraries/networking/src/AssetUtils.h | 3 +++ libraries/networking/src/ReceivedMessage.cpp | 4 ++-- libraries/networking/src/ReceivedMessage.h | 1 - libraries/networking/src/udt/BasePacket.cpp | 14 ++++++++++++++ libraries/networking/src/udt/BasePacket.h | 5 ++++- libraries/networking/src/udt/PacketList.cpp | 6 ++++++ libraries/networking/src/udt/PacketList.h | 2 ++ 7 files changed, 31 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 58e7aa6146..f13c9ac729 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -20,6 +20,9 @@ using MessageID = uint32_t; using DataOffset = int64_t; +using AssetPath = QString; +using AssetHash = QString; + 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 diff --git a/libraries/networking/src/ReceivedMessage.cpp b/libraries/networking/src/ReceivedMessage.cpp index eed275dc1a..6ef2b7c7d4 100644 --- a/libraries/networking/src/ReceivedMessage.cpp +++ b/libraries/networking/src/ReceivedMessage.cpp @@ -110,8 +110,8 @@ QByteArray ReceivedMessage::readAll() { QString ReceivedMessage::readString() { uint32_t size; readPrimitive(&size); - Q_ASSERT(size <= _size - _position); - auto string = QString::fromUtf8(_data.constData(), size); + //Q_ASSERT(size <= _size - _position); + auto string = QString::fromUtf8(_data.constData() + _position, size); _position += size; return string; } diff --git a/libraries/networking/src/ReceivedMessage.h b/libraries/networking/src/ReceivedMessage.h index b813149bed..e9131c074f 100644 --- a/libraries/networking/src/ReceivedMessage.h +++ b/libraries/networking/src/ReceivedMessage.h @@ -88,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..e0b2a8ba3a 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/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); From 6b485cf81d4bd851267b3460cbc257a4043f8e1d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Mar 2016 16:18:35 -0800 Subject: [PATCH 008/209] Update atp mapping operations to use a single packet --- assignment-client/src/assets/AssetServer.cpp | 59 ++++++++++++++++++++ assignment-client/src/assets/AssetServer.h | 16 ++++++ libraries/networking/src/AssetClient.cpp | 4 +- libraries/networking/src/AssetClient.h | 3 + libraries/networking/src/AssetUtils.h | 6 ++ libraries/networking/src/ReceivedMessage.cpp | 9 +++ libraries/networking/src/ReceivedMessage.h | 2 + libraries/networking/src/udt/PacketHeaders.h | 4 +- 8 files changed, 101 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 4ca2439996..84a3feaabc 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, "handleAssetMappingOpertation"); } void AssetServer::run() { @@ -161,6 +162,52 @@ 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 = NLPacket::create(PacketType::AssetMappingOperationReply); + 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()); + } + else { + qDebug() << "Mapping not found for: " << assetPath; + replyPacket->writePrimitive(AssetServerError::AssetNotFound); + } + } + case AssetMappingOperationType::Set: { + QString assetPath = message->readString(); + auto assetHash = message->read(SHA256_HASH_LENGTH); + _fileMapping[assetPath] = assetHash; + + replyPacket->writePrimitive(AssetServerError::NoError); + } + case AssetMappingOperationType::Delete: { + QString assetPath = message->readString(); + bool removed = _fileMapping.erase(assetPath) > 0; + + replyPacket->writePrimitive(AssetServerError::NoError); + } + } + + auto nodeList = DependencyManager::get(); + nodeList->sendPacket(std::move(replyPacket), *senderNode); +} + +>>>>>>> db98e46... Update atp mapping operations to use a single packet void AssetServer::handleAssetGetInfo(QSharedPointer message, SharedNodePointer senderNode) { QByteArray assetHash; MessageID messageID; @@ -308,3 +355,15 @@ void AssetServer::sendStatsPacket() { // send off the stats packets ThreadedAssignment::addPacketStatsAndSendStatsPacket(serverStats); } + +AssetServer::Hash AssetServer::getMapping(Path path) { + return _fileMapping[path]; +} + +void AssetServer::setMapping(Path path, Hash hash) { + _fileMapping[path] = hash; +} + +bool AssetServer::deleteMapping(Path path) { + return _fileMapping.erase(path) > 0; +} diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 7d6e26af08..5287c222aa 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -34,11 +34,27 @@ 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: + using Path = QString; + using Hash = QString; + using Mapping = std::unordered_map; + + /// Return the hash mapping for Path `path` + Hash getMapping(Path path); + + /// Set the mapping for path to hash + void setMapping(Path path, Hash hash); + + /// Delete mapping `path`. Return `true` if mapping existed, else `false`. + bool deleteMapping(Path path); + static void writeError(NLPacketList* packetList, AssetServerError error); + + Mapping _fileMapping; QDir _resourcesDirectory; QThreadPool _taskPool; }; diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 9591828fef..d658855e1f 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -39,6 +39,8 @@ AssetClient::AssetClient() { auto nodeList = DependencyManager::get(); auto& packetReceiver = nodeList->getPacketReceiver(); + + packetReceiver.registerListener(PacketType::AssetMappingOperationReply, this, "handleAssetMappingReply"); packetReceiver.registerListener(PacketType::AssetGetInfoReply, this, "handleAssetGetInfoReply"); packetReceiver.registerListener(PacketType::AssetGetReply, this, "handleAssetGetReply", true); packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply"); @@ -471,4 +473,4 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb }); assetRequest->start(); -} \ No newline at end of file +} diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index f66fe8adcc..16bd0a4e04 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -34,6 +34,7 @@ struct AssetInfo { }; using ReceivedAssetCallback = std::function; +using MappingOperationCallback = std::function; using GetInfoCallback = std::function; using UploadResultCallback = std::function; using ProgressCallback = std::function; @@ -62,6 +63,7 @@ private slots: void handleNodeKilled(SharedNodePointer node); private: + bool getAssetMapping(const QString& 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,6 +75,7 @@ private: }; static MessageID _currentID; + std::unordered_map> _pendingMappingRequests; std::unordered_map> _pendingRequests; std::unordered_map> _pendingInfoRequests; std::unordered_map> _pendingUploads; diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 21b6b3f434..58e7aa6146 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -32,6 +32,12 @@ enum AssetServerError : uint8_t { PermissionDenied }; +enum AssetMappingOperationType : uint8_t { + Get = 0, + 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..eed275dc1a 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(), 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..b813149bed 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. 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 }; }; From 9eb0fdf589aee092138e02af51e8be2f46a9a0aa Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 13:22:23 -0800 Subject: [PATCH 009/209] Clean up AssetServer mapping handling --- assignment-client/src/assets/AssetServer.cpp | 23 +++++++++++++++----- assignment-client/src/assets/AssetServer.h | 15 +++++++------ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 84a3feaabc..dbee3cd547 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -42,7 +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, "handleAssetMappingOpertation"); + packetReceiver.registerListener(PacketType::AssetMappingOperation, this, "handleAssetMappingOperation"); } void AssetServer::run() { @@ -181,25 +181,30 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me auto assetHash = it->second; qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; replyPacket->writePrimitive(AssetServerError::NoError); - replyPacket->write(assetHash.toLatin1().toHex()); + //replyPacket->write(assetHash.toLatin1().toHex()); + replyPacket->writeString(assetHash.toLatin1()); } else { qDebug() << "Mapping not found for: " << assetPath; replyPacket->writePrimitive(AssetServerError::AssetNotFound); } + break; } case AssetMappingOperationType::Set: { QString assetPath = message->readString(); - auto assetHash = message->read(SHA256_HASH_LENGTH); + //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; } } @@ -356,14 +361,20 @@ void AssetServer::sendStatsPacket() { ThreadedAssignment::addPacketStatsAndSendStatsPacket(serverStats); } -AssetServer::Hash AssetServer::getMapping(Path path) { +void AssetServer::loadMappingFromFile() { +} + +void AssetServer::writeMappingToFile() { +} + +AssetHash AssetServer::getMapping(AssetPath path) { return _fileMapping[path]; } -void AssetServer::setMapping(Path path, Hash hash) { +void AssetServer::setMapping(AssetPath path, AssetHash hash) { _fileMapping[path] = hash; } -bool AssetServer::deleteMapping(Path path) { +bool AssetServer::deleteMapping(AssetPath path) { return _fileMapping.erase(path) > 0; } diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 5287c222aa..1eee4feb94 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -39,18 +39,19 @@ private slots: void sendStatsPacket(); private: - using Path = QString; - using Hash = QString; - using Mapping = std::unordered_map; + using Mapping = std::map; - /// Return the hash mapping for Path `path` - Hash getMapping(Path path); + void loadMappingFromFile(); + void writeMappingToFile(); + + /// Return the hash mapping for AssetPath `path` + AssetHash getMapping(AssetPath path); /// Set the mapping for path to hash - void setMapping(Path path, Hash hash); + void setMapping(AssetPath path, AssetHash hash); /// Delete mapping `path`. Return `true` if mapping existed, else `false`. - bool deleteMapping(Path path); + bool deleteMapping(AssetPath path); static void writeError(NLPacketList* packetList, AssetServerError error); From 462f00077c39b3f4262e6c55d1798b31630d58cc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 13:23:00 -0800 Subject: [PATCH 010/209] Add get/set mapping request --- libraries/networking/src/AssetClient.cpp | 156 ++++++++++++++++++++++- 1 file changed, 152 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index d658855e1f..91d35701bf 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -30,6 +30,43 @@ MessageID AssetClient::_currentID = 0; +GetMappingRequest::GetMappingRequest(AssetPath path) : _path(path) { +}; + +void GetMappingRequest::start() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); + return; + } + + auto assetClient = DependencyManager::get(); + assetClient->getAssetMapping(_path, [this](bool responseReceived, AssetServerError error, QSharedPointer message) { + // read message + _error = error; + if (!error) { + //_hash = message->read(SHA256_HASH_HEX_LENGTH); + _hash = message->readString(); + } + emit finished(this); + }); +}; +SetMappingRequest::SetMappingRequest(AssetPath path, AssetHash hash) : _path(path), _hash(hash) { +}; + +void SetMappingRequest::start() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); + return; + } + + auto assetClient = DependencyManager::get(); + assetClient->setAssetMapping(_path, _hash, [this](bool responseReceived, AssetServerError error, QSharedPointer message) { + // read message + _error = error; + emit finished(this); + }); +}; + AssetClient::AssetClient() { @@ -40,7 +77,7 @@ AssetClient::AssetClient() { auto nodeList = DependencyManager::get(); auto& packetReceiver = nodeList->getPacketReceiver(); - packetReceiver.registerListener(PacketType::AssetMappingOperationReply, this, "handleAssetMappingReply"); + 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"); @@ -99,6 +136,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); @@ -112,7 +176,15 @@ bool haveAssetServer() { return true; } -AssetRequest* AssetClient::createRequest(const QString& hash, const QString& extension) { +GetMappingRequest* AssetClient::createGetMappingRequest(const AssetPath& path) { + return new GetMappingRequest(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; @@ -130,8 +202,6 @@ AssetRequest* AssetClient::createRequest(const QString& hash, const QString& ext } } - - AssetUpload* AssetClient::createUpload(const QString& filename) { if (haveAssetServer()) { @@ -157,6 +227,35 @@ AssetUpload* AssetClient::createUpload(const QByteArray& data, const QString& ex } } +//bool AssetClient::setAssetMapping(const QString& path, MappingOperationCallback callback) { +// auto nodeList = DependencyManager::get(); +// SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); +// +// if (assetServer) { +// auto messageID = ++_currentID; +// +// auto payload = path.toLatin1(); +// auto payloadSize = sizeof(messageID) + payload.size(); +// auto packet = NLPacket::create(PacketType::AssetMappingOperation, payloadSize, true); +// +// qCDebug(asset_client) << "Requesting mapping for" << path << "from asset-server."; +// +// packet->writePrimitive(messageID); +// +// auto bytesWritten = packet->write(payload); +// Q_ASSERT(bytesWritten == payload.size()); +// +// nodeList->sendPacket(std::move(packet), *assetServer); +// +// _pendingMappingRequests[assetServer][messageID] = callback; +// +// return true; +// } +// +// return false; +//} +// + bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback, ProgressCallback progressCallback) { if (hash.length() != SHA256_HASH_HEX_LENGTH) { @@ -307,6 +406,55 @@ void AssetClient::handleAssetGetReply(QSharedPointer message, S } } +bool AssetClient::getAssetMapping(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::Get); + + packetList->writeString(hash.toUtf8()); + + 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.toUtf8()); + packetList->writeString(hash.toUtf8()); + + 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); From 7dd436a7a81afe7a873f3f04d561569b362c61f6 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 13:23:27 -0800 Subject: [PATCH 011/209] Add AssetScriptingInterface methods for mapping --- libraries/networking/src/AssetClient.cpp | 36 +++++++++++++++ libraries/networking/src/AssetClient.h | 59 ++++++++++++++++++++++-- 2 files changed, 92 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 91d35701bf..472cbaab6e 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -622,3 +622,39 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb 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::getAllMappings(QString path, QScriptValue callback) { +} +>>>>>>> 6dd3b1b... Add AssetScriptingInterface methods for mapping diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 16bd0a4e04..0face50367 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -25,6 +25,8 @@ #include "ReceivedMessage.h" #include "ResourceCache.h" +class GetMappingRequest; +class SetMappingRequest; class AssetRequest; class AssetUpload; @@ -33,19 +35,61 @@ struct AssetInfo { int64_t size; }; +using MappingOperationCallback = std::function message)>; using ReceivedAssetCallback = std::function; -using MappingOperationCallback = std::function; using GetInfoCallback = std::function; using UploadResultCallback = std::function; using ProgressCallback = std::function; +class GetMappingRequest : public QObject { + Q_OBJECT +public: + GetMappingRequest(AssetPath path); + + Q_INVOKABLE void start(); + + AssetHash getHash() { return _hash; } + AssetServerError getError() { return _error; } + +signals: + void finished(GetMappingRequest* thisRequest); + +private: + AssetPath _path; + AssetHash _hash; + AssetServerError _error { AssetServerError::NoError }; +}; + + +class SetMappingRequest : public QObject { + Q_OBJECT +public: + SetMappingRequest(AssetPath path, AssetHash hash); + + Q_INVOKABLE void start(); + + AssetHash getHash() { return _hash; } + AssetServerError getError() { return _error; } + +signals: + void finished(SetMappingRequest* thisRequest); + +private: + AssetPath _path; + AssetHash _hash; + AssetServerError _error { AssetServerError::NoError }; +}; + + 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 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); @@ -56,6 +100,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); @@ -63,7 +108,10 @@ private slots: void handleNodeKilled(SharedNodePointer node); private: - bool getAssetMapping(const QString& path, MappingOperationCallback callback); + bool getAssetMapping(const AssetHash& hash, MappingOperationCallback callback); + bool setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback); + bool deleteAssetMapping(const AssetHash& hash, 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); @@ -82,6 +130,8 @@ private: friend class AssetRequest; friend class AssetUpload; + friend class GetMappingRequest; + friend class SetMappingRequest; }; @@ -92,6 +142,9 @@ 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 getAllMappings(QString path, QScriptValue callback); protected: QSet _pendingRequests; QScriptEngine* _engine; From 7317d3b2ea8de77baf8ee4e9be18d8fa56531912 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 13:23:47 -0800 Subject: [PATCH 012/209] Revert AssetRequest back to using hash --- libraries/networking/src/AssetRequest.cpp | 1 - libraries/networking/src/AssetRequest.h | 3 +++ libraries/networking/src/AssetResourceRequest.cpp | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) 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/AssetRequest.h b/libraries/networking/src/AssetRequest.h index 3c3459b15d..049ab19ef4 100644 --- a/libraries/networking/src/AssetRequest.h +++ b/libraries/networking/src/AssetRequest.h @@ -52,6 +52,9 @@ signals: void finished(AssetRequest* thisRequest); void progress(qint64 totalReceived, qint64 total); +//private slots: + //void getAssetCallback(bool responseReceived, AssetServerError serverError, const QByteArray& data); + private: State _state = NotStarted; Error _error = NoError; 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) { From 19cd352a77aa1b979407f39f89bb5b0fedd389b2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 13:24:12 -0800 Subject: [PATCH 013/209] Add read/writeString to PacketList and Packet --- libraries/networking/src/AssetUtils.h | 3 +++ libraries/networking/src/ReceivedMessage.cpp | 4 ++-- libraries/networking/src/ReceivedMessage.h | 1 - libraries/networking/src/udt/BasePacket.cpp | 14 ++++++++++++++ libraries/networking/src/udt/BasePacket.h | 5 ++++- libraries/networking/src/udt/PacketList.cpp | 6 ++++++ libraries/networking/src/udt/PacketList.h | 2 ++ 7 files changed, 31 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 58e7aa6146..f13c9ac729 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -20,6 +20,9 @@ using MessageID = uint32_t; using DataOffset = int64_t; +using AssetPath = QString; +using AssetHash = QString; + 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 diff --git a/libraries/networking/src/ReceivedMessage.cpp b/libraries/networking/src/ReceivedMessage.cpp index eed275dc1a..6ef2b7c7d4 100644 --- a/libraries/networking/src/ReceivedMessage.cpp +++ b/libraries/networking/src/ReceivedMessage.cpp @@ -110,8 +110,8 @@ QByteArray ReceivedMessage::readAll() { QString ReceivedMessage::readString() { uint32_t size; readPrimitive(&size); - Q_ASSERT(size <= _size - _position); - auto string = QString::fromUtf8(_data.constData(), size); + //Q_ASSERT(size <= _size - _position); + auto string = QString::fromUtf8(_data.constData() + _position, size); _position += size; return string; } diff --git a/libraries/networking/src/ReceivedMessage.h b/libraries/networking/src/ReceivedMessage.h index b813149bed..e9131c074f 100644 --- a/libraries/networking/src/ReceivedMessage.h +++ b/libraries/networking/src/ReceivedMessage.h @@ -88,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..e0b2a8ba3a 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/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); From 267ed3af822bbd33d8d2071ce4fd9b723431cc2c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 11:56:00 -0800 Subject: [PATCH 014/209] remove client side handling of extension for ATP hash URLs --- interface/src/assets/ATPAssetMigrator.cpp | 2 +- libraries/networking/src/AssetClient.cpp | 50 +++---------------- libraries/networking/src/AssetClient.h | 6 +-- libraries/networking/src/AssetRequest.cpp | 9 ++-- libraries/networking/src/AssetRequest.h | 5 +- .../networking/src/AssetResourceRequest.cpp | 36 +++++++++++-- libraries/networking/src/AssetUpload.cpp | 2 +- libraries/networking/src/AssetUtils.cpp | 8 +-- libraries/networking/src/AssetUtils.h | 2 +- .../networking/src/udt/PacketHeaders.cpp | 4 ++ 10 files changed, 57 insertions(+), 67 deletions(-) diff --git a/interface/src/assets/ATPAssetMigrator.cpp b/interface/src/assets/ATPAssetMigrator.cpp index f037cf9f91..dba2047da1 100644 --- a/interface/src/assets/ATPAssetMigrator.cpp +++ b/interface/src/assets/ATPAssetMigrator.cpp @@ -173,7 +173,7 @@ void ATPAssetMigrator::assetUploadFinished(AssetUpload *upload, const QString& h auto values = _pendingReplacements.values(modelURL); - QString atpURL = getATPUrl(hash, upload->getExtension()).toString(); + QString atpURL = getATPUrl(hash).toString(); for (auto value : values) { // replace the modelURL in this QJsonValueRef with the hash diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 472cbaab6e..51c5ae8cb3 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -184,14 +184,14 @@ SetMappingRequest* AssetClient::createSetMappingRequest(const AssetPath& path, c return new SetMappingRequest(path, hash); } -AssetRequest* AssetClient::createRequest(const AssetHash& hash, const QString& extension) { +AssetRequest* AssetClient::createRequest(const AssetHash& hash) { if (hash.length() != SHA256_HASH_HEX_LENGTH) { qCWarning(asset_client) << "Invalid hash size"; return nullptr; } if (haveAssetServer()) { - auto request = new AssetRequest(hash, extension); + auto request = new AssetRequest(hash); // Move to the AssetClient thread in case we are not currently on that thread (which will usually be the case) request->moveToThread(thread()); @@ -227,36 +227,7 @@ AssetUpload* AssetClient::createUpload(const QByteArray& data, const QString& ex } } -//bool AssetClient::setAssetMapping(const QString& path, MappingOperationCallback callback) { -// auto nodeList = DependencyManager::get(); -// SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); -// -// if (assetServer) { -// auto messageID = ++_currentID; -// -// auto payload = path.toLatin1(); -// auto payloadSize = sizeof(messageID) + payload.size(); -// auto packet = NLPacket::create(PacketType::AssetMappingOperation, payloadSize, true); -// -// qCDebug(asset_client) << "Requesting mapping for" << path << "from asset-server."; -// -// packet->writePrimitive(messageID); -// -// auto bytesWritten = packet->write(payload); -// Q_ASSERT(bytesWritten == payload.size()); -// -// nodeList->sendPacket(std::move(packet), *assetServer); -// -// _pendingMappingRequests[assetServer][messageID] = callback; -// -// return true; -// } -// -// return false; -//} -// - -bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, +bool AssetClient::getAsset(const QString& hash, DataOffset start, DataOffset end, ReceivedAssetCallback callback, ProgressCallback progressCallback) { if (hash.length() != SHA256_HASH_HEX_LENGTH) { qCWarning(asset_client) << "Invalid hash size"; @@ -270,8 +241,7 @@ bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOf auto messageID = ++_currentID; - auto payloadSize = sizeof(messageID) + SHA256_HASH_LENGTH + sizeof(uint8_t) + extension.length() - + sizeof(start) + sizeof(end); + auto payloadSize = sizeof(messageID) + SHA256_HASH_LENGTH + sizeof(start) + sizeof(end); auto packet = NLPacket::create(PacketType::AssetGet, payloadSize, true); qCDebug(asset_client) << "Requesting data from" << start << "to" << end << "of" << hash << "from asset-server."; @@ -280,9 +250,6 @@ bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOf packet->write(QByteArray::fromHex(hash.toLatin1())); - packet->writePrimitive(uint8_t(extension.length())); - packet->write(extension.toLatin1()); - packet->writePrimitive(start); packet->writePrimitive(end); @@ -296,20 +263,18 @@ bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOf return false; } -bool AssetClient::getAssetInfo(const QString& hash, const QString& extension, GetInfoCallback callback) { +bool AssetClient::getAssetInfo(const QString& hash, GetInfoCallback callback) { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); if (assetServer) { auto messageID = ++_currentID; - auto payloadSize = sizeof(messageID) + SHA256_HASH_LENGTH + sizeof(uint8_t) + extension.length(); + auto payloadSize = sizeof(messageID) + SHA256_HASH_LENGTH; auto packet = NLPacket::create(PacketType::AssetGetInfo, payloadSize, true); packet->writePrimitive(messageID); packet->write(QByteArray::fromHex(hash.toLatin1())); - packet->writePrimitive(uint8_t(extension.length())); - packet->write(extension.toLatin1()); nodeList->sendPacket(std::move(packet), *assetServer); @@ -590,14 +555,13 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb auto path = urlString.right(urlString.length() - ATP_SCHEME.length()); auto parts = path.split(".", QString::SkipEmptyParts); auto hash = parts.length() > 0 ? parts[0] : ""; - auto extension = parts.length() > 1 ? parts[1] : ""; if (hash.length() != SHA256_HASH_HEX_LENGTH) { return; } auto assetClient = DependencyManager::get(); - auto assetRequest = assetClient->createRequest(hash, extension); + auto assetRequest = assetClient->createRequest(hash); if (!assetRequest) { return; diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 0face50367..60a6815a53 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -89,7 +89,7 @@ public: Q_INVOKABLE GetMappingRequest* createGetMappingRequest(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 AssetRequest* createRequest(const AssetHash& hash); Q_INVOKABLE AssetUpload* createUpload(const QString& filename); Q_INVOKABLE AssetUpload* createUpload(const QByteArray& data, const QString& extension); @@ -112,8 +112,8 @@ private: bool setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback); bool deleteAssetMapping(const AssetHash& hash, MappingOperationCallback callback); - bool getAssetInfo(const QString& hash, const QString& extension, GetInfoCallback callback); - bool getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, + bool getAssetInfo(const QString& hash, GetInfoCallback callback); + bool getAsset(const QString& hash, DataOffset start, DataOffset end, ReceivedAssetCallback callback, ProgressCallback progressCallback); bool uploadAsset(const QByteArray& data, const QString& extension, UploadResultCallback callback); diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 0665590902..f2e347e0f7 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -20,9 +20,8 @@ #include "NodeList.h" #include "ResourceCache.h" -AssetRequest::AssetRequest(const QString& hash, const QString& extension) : - _hash(hash), - _extension(extension) +AssetRequest::AssetRequest(const QString& hash) : + _hash(hash) { } @@ -52,7 +51,7 @@ void AssetRequest::start() { _state = WaitingForInfo; auto assetClient = DependencyManager::get(); - assetClient->getAssetInfo(_hash, _extension, [this](bool responseReceived, AssetServerError serverError, AssetInfo info) { + assetClient->getAssetInfo(_hash, [this](bool responseReceived, AssetServerError serverError, AssetInfo info) { _info = info; if (!responseReceived) { @@ -84,7 +83,7 @@ void AssetRequest::start() { int start = 0, end = _info.size; auto assetClient = DependencyManager::get(); - assetClient->getAsset(_hash, _extension, start, end, [this, start, end](bool responseReceived, AssetServerError serverError, + assetClient->getAsset(_hash, start, end, [this, start, end](bool responseReceived, AssetServerError serverError, const QByteArray& data) { if (!responseReceived) { _error = NetworkError; diff --git a/libraries/networking/src/AssetRequest.h b/libraries/networking/src/AssetRequest.h index 049ab19ef4..4c35a46fe7 100644 --- a/libraries/networking/src/AssetRequest.h +++ b/libraries/networking/src/AssetRequest.h @@ -39,14 +39,14 @@ public: UnknownError }; - AssetRequest(const QString& hash, const QString& extension); + AssetRequest(const QString& hash); Q_INVOKABLE void start(); const QByteArray& getData() const { return _data; } const State& getState() const { return _state; } const Error& getError() const { return _error; } - QUrl getUrl() const { return ::getATPUrl(_hash, _extension); } + QUrl getUrl() const { return ::getATPUrl(_hash); } signals: void finished(AssetRequest* thisRequest); @@ -61,7 +61,6 @@ private: AssetInfo _info; uint64_t _totalReceived { 0 }; QString _hash; - QString _extension; QByteArray _data; int _numPendingRequests { 0 }; }; diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 92a804d421..07fc5920ee 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -20,14 +20,42 @@ AssetResourceRequest::~AssetResourceRequest() { } } +bool AssetResourceRequest::urlIsAssetPath() const { + static const QString ATP_HASH_REGEX_STRING = "^atp:([A-Fa-f0-9]{64})(\\.[\\w]+)?$"; + + QRegExp hashRegex { ATP_HASH_REGEX_STRING }; + return !hashRegex.exactMatch(_url.toString()); +} + void AssetResourceRequest::doSend() { auto parts = _url.path().split(".", QString::SkipEmptyParts); auto hash = parts.length() > 0 ? parts[0] : ""; auto extension = parts.length() > 1 ? parts[1] : ""; - if (hash.length() != SHA256_HASH_HEX_LENGTH) { - _result = InvalidURL; - _state = Finished; + // We'll either have a hash or an ATP path to a file (that maps to a hash) + + if (urlIsAssetPath()) { + // This is an ATP path, we'll need to figure out what the mapping is. + // This may incur a roundtrip to the asset-server, or it may return immediately from the cache in AssetClient. + + qDebug() << "Detected an asset path! URL is" << _url; + } else { + + qDebug() << "ATP URL was not an asset path - url is" << _url.toString(); + + // We've detected that this is a hash - simply use AssetClient to request that asset + auto parts = _url.path().split(".", QString::SkipEmptyParts); + auto hash = parts.length() > 0 ? parts[0] : ""; + auto extension = parts.length() > 1 ? parts[1] : ""; + + // in case we haven't parsed a valid hash, return an error now + if (hash.length() != SHA256_HASH_HEX_LENGTH) { + _result = InvalidURL; + _state = Finished; + + emit finished(); + return; + } emit finished(); return; @@ -35,7 +63,7 @@ void AssetResourceRequest::doSend() { // Make request to atp auto assetClient = DependencyManager::get(); - _assetRequest = assetClient->createRequest(hash, extension); + _assetRequest = assetClient->createRequest(hash); if (!_assetRequest) { _result = ServerUnavailable; diff --git a/libraries/networking/src/AssetUpload.cpp b/libraries/networking/src/AssetUpload.cpp index 2d6f0c0e97..1189c341b1 100644 --- a/libraries/networking/src/AssetUpload.cpp +++ b/libraries/networking/src/AssetUpload.cpp @@ -103,7 +103,7 @@ void AssetUpload::start() { } if (_error == NoError && hash == hashData(_data).toHex()) { - saveToCache(getATPUrl(hash, _extension), _data); + saveToCache(getATPUrl(hash), _data); } emit finished(this, hash); diff --git a/libraries/networking/src/AssetUtils.cpp b/libraries/networking/src/AssetUtils.cpp index f37e0af820..cf1bdbe8f2 100644 --- a/libraries/networking/src/AssetUtils.cpp +++ b/libraries/networking/src/AssetUtils.cpp @@ -19,12 +19,8 @@ #include "ResourceManager.h" -QUrl getATPUrl(const QString& hash, const QString& extension) { - if (!extension.isEmpty()) { - return QUrl(QString("%1:%2.%3").arg(URL_SCHEME_ATP, hash, extension)); - } else { - return QUrl(QString("%1:%2").arg(URL_SCHEME_ATP, hash)); - } +QUrl getATPUrl(const QString& hash) { + return QUrl(QString("%1:%2").arg(URL_SCHEME_ATP, hash)); } QByteArray hashData(const QByteArray& data) { diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index f13c9ac729..cc9aa60407 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -41,7 +41,7 @@ enum AssetMappingOperationType : uint8_t { Delete }; -QUrl getATPUrl(const QString& hash, const QString& extension = QString()); +QUrl getATPUrl(const QString& hash); QByteArray hashData(const QByteArray& data); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 3ffbb867bf..2c53e01b2a 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -53,6 +53,10 @@ PacketVersion versionForPacketType(PacketType packetType) { return static_cast(AvatarMixerPacketVersion::SoftAttachmentSupport); case PacketType::ICEServerHeartbeat: return 18; // ICE Server Heartbeat signing + case PacketType::AssetGetInfo: + case PacketType::AssetGet: + // Introduction of ATP Mappings + return 18; default: return 17; } From e7124d4b10e6b864bbb67f2d31e5bcd874e2dec2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 12:15:22 -0800 Subject: [PATCH 015/209] add server handling for no extension requests --- assignment-client/src/assets/AssetServer.cpp | 40 +++++-------------- .../src/assets/SendAssetTask.cpp | 5 +-- 2 files changed, 10 insertions(+), 35 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index dbee3cd547..15dfb95551 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -130,34 +130,15 @@ void AssetServer::completeSetup() { } } - qDebug() << "Serving files from: " << _resourcesDirectory.path(); + qInfo() << "Serving files from: " << _resourcesDirectory.path(); - // Scan for new files - qDebug() << "Looking for new files in asset directory"; - auto files = _resourcesDirectory.entryInfoList(QDir::Files); - QRegExp filenameRegex { "^[a-f0-9]{" + QString::number(SHA256_HASH_HEX_LENGTH) + "}(\\..+)?$" }; - for (const auto& fileInfo : files) { - auto filename = fileInfo.fileName(); - if (!filenameRegex.exactMatch(filename)) { - qDebug() << "Found file: " << filename; - if (!fileInfo.isReadable()) { - qDebug() << "\tCan't open file for reading: " << filename; - continue; - } + // Check the asset directory to output some information about what we have + auto files = _resourcesDirectory.entryList(QDir::Files); - // Read file - QFile file { fileInfo.absoluteFilePath() }; - file.open(QFile::ReadOnly); - QByteArray data = file.readAll(); + QRegExp hashFileRegex { "^[a-f0-9]{" + QString::number(SHA256_HASH_HEX_LENGTH) + "}$" }; + auto hashedFiles = files.filter(hashFileRegex); - auto hash = hashData(data); - auto hexHash = hash.toHex(); - - qDebug() << "\tMoving " << filename << " to " << hexHash; - - file.rename(_resourcesDirectory.absoluteFilePath(hexHash) + "." + fileInfo.suffix()); - } - } + qInfo() << "There are" << hashedFiles.size() << "asset files in the asset directory."; nodeList->addNodeTypeToInterestSet(NodeType::Agent); } @@ -216,17 +197,14 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me void AssetServer::handleAssetGetInfo(QSharedPointer message, SharedNodePointer senderNode) { QByteArray assetHash; MessageID messageID; - uint8_t extensionLength; - if (message->getSize() < qint64(SHA256_HASH_LENGTH + sizeof(messageID) + sizeof(extensionLength))) { + if (message->getSize() < qint64(SHA256_HASH_LENGTH + sizeof(messageID))) { qDebug() << "ERROR bad file request"; return; } message->readPrimitive(&messageID); assetHash = message->readWithoutCopy(SHA256_HASH_LENGTH); - message->readPrimitive(&extensionLength); - QByteArray extension = message->read(extensionLength); auto replyPacket = NLPacket::create(PacketType::AssetGetInfoReply); @@ -235,7 +213,7 @@ void AssetServer::handleAssetGetInfo(QSharedPointer message, Sh replyPacket->writePrimitive(messageID); replyPacket->write(assetHash); - QString fileName = QString(hexHash) + "." + extension; + QString fileName = QString(hexHash); QFileInfo fileInfo { _resourcesDirectory.filePath(fileName) }; if (fileInfo.exists() && fileInfo.isReadable()) { @@ -253,7 +231,7 @@ void AssetServer::handleAssetGetInfo(QSharedPointer message, Sh void AssetServer::handleAssetGet(QSharedPointer message, SharedNodePointer senderNode) { - auto minSize = qint64(sizeof(MessageID) + SHA256_HASH_LENGTH + sizeof(uint8_t) + sizeof(DataOffset) + sizeof(DataOffset)); + auto minSize = qint64(sizeof(MessageID) + SHA256_HASH_LENGTH + sizeof(DataOffset) + sizeof(DataOffset)); if (message->getSize() < minSize) { qDebug() << "ERROR bad file request"; diff --git a/assignment-client/src/assets/SendAssetTask.cpp b/assignment-client/src/assets/SendAssetTask.cpp index 35f4ad1801..33e1ab0fb8 100644 --- a/assignment-client/src/assets/SendAssetTask.cpp +++ b/assignment-client/src/assets/SendAssetTask.cpp @@ -33,13 +33,10 @@ SendAssetTask::SendAssetTask(QSharedPointer message, const Shar void SendAssetTask::run() { MessageID messageID; - uint8_t extensionLength; DataOffset start, end; _message->readPrimitive(&messageID); QByteArray assetHash = _message->read(SHA256_HASH_LENGTH); - _message->readPrimitive(&extensionLength); - QByteArray extension = _message->read(extensionLength); // `start` and `end` indicate the range of data to retrieve for the asset identified by `assetHash`. // `start` is inclusive, `end` is exclusive. Requesting `start` = 1, `end` = 10 will retrieve 9 bytes of data, @@ -61,7 +58,7 @@ void SendAssetTask::run() { if (end <= start) { writeError(replyPacketList.get(), AssetServerError::InvalidByteRange); } else { - QString filePath = _resourcesDir.filePath(QString(hexHash) + "." + QString(extension)); + QString filePath = _resourcesDir.filePath(QString(hexHash)); QFile file { filePath }; From 7bb97ec3da0483103056c1be5354dcb9b0315fd6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 13:25:28 -0800 Subject: [PATCH 016/209] add an extra space before debug in AssetServer --- assignment-client/src/assets/AssetServer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 15dfb95551..2777496d97 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -130,6 +130,7 @@ void AssetServer::completeSetup() { } } + qInfo() << "Serving files from: " << _resourcesDirectory.path(); // Check the asset directory to output some information about what we have From e6ce5170418682d9d96e006178996cc2ec84176f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 13:57:41 -0800 Subject: [PATCH 017/209] remove committed version control marker --- libraries/networking/src/AssetClient.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 51c5ae8cb3..deb1d9eb7d 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -621,4 +621,3 @@ void AssetScriptingInterface::getMapping(QString path, QScriptValue callback) { void AssetScriptingInterface::getAllMappings(QString path, QScriptValue callback) { } ->>>>>>> 6dd3b1b... Add AssetScriptingInterface methods for mapping From 4bf69f20b7bc789c2d46b44bfad460bd1ad4087d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 13:59:17 -0800 Subject: [PATCH 018/209] fix removal of requestHash method during cherry-pick --- .../networking/src/AssetResourceRequest.cpp | 17 +++++++++-------- libraries/networking/src/AssetResourceRequest.h | 4 ++++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 07fc5920ee..10c50c0b87 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -46,16 +46,17 @@ void AssetResourceRequest::doSend() { // We've detected that this is a hash - simply use AssetClient to request that asset auto parts = _url.path().split(".", QString::SkipEmptyParts); auto hash = parts.length() > 0 ? parts[0] : ""; - auto extension = parts.length() > 1 ? parts[1] : ""; - // in case we haven't parsed a valid hash, return an error now - if (hash.length() != SHA256_HASH_HEX_LENGTH) { - _result = InvalidURL; - _state = Finished; + requestHash(hash); + } +} - emit finished(); - return; - } +void AssetResourceRequest::requestHash(const QString& hash) { + + // in case we haven't parsed a valid hash, return an error now + if (hash.length() != SHA256_HASH_HEX_LENGTH) { + _result = InvalidURL; + _state = Finished; emit finished(); return; diff --git a/libraries/networking/src/AssetResourceRequest.h b/libraries/networking/src/AssetResourceRequest.h index 4d2ea56ca4..d74991ad6a 100644 --- a/libraries/networking/src/AssetResourceRequest.h +++ b/libraries/networking/src/AssetResourceRequest.h @@ -30,6 +30,10 @@ private slots: void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); private: + bool urlIsAssetPath() const; + + void requestHash(const QString& hash); + AssetRequest* _assetRequest { nullptr }; }; From 83b563cf9c95cc75786dc5ddcdaa6940d92f3b54 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 14:00:12 -0800 Subject: [PATCH 019/209] use AssetHash alias for hash in AssetResourceRequest --- libraries/networking/src/AssetResourceRequest.cpp | 2 +- libraries/networking/src/AssetResourceRequest.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 10c50c0b87..c9ac06fca4 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -51,7 +51,7 @@ void AssetResourceRequest::doSend() { } } -void AssetResourceRequest::requestHash(const QString& hash) { +void AssetResourceRequest::requestHash(const AssetHash& hash) { // in case we haven't parsed a valid hash, return an error now if (hash.length() != SHA256_HASH_HEX_LENGTH) { diff --git a/libraries/networking/src/AssetResourceRequest.h b/libraries/networking/src/AssetResourceRequest.h index d74991ad6a..c9a1fbfbf9 100644 --- a/libraries/networking/src/AssetResourceRequest.h +++ b/libraries/networking/src/AssetResourceRequest.h @@ -32,7 +32,7 @@ private slots: private: bool urlIsAssetPath() const; - void requestHash(const QString& hash); + void requestHash(const AssetHash& hash); AssetRequest* _assetRequest { nullptr }; }; From 9d61de6cd59111b3a026be9d0e534943754a7497 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 14:38:55 -0800 Subject: [PATCH 020/209] add a mapping migration for pre-mapping assets --- assignment-client/src/assets/AssetServer.cpp | 35 ++++++++++++++++++-- assignment-client/src/assets/AssetServer.h | 2 ++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 2777496d97..87d6cb9cdf 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -127,7 +127,6 @@ void AssetServer::completeSetup() { qDebug() << "\tCopying from " << from << " to " << to; QFile::copy(from, to); } - } } @@ -141,9 +140,42 @@ void AssetServer::completeSetup() { qInfo() << "There are" << hashedFiles.size() << "asset files in the asset directory."; + performMappingMigration(); + nodeList->addNodeTypeToInterestSet(NodeType::Agent); } +void AssetServer::performMappingMigration() { + QRegExp hashFileRegex { "^[a-f0-9]{" + QString::number(SHA256_HASH_HEX_LENGTH) + "}(\\.[\\w]+)+$" }; + + auto files = _resourcesDirectory.entryInfoList(QDir::Files); + + for (const auto& fileInfo : files) { + if (hashFileRegex.exactMatch(fileInfo.fileName())) { + // we have a pre-mapping file that we should migrate to the new mapping system + qDebug() << "Migrating pre-mapping file" << fileInfo.fileName(); + + // rename the file to the same name with no extension + QFile oldFile { fileInfo.absoluteFilePath() }; + + auto oldAbsolutePath = fileInfo.absoluteFilePath(); + auto oldFilename = fileInfo.fileName(); + auto fullExtension = oldFilename.mid(oldFilename.indexOf('.')); + + qDebug() << "Moving" << oldAbsolutePath << "to" << oldAbsolutePath.replace(fullExtension, ""); + + bool renamed = oldFile.rename(oldAbsolutePath.replace(fullExtension, "")); + if (!renamed) { + qWarning() << "Could not migrate pre-mapping file" << fileInfo.fileName(); + } else { + qDebug() << "Renamed pre-mapping file" << fileInfo.fileName(); + + // add a new mapping with the old extension and a truncated version of the hash + } + } + } +} + void AssetServer::handleAssetMappingOperation(QSharedPointer message, SharedNodePointer senderNode) { MessageID messageID; message->readPrimitive(&messageID); @@ -194,7 +226,6 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me nodeList->sendPacket(std::move(replyPacket), *senderNode); } ->>>>>>> db98e46... Update atp mapping operations to use a single packet void AssetServer::handleAssetGetInfo(QSharedPointer message, SharedNodePointer senderNode) { QByteArray assetHash; MessageID messageID; diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 1eee4feb94..1face3be26 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -55,6 +55,8 @@ private: static void writeError(NLPacketList* packetList, AssetServerError error); + void performMappingMigration(); + Mapping _fileMapping; QDir _resourcesDirectory; QThreadPool _taskPool; From 18b22cbd16b9d47e986dee5818d7845e17fa7485 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 14:43:17 -0800 Subject: [PATCH 021/209] add a mapping for pre-mapping migrated files --- assignment-client/src/assets/AssetServer.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 87d6cb9cdf..611ff0161c 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -171,6 +171,13 @@ void AssetServer::performMappingMigration() { qDebug() << "Renamed pre-mapping file" << fileInfo.fileName(); // add a new mapping with the old extension and a truncated version of the hash + static const int TRUNCATED_HASH_NUM_CHAR = 16; + auto fakeFileName = oldFilename.left(TRUNCATED_HASH_NUM_CHAR) + fullExtension; + + auto hash = oldFilename.left(SHA256_HASH_HEX_LENGTH); + + qDebug() << "Adding a migration mapping from" << fakeFileName << "to" << hash; + _fileMapping[fakeFileName] = hash; } } } From 82cd8aed8cd1c244c18489ec924065eda88e8643 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 14:46:54 -0800 Subject: [PATCH 022/209] protect mapping clobbering when migrating --- assignment-client/src/assets/AssetServer.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 611ff0161c..c6254aea07 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -150,6 +150,8 @@ void AssetServer::performMappingMigration() { auto files = _resourcesDirectory.entryInfoList(QDir::Files); + bool addedAtLeastOneMapping = false; + for (const auto& fileInfo : files) { if (hashFileRegex.exactMatch(fileInfo.fileName())) { // we have a pre-mapping file that we should migrate to the new mapping system @@ -177,10 +179,23 @@ void AssetServer::performMappingMigration() { auto hash = oldFilename.left(SHA256_HASH_HEX_LENGTH); qDebug() << "Adding a migration mapping from" << fakeFileName << "to" << hash; - _fileMapping[fakeFileName] = hash; + + auto it = _fileMapping.find(fakeFileName); + if (it == _fileMapping.end()) { + _fileMapping[fakeFileName] = hash; + + addedAtLeastOneMapping = true; + } else { + qDebug() << "Could not add migration mapping for" << hash << "since a mapping for" << fakeFileName + << "already exists."; + } } } } + + if (addedAtLeastOneMapping) { + // we added at least one new mapping - let's persist changes to file + } } void AssetServer::handleAssetMappingOperation(QSharedPointer message, SharedNodePointer senderNode) { From 5aa287a789416333364fd3fec7f4361a76f75dae Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 15:30:30 -0800 Subject: [PATCH 023/209] handle read/write to asset-server map file --- assignment-client/src/assets/AssetServer.cpp | 137 ++++++++++--------- assignment-client/src/assets/AssetServer.h | 8 +- 2 files changed, 80 insertions(+), 65 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index c6254aea07..e25b56159a 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -12,13 +12,14 @@ #include "AssetServer.h" -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include "NetworkLogging.h" #include "NodeType.h" @@ -57,6 +58,8 @@ void AssetServer::run() { ThreadedAssignment::commonInit(ASSET_SERVER_LOGGING_TARGET_NAME, NodeType::AssetServer); } +static const QString ASSET_FILES_SUBDIR = "files"; + void AssetServer::completeSetup() { auto nodeList = DependencyManager::get(); @@ -97,43 +100,18 @@ void AssetServer::completeSetup() { qDebug() << "Creating resources directory"; _resourcesDirectory.mkpath("."); + _resourcesDirectory.mkpath(ASSET_FILES_SUBDIR); - bool noExistingAssets = !_resourcesDirectory.exists() || _resourcesDirectory.entryList(QDir::Files).size() == 0; + _filesDirectory = _resourcesDirectory; + _filesDirectory.cd(ASSET_FILES_SUBDIR); - if (noExistingAssets) { - qDebug() << "Asset resources directory empty, searching for existing asset resources to migrate"; - QString oldDataDirectory = QCoreApplication::applicationDirPath(); - - const QString OLD_RESOURCES_PATH = "assets"; - - auto oldResourcesDirectory = QDir(oldDataDirectory).filePath("resources/" + OLD_RESOURCES_PATH); - - - if (QDir(oldResourcesDirectory).exists()) { - qDebug() << "Existing assets found in " << oldResourcesDirectory << ", copying to " << _resourcesDirectory; - - - QDir resourcesParentDirectory = _resourcesDirectory.filePath(".."); - if (!resourcesParentDirectory.exists()) { - qDebug() << "Creating data directory " << resourcesParentDirectory.absolutePath(); - resourcesParentDirectory.mkpath("."); - } - - auto files = QDir(oldResourcesDirectory).entryList(QDir::Files); - - for (auto& file : files) { - auto from = oldResourcesDirectory + QDir::separator() + file; - auto to = _resourcesDirectory.absoluteFilePath(file); - qDebug() << "\tCopying from " << from << " to " << to; - QFile::copy(from, to); - } - } - } + // load whatever mappings we currently have from the local file + loadMappingFromFile(); - qInfo() << "Serving files from: " << _resourcesDirectory.path(); + qInfo() << "Serving files from: " << _filesDirectory.path(); // Check the asset directory to output some information about what we have - auto files = _resourcesDirectory.entryList(QDir::Files); + auto files = _filesDirectory.entryList(QDir::Files); QRegExp hashFileRegex { "^[a-f0-9]{" + QString::number(SHA256_HASH_HEX_LENGTH) + "}$" }; auto hashedFiles = files.filter(hashFileRegex); @@ -150,8 +128,6 @@ void AssetServer::performMappingMigration() { auto files = _resourcesDirectory.entryInfoList(QDir::Files); - bool addedAtLeastOneMapping = false; - for (const auto& fileInfo : files) { if (hashFileRegex.exactMatch(fileInfo.fileName())) { // we have a pre-mapping file that we should migrate to the new mapping system @@ -162,40 +138,40 @@ void AssetServer::performMappingMigration() { auto oldAbsolutePath = fileInfo.absoluteFilePath(); auto oldFilename = fileInfo.fileName(); + auto hash = oldFilename.left(SHA256_HASH_HEX_LENGTH); auto fullExtension = oldFilename.mid(oldFilename.indexOf('.')); - qDebug() << "Moving" << oldAbsolutePath << "to" << oldAbsolutePath.replace(fullExtension, ""); + qDebug() << "\tMoving" << oldAbsolutePath << "to" << oldAbsolutePath.replace(fullExtension, ""); - bool renamed = oldFile.rename(oldAbsolutePath.replace(fullExtension, "")); + bool renamed = oldFile.copy(_filesDirectory.filePath(hash)); if (!renamed) { - qWarning() << "Could not migrate pre-mapping file" << fileInfo.fileName(); + qWarning() << "\tCould not migrate pre-mapping file" << fileInfo.fileName(); } else { - qDebug() << "Renamed pre-mapping file" << fileInfo.fileName(); + qDebug() << "\tRenamed pre-mapping file" << fileInfo.fileName(); // add a new mapping with the old extension and a truncated version of the hash static const int TRUNCATED_HASH_NUM_CHAR = 16; - auto fakeFileName = oldFilename.left(TRUNCATED_HASH_NUM_CHAR) + fullExtension; + auto fakeFileName = hash.left(TRUNCATED_HASH_NUM_CHAR) + fullExtension; - auto hash = oldFilename.left(SHA256_HASH_HEX_LENGTH); - - qDebug() << "Adding a migration mapping from" << fakeFileName << "to" << hash; + qDebug() << "\tAdding a migration mapping from" << fakeFileName << "to" << hash; auto it = _fileMapping.find(fakeFileName); if (it == _fileMapping.end()) { _fileMapping[fakeFileName] = hash; - addedAtLeastOneMapping = true; + + if (writeMappingToFile()) { + // mapping added and persisted, we can remove the migrated file + oldFile.remove(); + qDebug() << "\tMigration completed for" << oldFilename; + } } else { - qDebug() << "Could not add migration mapping for" << hash << "since a mapping for" << fakeFileName + qDebug() << "\tCould not add migration mapping for" << hash << "since a mapping for" << fakeFileName << "already exists."; } } } } - - if (addedAtLeastOneMapping) { - // we added at least one new mapping - let's persist changes to file - } } void AssetServer::handleAssetMappingOperation(QSharedPointer message, SharedNodePointer senderNode) { @@ -214,7 +190,7 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me auto it = _fileMapping.find(assetPath); if (it != _fileMapping.end()) { - auto assetHash = it->second; + auto assetHash = it->toString(); qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; replyPacket->writePrimitive(AssetServerError::NoError); //replyPacket->write(assetHash.toLatin1().toHex()); @@ -237,7 +213,7 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me } case AssetMappingOperationType::Delete: { QString assetPath = message->readString(); - bool removed = _fileMapping.erase(assetPath) > 0; + bool removed = _fileMapping.remove(assetPath) > 0; replyPacket->writePrimitive(AssetServerError::NoError); break; @@ -293,7 +269,7 @@ void AssetServer::handleAssetGet(QSharedPointer message, Shared } // Queue task - auto task = new SendAssetTask(message, senderNode, _resourcesDirectory); + auto task = new SendAssetTask(message, senderNode, _filesDirectory); _taskPool.start(task); } @@ -302,7 +278,7 @@ void AssetServer::handleAssetUpload(QSharedPointer message, Sha if (senderNode->getCanRez()) { qDebug() << "Starting an UploadAssetTask for upload from" << uuidStringWithoutCurlyBraces(senderNode->getUUID()); - auto task = new UploadAssetTask(message, senderNode, _resourcesDirectory); + auto task = new UploadAssetTask(message, senderNode, _filesDirectory); _taskPool.start(task); } else { // this is a node the domain told us is not allowed to rez entities @@ -393,14 +369,51 @@ void AssetServer::sendStatsPacket() { ThreadedAssignment::addPacketStatsAndSendStatsPacket(serverStats); } +static const QString MAP_FILE_NAME = "map.json"; + void AssetServer::loadMappingFromFile() { + + auto mapFilePath = _resourcesDirectory.absoluteFilePath(MAP_FILE_NAME); + + QFile mapFile { mapFilePath }; + if (mapFile.exists()) { + if (mapFile.open(QIODevice::ReadOnly)) { + auto jsonDocument = QJsonDocument::fromJson(mapFile.readAll()); + _fileMapping = jsonDocument.object().toVariantHash(); + + qInfo() << "Loaded" << _fileMapping.count() << "mappings from map file at" << mapFilePath; + } else { + qCritical() << "Failed to read mapping file at" << mapFilePath << "- assignment with not continue."; + setFinished(true); + } + } else { + qInfo() << "No existing mappings loaded from file since no file was found at" << mapFilePath; + } } -void AssetServer::writeMappingToFile() { +bool AssetServer::writeMappingToFile() { + auto mapFilePath = _resourcesDirectory.absoluteFilePath(MAP_FILE_NAME); + + QFile mapFile { mapFilePath }; + if (mapFile.open(QIODevice::WriteOnly)) { + auto jsonObject = QJsonObject::fromVariantHash(_fileMapping); + QJsonDocument jsonDocument { jsonObject }; + + if (mapFile.write(jsonDocument.toJson()) != -1) { + qDebug() << "Wrote JSON mappings to file at" << mapFilePath; + return true; + } else { + qWarning() << "Failed to write JSON mappings to file at" << mapFilePath; + } + } else { + qWarning() << "Failed to open map file at" << mapFilePath; + } + + return false; } AssetHash AssetServer::getMapping(AssetPath path) { - return _fileMapping[path]; + return _fileMapping.value(path).toString(); } void AssetServer::setMapping(AssetPath path, AssetHash hash) { @@ -408,5 +421,5 @@ void AssetServer::setMapping(AssetPath path, AssetHash hash) { } bool AssetServer::deleteMapping(AssetPath path) { - return _fileMapping.erase(path) > 0; + return _fileMapping.remove(path) > 0; } diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 1face3be26..f81ca924ed 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -39,10 +39,11 @@ private slots: void sendStatsPacket(); private: - using Mapping = std::map; + using Mapping = QVariantHash; + // Mapping file operations must be called from main assignment thread only void loadMappingFromFile(); - void writeMappingToFile(); + bool writeMappingToFile(); /// Return the hash mapping for AssetPath `path` AssetHash getMapping(AssetPath path); @@ -57,8 +58,9 @@ private: void performMappingMigration(); - Mapping _fileMapping; + QVariantHash _fileMapping; QDir _resourcesDirectory; + QDir _filesDirectory; QThreadPool _taskPool; }; From 12a774d47f1deaa1909f7219d635a0e3c2243983 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 15:46:44 -0800 Subject: [PATCH 024/209] return error if persistence fails for set/delete operations --- assignment-client/src/assets/AssetServer.cpp | 54 +++++++++++++++++--- assignment-client/src/assets/AssetServer.h | 2 +- libraries/networking/src/AssetUtils.h | 3 +- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index e25b56159a..97c28816b9 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -206,16 +206,25 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me QString assetPath = message->readString(); //auto assetHash = message->read(SHA256_HASH_LENGTH); auto assetHash = message->readString(); - _fileMapping[assetPath] = assetHash; - replyPacket->writePrimitive(AssetServerError::NoError); + if (setMapping(assetPath, assetHash)) { + replyPacket->writePrimitive(AssetServerError::NoError); + } else { + replyPacket->writePrimitive(AssetServerError::MappingOperationFailed); + } + + break; } case AssetMappingOperationType::Delete: { QString assetPath = message->readString(); - bool removed = _fileMapping.remove(assetPath) > 0; - replyPacket->writePrimitive(AssetServerError::NoError); + if (deleteMapping(assetPath)) { + replyPacket->writePrimitive(AssetServerError::NoError); + } else { + replyPacket->writePrimitive(AssetServerError::MappingOperationFailed); + } + break; } } @@ -416,10 +425,43 @@ AssetHash AssetServer::getMapping(AssetPath path) { return _fileMapping.value(path).toString(); } -void AssetServer::setMapping(AssetPath path, AssetHash hash) { +bool AssetServer::setMapping(AssetPath path, AssetHash hash) { + // remember what the old mapping was in case persistence fails + auto oldMapping = _fileMapping.value(path).toString(); + + // update the in memory QHash _fileMapping[path] = hash; + + // attempt to write to file + if (writeMappingToFile()) { + // persistence succeeded, we are good to go + return true; + } else { + // failed to persist this mapping to file - put back the old one in our in-memory representation + if (oldMapping.isEmpty()) { + _fileMapping.remove(path); + } else { + _fileMapping[path] = oldMapping; + } + + return false; + } } bool AssetServer::deleteMapping(AssetPath path) { - return _fileMapping.remove(path) > 0; + // keep the old mapping in case the delete fails + auto oldMapping = _fileMapping.take(path); + + if (!oldMapping.isNull()) { + // deleted the old mapping, attempt to persist to file + if (writeMappingToFile()) { + // persistence succeeded we are good to go + return true; + } else { + // we didn't delete the previous mapping, put it back in our in-memory representation + _fileMapping[path] = oldMapping.toString(); + } + } + + return false; } diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index f81ca924ed..01b3a95ece 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -49,7 +49,7 @@ private: AssetHash getMapping(AssetPath path); /// Set the mapping for path to hash - void setMapping(AssetPath path, AssetHash hash); + bool setMapping(AssetPath path, AssetHash hash); /// Delete mapping `path`. Return `true` if mapping existed, else `false`. bool deleteMapping(AssetPath path); diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index cc9aa60407..e682a48c59 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -32,7 +32,8 @@ enum AssetServerError : uint8_t { AssetNotFound, InvalidByteRange, AssetTooLarge, - PermissionDenied + PermissionDenied, + MappingOperationFailed }; enum AssetMappingOperationType : uint8_t { From 08f181be764e2efa9b30a5afe87052d52869cf64 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 16:30:26 -0800 Subject: [PATCH 025/209] handle mapping requests from AssetResourceRequest --- .../networking/src/AssetResourceRequest.cpp | 57 +++++++++++++++++-- .../networking/src/AssetResourceRequest.h | 4 +- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index c9ac06fca4..d4188467ab 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -15,6 +15,10 @@ #include "AssetUtils.h" AssetResourceRequest::~AssetResourceRequest() { + if (_assetMappingRequest) { + _assetMappingRequest->deleteLater(); + } + if (_assetRequest) { _assetRequest->deleteLater(); } @@ -38,11 +42,9 @@ void AssetResourceRequest::doSend() { // This is an ATP path, we'll need to figure out what the mapping is. // This may incur a roundtrip to the asset-server, or it may return immediately from the cache in AssetClient. - qDebug() << "Detected an asset path! URL is" << _url; + auto path = _url.path(); + requestMappingForPath(path); } else { - - qDebug() << "ATP URL was not an asset path - url is" << _url.toString(); - // We've detected that this is a hash - simply use AssetClient to request that asset auto parts = _url.path().split(".", QString::SkipEmptyParts); auto hash = parts.length() > 0 ? parts[0] : ""; @@ -51,6 +53,53 @@ void AssetResourceRequest::doSend() { } } +void AssetResourceRequest::requestMappingForPath(const AssetPath& path) { + auto assetClient = DependencyManager::get(); + _assetMappingRequest = assetClient->createGetMappingRequest(path); + + // if we get a nullptr for createGetMappingRequest assume that there is no currently available asset-server + if (!_assetMappingRequest) { + _result = ServerUnavailable; + _state = Finished; + + emit finished(); + return; + } + + // make sure we'll hear about the result of the get mapping request + connect(_assetMappingRequest, &GetMappingRequest::finished, this, [this, path](GetMappingRequest* request){ + Q_ASSERT(_state == InProgress); + Q_ASSERT(request == _assetMappingRequest); + + switch (request->getError()) { + case AssetServerError::NoError: + // we have no error, we should have a resulting hash - use that to send of a request for that asset + qDebug() << "Got mapping for:" << path << "=>" << request->getHash(); + + requestHash(request->getHash()); + + break; + case AssetServerError::AssetNotFound: + // no result for the mapping request, set error to not found + _result = NotFound; + + // since we've failed we know we are finished + _state = Finished; + emit finished(); + + break; + default: + // these are unexpected errors for a GetMappingRequest object + break; + } + + _assetMappingRequest->deleteLater(); + _assetMappingRequest = nullptr; + }); + + _assetMappingRequest->start(); +} + void AssetResourceRequest::requestHash(const AssetHash& hash) { // in case we haven't parsed a valid hash, return an error now diff --git a/libraries/networking/src/AssetResourceRequest.h b/libraries/networking/src/AssetResourceRequest.h index c9a1fbfbf9..2fb8cfd3df 100644 --- a/libraries/networking/src/AssetResourceRequest.h +++ b/libraries/networking/src/AssetResourceRequest.h @@ -31,9 +31,11 @@ private slots: private: bool urlIsAssetPath() const; - + + void requestMappingForPath(const AssetPath& path); void requestHash(const AssetHash& hash); + GetMappingRequest* _assetMappingRequest { nullptr }; AssetRequest* _assetRequest { nullptr }; }; From 37c0417ea607a5131541b13b9e36130450f10f85 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 16:31:49 -0800 Subject: [PATCH 026/209] Add GetAll and Delete mapping requests --- assignment-client/src/assets/AssetServer.cpp | 14 +- assignment-client/src/assets/AssetServer.h | 3 +- libraries/networking/src/AssetClient.cpp | 130 ++++++++++++++++++- libraries/networking/src/AssetClient.h | 48 ++++++- libraries/networking/src/AssetUtils.h | 4 + 5 files changed, 186 insertions(+), 13 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index f685bbe1a9..109ded1b73 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -170,7 +170,7 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me AssetMappingOperationType operationType; message->readPrimitive(&operationType); - auto replyPacket = NLPacket::create(PacketType::AssetMappingOperationReply); + auto replyPacket = NLPacketList::create(PacketType::AssetMappingOperationReply); replyPacket->writePrimitive(messageID); switch (operationType) { @@ -191,6 +191,16 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me } 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); @@ -210,7 +220,7 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me } auto nodeList = DependencyManager::get(); - nodeList->sendPacket(std::move(replyPacket), *senderNode); + nodeList->sendPacketList(std::move(replyPacket), *senderNode); } void AssetServer::handleAssetGetInfo(QSharedPointer message, SharedNodePointer senderNode) { diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 1eee4feb94..545faa23fb 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -39,7 +39,6 @@ private slots: void sendStatsPacket(); private: - using Mapping = std::map; void loadMappingFromFile(); void writeMappingToFile(); @@ -55,7 +54,7 @@ private: static void writeError(NLPacketList* packetList, AssetServerError error); - Mapping _fileMapping; + AssetMapping _fileMapping; QDir _resourcesDirectory; QThreadPool _taskPool; }; diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 93139af2d0..6f5e2eee03 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -50,6 +50,34 @@ void GetMappingRequest::start() { emit finished(this); }); }; + +GetAllMappingsRequest::GetAllMappingsRequest() { +}; + +void GetAllMappingsRequest::start() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); + return; + } + + auto assetClient = DependencyManager::get(); + assetClient->getAllAssetMappings([this](bool responseReceived, AssetServerError error, QSharedPointer message) { + // read message + _error = error; + if (!error) { + size_t numberOfMappings; + message->readPrimitive(&numberOfMappings); + AssetMapping mapping; + for (auto i = 0; i < numberOfMappings; ++i) { + auto path = message->readString(); + auto hash = message->readString(); + mapping[path] = hash; + } + } + emit finished(this); + }); +}; + SetMappingRequest::SetMappingRequest(AssetPath path, AssetHash hash) : _path(path), _hash(hash) { }; @@ -67,6 +95,23 @@ void SetMappingRequest::start() { }); }; +DeleteMappingRequest::DeleteMappingRequest(AssetPath path) : _path(path) { +}; + +void DeleteMappingRequest::start() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); + return; + } + + auto assetClient = DependencyManager::get(); + assetClient->deleteAssetMapping(_path, [this](bool responseReceived, AssetServerError error, QSharedPointer message) { + // read message + _error = error; + emit finished(this); + }); +}; + AssetClient::AssetClient() { @@ -174,11 +219,18 @@ bool haveAssetServer() { return true; } - GetMappingRequest* AssetClient::createGetMappingRequest(const AssetPath& path) { return new GetMappingRequest(path); } +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); } @@ -404,7 +456,7 @@ void AssetClient::handleAssetGetReply(QSharedPointer message, S } } -bool AssetClient::getAssetMapping(const AssetHash& hash, MappingOperationCallback callback) { +bool AssetClient::getAssetMapping(const AssetPath& path, MappingOperationCallback callback) { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); @@ -416,7 +468,53 @@ bool AssetClient::getAssetMapping(const AssetHash& hash, MappingOperationCallbac packetList->writePrimitive(AssetMappingOperationType::Get); - packetList->writeString(hash.toUtf8()); + 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); @@ -440,8 +538,8 @@ bool AssetClient::setAssetMapping(const QString& path, const AssetHash& hash, Ma packetList->writePrimitive(AssetMappingOperationType::Set); - packetList->writeString(path.toUtf8()); - packetList->writeString(hash.toUtf8()); + packetList->writeString(path); + packetList->writeString(hash); nodeList->sendPacketList(std::move(packetList), *assetServer); @@ -653,5 +751,25 @@ void AssetScriptingInterface::getMapping(QString path, QScriptValue callback) { request->start(); } -void AssetScriptingInterface::getAllMappings(QString path, QScriptValue callback) { +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 0face50367..5e6a071ad8 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -16,6 +16,8 @@ #include #include +#include + #include #include "AssetUtils.h" @@ -61,7 +63,6 @@ private: AssetServerError _error { AssetServerError::NoError }; }; - class SetMappingRequest : public QObject { Q_OBJECT public: @@ -81,6 +82,42 @@ private: AssetServerError _error { AssetServerError::NoError }; }; +class DeleteMappingRequest : public QObject { + Q_OBJECT +public: + DeleteMappingRequest(AssetPath path); + + Q_INVOKABLE void start(); + + AssetServerError getError() { return _error; } + +signals: + void finished(DeleteMappingRequest* thisRequest); + +private: + AssetPath _path; + AssetServerError _error { AssetServerError::NoError }; +}; + +class GetAllMappingsRequest : public QObject { + Q_OBJECT +public: + GetAllMappingsRequest(); + + Q_INVOKABLE void start(); + + AssetServerError getError() { return _error; } + AssetMapping getMappings() { return _mappings; } + +signals: + void finished(GetAllMappingsRequest* thisRequest); + +private: + std::map _mappings; + AssetServerError _error { AssetServerError::NoError }; +}; + + class AssetClient : public QObject, public Dependency { Q_OBJECT @@ -88,6 +125,8 @@ public: AssetClient(); 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); @@ -109,8 +148,9 @@ private slots: 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 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, @@ -131,7 +171,9 @@ private: friend class AssetRequest; friend class AssetUpload; friend class GetMappingRequest; + friend class GetAllMappingsRequest; friend class SetMappingRequest; + friend class DeleteMappingRequest; }; @@ -144,7 +186,7 @@ public: 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 getAllMappings(QString path, QScriptValue callback); + Q_INVOKABLE void getAllMappings(QScriptValue callback); protected: QSet _pendingRequests; QScriptEngine* _engine; diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index f13c9ac729..99e8fdc386 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -14,6 +14,8 @@ #include +#include + #include #include @@ -22,6 +24,7 @@ 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; @@ -37,6 +40,7 @@ enum AssetServerError : uint8_t { enum AssetMappingOperationType : uint8_t { Get = 0, + GetAll, Set, Delete }; From bc99e871e16fa77955760b1cf8b775f99d8073ad Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 16:51:49 -0800 Subject: [PATCH 027/209] Add asset mapping cache --- libraries/networking/src/AssetClient.cpp | 31 +++++++++++++++++++++--- libraries/networking/src/AssetClient.h | 2 ++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 6f5e2eee03..d518961216 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -40,12 +40,13 @@ void GetMappingRequest::start() { } auto assetClient = DependencyManager::get(); - assetClient->getAssetMapping(_path, [this](bool responseReceived, AssetServerError error, QSharedPointer message) { + assetClient->getAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { // read message _error = error; if (!error) { //_hash = message->read(SHA256_HASH_HEX_LENGTH); _hash = message->readString(); + assetClient->_mappingCache[_path] = _hash; } emit finished(this); }); @@ -61,17 +62,19 @@ void GetAllMappingsRequest::start() { } auto assetClient = DependencyManager::get(); - assetClient->getAllAssetMappings([this](bool responseReceived, AssetServerError error, QSharedPointer message) { + assetClient->getAllAssetMappings([this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { // read message _error = error; if (!error) { size_t numberOfMappings; message->readPrimitive(&numberOfMappings); AssetMapping mapping; + assetClient->_mappingCache.clear(); for (auto i = 0; i < numberOfMappings; ++i) { auto path = message->readString(); auto hash = message->readString(); mapping[path] = hash; + assetClient->_mappingCache[path] = hash; } } emit finished(this); @@ -88,9 +91,12 @@ void SetMappingRequest::start() { } auto assetClient = DependencyManager::get(); - assetClient->setAssetMapping(_path, _hash, [this](bool responseReceived, AssetServerError error, QSharedPointer message) { + assetClient->setAssetMapping(_path, _hash, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { // read message _error = error; + if (!error) { + assetClient->_mappingCache[_path] = _hash; + } emit finished(this); }); }; @@ -105,9 +111,12 @@ void DeleteMappingRequest::start() { } auto assetClient = DependencyManager::get(); - assetClient->deleteAssetMapping(_path, [this](bool responseReceived, AssetServerError error, QSharedPointer message) { + assetClient->deleteAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { // read message _error = error; + if (!error) { + assetClient->_mappingCache.remove(_path); + } emit finished(this); }); }; @@ -172,6 +181,8 @@ void AssetClient::clearCache() { return; } + _mappingCache.clear(); + if (auto cache = NetworkAccessManager::getInstance().cache()) { qDebug() << "AssetClient::clearCache(): Clearing disk cache."; cache->clear(); @@ -650,6 +661,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::PermissionDenied, QSharedPointer()); + } + messageMapIt->second.clear(); + } + } + + _mappingCache.clear(); } void AssetScriptingInterface::uploadData(QString data, QString extension, QScriptValue callback) { diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 5e6a071ad8..10fad14ee9 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -167,6 +167,8 @@ private: std::unordered_map> _pendingRequests; std::unordered_map> _pendingInfoRequests; std::unordered_map> _pendingUploads; + + QHash _mappingCache; friend class AssetRequest; friend class AssetUpload; From da3e3b7e6c930995257b1a5e156d35a416086f5e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 09:55:48 -0800 Subject: [PATCH 028/209] add handle calls for mapping operations --- assignment-client/src/assets/AssetServer.cpp | 86 ++++++++++++-------- assignment-client/src/assets/AssetServer.h | 5 ++ 2 files changed, 58 insertions(+), 33 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 97c28816b9..2bdef28b89 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -186,45 +186,15 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me switch (operationType) { case AssetMappingOperationType::Get: { - QString assetPath = message->readString(); - - auto it = _fileMapping.find(assetPath); - if (it != _fileMapping.end()) { - auto assetHash = it->toString(); - 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); - } + handleGetMappingOperation(*message, senderNode, std::move(replyPacket)); break; } case AssetMappingOperationType::Set: { - QString assetPath = message->readString(); - //auto assetHash = message->read(SHA256_HASH_LENGTH); - auto assetHash = message->readString(); - - if (setMapping(assetPath, assetHash)) { - replyPacket->writePrimitive(AssetServerError::NoError); - } else { - replyPacket->writePrimitive(AssetServerError::MappingOperationFailed); - } - - + handleSetMappingOperation(*message, senderNode, std::move(replyPacket)); break; } case AssetMappingOperationType::Delete: { - QString assetPath = message->readString(); - - if (deleteMapping(assetPath)) { - replyPacket->writePrimitive(AssetServerError::NoError); - } else { - replyPacket->writePrimitive(AssetServerError::MappingOperationFailed); - } - + handleDeleteMappingOperation(*message, senderNode, std::move(replyPacket)); break; } } @@ -233,6 +203,56 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me nodeList->sendPacket(std::move(replyPacket), *senderNode); } +void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, + std::unique_ptr replyPacket) { + QString assetPath = message.readString(); + + auto it = _fileMapping.find(assetPath); + if (it != _fileMapping.end()) { + auto assetHash = it->toString(); + 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); + } +} + +void AssetServer::handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, + std::unique_ptr replyPacket) { + if (senderNode->getCanRez()) { + QString assetPath = message.readString(); + // auto assetHash = message->read(SHA256_HASH_LENGTH); + auto assetHash = message.readString(); + + if (setMapping(assetPath, assetHash)) { + replyPacket->writePrimitive(AssetServerError::NoError); + } else { + replyPacket->writePrimitive(AssetServerError::MappingOperationFailed); + } + } else { + replyPacket->writePrimitive(AssetServerError::PermissionDenied); + } +} + +void AssetServer::handleDeleteMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, + std::unique_ptr replyPacket) { + if (senderNode->getCanRez()) { + QString assetPath = message.readString(); + + if (deleteMapping(assetPath)) { + 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; diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 01b3a95ece..a15adc6f60 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -41,6 +41,11 @@ private slots: private: using Mapping = QVariantHash; + void handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, std::unique_ptr replyPacket); + void handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, std::unique_ptr replyPacket); + void handleDeleteMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, + std::unique_ptr replyPacket); + // Mapping file operations must be called from main assignment thread only void loadMappingFromFile(); bool writeMappingToFile(); From fa04f08c4cf31a1beea000218a991a506768402c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 10:01:54 -0800 Subject: [PATCH 029/209] use toHex/fromHex for more compact messaging --- assignment-client/src/assets/AssetServer.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 2bdef28b89..dc4e6c90d5 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -212,8 +212,7 @@ void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNode auto assetHash = it->toString(); qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; replyPacket->writePrimitive(AssetServerError::NoError); - //replyPacket->write(assetHash.toLatin1().toHex()); - replyPacket->writeString(assetHash.toLatin1()); + replyPacket->write(QByteArray::fromHex(assetHash.toLocal8Bit())); } else { qDebug() << "Mapping not found for: " << assetPath; @@ -225,8 +224,7 @@ void AssetServer::handleSetMappingOperation(ReceivedMessage& message, SharedNode std::unique_ptr replyPacket) { if (senderNode->getCanRez()) { QString assetPath = message.readString(); - // auto assetHash = message->read(SHA256_HASH_LENGTH); - auto assetHash = message.readString(); + auto assetHash = message.read(SHA256_HASH_LENGTH).toHex(); if (setMapping(assetPath, assetHash)) { replyPacket->writePrimitive(AssetServerError::NoError); From bf8a2bc9e5d16a087d3ff18340431bc5b08dbc1f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 10:03:29 -0800 Subject: [PATCH 030/209] update read for get mapping to toHex --- libraries/networking/src/AssetClient.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index deb1d9eb7d..78c394cd27 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -44,8 +44,7 @@ void GetMappingRequest::start() { // read message _error = error; if (!error) { - //_hash = message->read(SHA256_HASH_HEX_LENGTH); - _hash = message->readString(); + _hash = message->read(SHA256_HASH_LENGTH).toHex(); } emit finished(this); }); From cf9d4c256ad6db9202db18e67e47de1e1618aaec Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 10:10:48 -0800 Subject: [PATCH 031/209] Add proper cache checking to GetAssetMapping --- libraries/networking/src/AssetClient.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index d518961216..f690c17cbd 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -40,6 +40,15 @@ void GetMappingRequest::start() { } 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) { // read message _error = error; From a18486d97db8c13baf11b99d380d44eb575d2873 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 10:11:37 -0800 Subject: [PATCH 032/209] Fix GetAllMappingsRequest not storing mappings --- libraries/networking/src/AssetClient.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index f690c17cbd..70064c3f69 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -77,12 +77,11 @@ void GetAllMappingsRequest::start() { if (!error) { size_t numberOfMappings; message->readPrimitive(&numberOfMappings); - AssetMapping mapping; assetClient->_mappingCache.clear(); for (auto i = 0; i < numberOfMappings; ++i) { auto path = message->readString(); auto hash = message->readString(); - mapping[path] = hash; + _mappings[path] = hash; assetClient->_mappingCache[path] = hash; } } From 6ca4b72479cf75e35f53c0f064912b5bdc200d6c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 10:11:57 -0800 Subject: [PATCH 033/209] Add deleteMapping to asset scripting interface --- libraries/networking/src/AssetClient.cpp | 16 ++++++++++++++++ libraries/networking/src/AssetClient.h | 1 + 2 files changed, 17 insertions(+) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 70064c3f69..d8c356aa07 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -782,6 +782,22 @@ void AssetScriptingInterface::getMapping(QString path, QScriptValue callback) { 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(); diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 10fad14ee9..f95f4bc9bc 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -188,6 +188,7 @@ public: 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; From a3533b0b7df4cb93e7bfbc50a295bf607d7348ff Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 10:21:29 -0800 Subject: [PATCH 034/209] repairs for moved packet handling in AssetServer --- assignment-client/src/assets/AssetServer.cpp | 33 +++++++++----------- assignment-client/src/assets/AssetServer.h | 7 ++--- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index dc4e6c90d5..2fbadf56d1 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -186,15 +186,15 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me switch (operationType) { case AssetMappingOperationType::Get: { - handleGetMappingOperation(*message, senderNode, std::move(replyPacket)); + handleGetMappingOperation(*message, senderNode, *replyPacket); break; } case AssetMappingOperationType::Set: { - handleSetMappingOperation(*message, senderNode, std::move(replyPacket)); + handleSetMappingOperation(*message, senderNode, *replyPacket); break; } case AssetMappingOperationType::Delete: { - handleDeleteMappingOperation(*message, senderNode, std::move(replyPacket)); + handleDeleteMappingOperation(*message, senderNode, *replyPacket); break; } } @@ -203,51 +203,48 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me nodeList->sendPacket(std::move(replyPacket), *senderNode); } -void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, - std::unique_ptr replyPacket) { +void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacket& replyPacket) { QString assetPath = message.readString(); auto it = _fileMapping.find(assetPath); if (it != _fileMapping.end()) { auto assetHash = it->toString(); qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; - replyPacket->writePrimitive(AssetServerError::NoError); - replyPacket->write(QByteArray::fromHex(assetHash.toLocal8Bit())); + replyPacket.writePrimitive(AssetServerError::NoError); + replyPacket.write(QByteArray::fromHex(assetHash.toLocal8Bit())); } else { qDebug() << "Mapping not found for: " << assetPath; - replyPacket->writePrimitive(AssetServerError::AssetNotFound); + replyPacket.writePrimitive(AssetServerError::AssetNotFound); } } -void AssetServer::handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, - std::unique_ptr replyPacket) { +void AssetServer::handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacket& replyPacket) { if (senderNode->getCanRez()) { QString assetPath = message.readString(); auto assetHash = message.read(SHA256_HASH_LENGTH).toHex(); if (setMapping(assetPath, assetHash)) { - replyPacket->writePrimitive(AssetServerError::NoError); + replyPacket.writePrimitive(AssetServerError::NoError); } else { - replyPacket->writePrimitive(AssetServerError::MappingOperationFailed); + replyPacket.writePrimitive(AssetServerError::MappingOperationFailed); } } else { - replyPacket->writePrimitive(AssetServerError::PermissionDenied); + replyPacket.writePrimitive(AssetServerError::PermissionDenied); } } -void AssetServer::handleDeleteMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, - std::unique_ptr replyPacket) { +void AssetServer::handleDeleteMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacket& replyPacket) { if (senderNode->getCanRez()) { QString assetPath = message.readString(); if (deleteMapping(assetPath)) { - replyPacket->writePrimitive(AssetServerError::NoError); + replyPacket.writePrimitive(AssetServerError::NoError); } else { - replyPacket->writePrimitive(AssetServerError::MappingOperationFailed); + replyPacket.writePrimitive(AssetServerError::MappingOperationFailed); } } else { - replyPacket->writePrimitive(AssetServerError::PermissionDenied); + replyPacket.writePrimitive(AssetServerError::PermissionDenied); } } diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index a15adc6f60..871898505f 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -41,10 +41,9 @@ private slots: private: using Mapping = QVariantHash; - void handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, std::unique_ptr replyPacket); - void handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, std::unique_ptr replyPacket); - void handleDeleteMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, - std::unique_ptr replyPacket); + void handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacket& replyPacket); + void handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacket& replyPacket); + void handleDeleteMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacket& replyPacket); // Mapping file operations must be called from main assignment thread only void loadMappingFromFile(); From 7db296fa69f3e16143c927416758b10f58725190 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 10:23:48 -0800 Subject: [PATCH 035/209] Remove unused get/set/deleteMapping in AssetServer --- assignment-client/src/assets/AssetServer.cpp | 12 ------------ assignment-client/src/assets/AssetServer.h | 9 --------- libraries/networking/src/AssetClient.cpp | 1 - 3 files changed, 22 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 109ded1b73..d3198c0f30 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -376,15 +376,3 @@ void AssetServer::loadMappingFromFile() { void AssetServer::writeMappingToFile() { } - -AssetHash AssetServer::getMapping(AssetPath path) { - return _fileMapping[path]; -} - -void AssetServer::setMapping(AssetPath path, AssetHash hash) { - _fileMapping[path] = hash; -} - -bool AssetServer::deleteMapping(AssetPath path) { - return _fileMapping.erase(path) > 0; -} diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 545faa23fb..e87c0797c8 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -43,15 +43,6 @@ private: void loadMappingFromFile(); void writeMappingToFile(); - /// Return the hash mapping for AssetPath `path` - AssetHash getMapping(AssetPath path); - - /// Set the mapping for path to hash - void setMapping(AssetPath path, AssetHash hash); - - /// Delete mapping `path`. Return `true` if mapping existed, else `false`. - bool deleteMapping(AssetPath path); - static void writeError(NLPacketList* packetList, AssetServerError error); AssetMapping _fileMapping; diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index d8c356aa07..27a3acc00b 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -478,7 +478,6 @@ 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); From 89b37f78f03f971aa0916b72e9761edf75bdc449 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 10:26:50 -0800 Subject: [PATCH 036/209] Make AssetServer response reliable and ordered --- assignment-client/src/assets/AssetServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index d3198c0f30..b7d02cdb85 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -170,7 +170,7 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me AssetMappingOperationType operationType; message->readPrimitive(&operationType); - auto replyPacket = NLPacketList::create(PacketType::AssetMappingOperationReply); + auto replyPacket = NLPacketList::create(PacketType::AssetMappingOperationReply, QByteArray(), true, true); replyPacket->writePrimitive(messageID); switch (operationType) { From e3523c86046a6459e78ed0de5350d19ecebfe168 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 10:28:31 -0800 Subject: [PATCH 037/209] Remove commented out function --- libraries/networking/src/AssetClient.cpp | 28 ------------------------ 1 file changed, 28 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 27a3acc00b..d40aa741a9 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -297,34 +297,6 @@ AssetUpload* AssetClient::createUpload(const QByteArray& data, const QString& ex } } -//bool AssetClient::setAssetMapping(const QString& path, MappingOperationCallback callback) { -// auto nodeList = DependencyManager::get(); -// SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); -// -// if (assetServer) { -// auto messageID = ++_currentID; -// -// auto payload = path.toLatin1(); -// auto payloadSize = sizeof(messageID) + payload.size(); -// auto packet = NLPacket::create(PacketType::AssetMappingOperation, payloadSize, true); -// -// qCDebug(asset_client) << "Requesting mapping for" << path << "from asset-server."; -// -// packet->writePrimitive(messageID); -// -// auto bytesWritten = packet->write(payload); -// Q_ASSERT(bytesWritten == payload.size()); -// -// nodeList->sendPacket(std::move(packet), *assetServer); -// -// _pendingMappingRequests[assetServer][messageID] = callback; -// -// return true; -// } -// -// return false; -//} -// bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback, ProgressCallback progressCallback) { if (hash.length() != SHA256_HASH_HEX_LENGTH) { From 7bf6b8405ce0fbc5f643f9353a2789c23fa0e0b6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 10:27:35 -0800 Subject: [PATCH 038/209] pluralize mappings in AssetServer naming --- assignment-client/src/assets/AssetServer.cpp | 42 ++++++++++---------- assignment-client/src/assets/AssetServer.h | 8 ++-- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 2fbadf56d1..d4e33c5bf8 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -106,7 +106,7 @@ void AssetServer::completeSetup() { _filesDirectory.cd(ASSET_FILES_SUBDIR); // load whatever mappings we currently have from the local file - loadMappingFromFile(); + loadMappingsFromFile(); qInfo() << "Serving files from: " << _filesDirectory.path(); @@ -155,12 +155,12 @@ void AssetServer::performMappingMigration() { qDebug() << "\tAdding a migration mapping from" << fakeFileName << "to" << hash; - auto it = _fileMapping.find(fakeFileName); - if (it == _fileMapping.end()) { - _fileMapping[fakeFileName] = hash; + auto it = _fileMappings.find(fakeFileName); + if (it == _fileMappings.end()) { + _fileMappings[fakeFileName] = hash; - if (writeMappingToFile()) { + if (writeMappingsToFile()) { // mapping added and persisted, we can remove the migrated file oldFile.remove(); qDebug() << "\tMigration completed for" << oldFilename; @@ -206,8 +206,8 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacket& replyPacket) { QString assetPath = message.readString(); - auto it = _fileMapping.find(assetPath); - if (it != _fileMapping.end()) { + auto it = _fileMappings.find(assetPath); + if (it != _fileMappings.end()) { auto assetHash = it->toString(); qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; replyPacket.writePrimitive(AssetServerError::NoError); @@ -395,7 +395,7 @@ void AssetServer::sendStatsPacket() { static const QString MAP_FILE_NAME = "map.json"; -void AssetServer::loadMappingFromFile() { +void AssetServer::loadMappingsFromFile() { auto mapFilePath = _resourcesDirectory.absoluteFilePath(MAP_FILE_NAME); @@ -403,9 +403,9 @@ void AssetServer::loadMappingFromFile() { if (mapFile.exists()) { if (mapFile.open(QIODevice::ReadOnly)) { auto jsonDocument = QJsonDocument::fromJson(mapFile.readAll()); - _fileMapping = jsonDocument.object().toVariantHash(); + _fileMappings = jsonDocument.object().toVariantHash(); - qInfo() << "Loaded" << _fileMapping.count() << "mappings from map file at" << mapFilePath; + qInfo() << "Loaded" << _fileMappings.count() << "mappings from map file at" << mapFilePath; } else { qCritical() << "Failed to read mapping file at" << mapFilePath << "- assignment with not continue."; setFinished(true); @@ -415,12 +415,12 @@ void AssetServer::loadMappingFromFile() { } } -bool AssetServer::writeMappingToFile() { +bool AssetServer::writeMappingsToFile() { auto mapFilePath = _resourcesDirectory.absoluteFilePath(MAP_FILE_NAME); QFile mapFile { mapFilePath }; if (mapFile.open(QIODevice::WriteOnly)) { - auto jsonObject = QJsonObject::fromVariantHash(_fileMapping); + auto jsonObject = QJsonObject::fromVariantHash(_fileMappings); QJsonDocument jsonDocument { jsonObject }; if (mapFile.write(jsonDocument.toJson()) != -1) { @@ -437,26 +437,26 @@ bool AssetServer::writeMappingToFile() { } AssetHash AssetServer::getMapping(AssetPath path) { - return _fileMapping.value(path).toString(); + return _fileMappings.value(path).toString(); } bool AssetServer::setMapping(AssetPath path, AssetHash hash) { // remember what the old mapping was in case persistence fails - auto oldMapping = _fileMapping.value(path).toString(); + auto oldMapping = _fileMappings.value(path).toString(); // update the in memory QHash - _fileMapping[path] = hash; + _fileMappings[path] = hash; // attempt to write to file - if (writeMappingToFile()) { + if (writeMappingsToFile()) { // persistence succeeded, we are good to go return true; } else { // failed to persist this mapping to file - put back the old one in our in-memory representation if (oldMapping.isEmpty()) { - _fileMapping.remove(path); + _fileMappings.remove(path); } else { - _fileMapping[path] = oldMapping; + _fileMappings[path] = oldMapping; } return false; @@ -465,16 +465,16 @@ bool AssetServer::setMapping(AssetPath path, AssetHash hash) { bool AssetServer::deleteMapping(AssetPath path) { // keep the old mapping in case the delete fails - auto oldMapping = _fileMapping.take(path); + auto oldMapping = _fileMappings.take(path); if (!oldMapping.isNull()) { // deleted the old mapping, attempt to persist to file - if (writeMappingToFile()) { + if (writeMappingsToFile()) { // persistence succeeded we are good to go return true; } else { // we didn't delete the previous mapping, put it back in our in-memory representation - _fileMapping[path] = oldMapping.toString(); + _fileMappings[path] = oldMapping.toString(); } } diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 871898505f..b1de4a355a 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -39,15 +39,15 @@ private slots: void sendStatsPacket(); private: - using Mapping = QVariantHash; + using Mappings = QVariantHash; void handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacket& replyPacket); void handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacket& replyPacket); void handleDeleteMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacket& replyPacket); // Mapping file operations must be called from main assignment thread only - void loadMappingFromFile(); - bool writeMappingToFile(); + void loadMappingsFromFile(); + bool writeMappingsToFile(); /// Return the hash mapping for AssetPath `path` AssetHash getMapping(AssetPath path); @@ -62,7 +62,7 @@ private: void performMappingMigration(); - QVariantHash _fileMapping; + Mappings _fileMappings; QDir _resourcesDirectory; QDir _filesDirectory; QThreadPool _taskPool; From 0a75a9479014737e72cc7e194d06697dea71196c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 10:31:40 -0800 Subject: [PATCH 039/209] Remove commented out private slot --- libraries/networking/src/AssetRequest.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/networking/src/AssetRequest.h b/libraries/networking/src/AssetRequest.h index 049ab19ef4..3c3459b15d 100644 --- a/libraries/networking/src/AssetRequest.h +++ b/libraries/networking/src/AssetRequest.h @@ -52,9 +52,6 @@ signals: void finished(AssetRequest* thisRequest); void progress(qint64 totalReceived, qint64 total); -//private slots: - //void getAssetCallback(bool responseReceived, AssetServerError serverError, const QByteArray& data); - private: State _state = NotStarted; Error _error = NoError; From e06c1591fbfb7aa86c7e5dbc7bf114338194a833 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 10:43:26 -0800 Subject: [PATCH 040/209] Remove initializer --- libraries/networking/src/udt/BasePacket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/BasePacket.cpp b/libraries/networking/src/udt/BasePacket.cpp index e0b2a8ba3a..dba241f221 100644 --- a/libraries/networking/src/udt/BasePacket.cpp +++ b/libraries/networking/src/udt/BasePacket.cpp @@ -157,7 +157,7 @@ qint64 BasePacket::writeString(const QString& string) { } QString BasePacket::readString() { - uint32_t size {}; + uint32_t size; readPrimitive(&size); auto string = QString::fromUtf8(getPayload() + pos(), size); seek(pos() + size); From c9bd67bc3e9755add744c1ad0e9c34a5c1ead1cd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 11:18:10 -0800 Subject: [PATCH 041/209] Add MappingRequest superclass and mapping specific errors --- libraries/networking/src/AssetClient.cpp | 90 +++++++++++++++++++----- libraries/networking/src/AssetClient.h | 56 +++++++++------ 2 files changed, 110 insertions(+), 36 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index d40aa741a9..b447380e5c 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -30,14 +30,18 @@ MessageID AssetClient::_currentID = 0; -GetMappingRequest::GetMappingRequest(AssetPath path) : _path(path) { -}; - -void GetMappingRequest::start() { +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(); @@ -50,9 +54,23 @@ void GetMappingRequest::start() { } assetClient->getAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { - // read message - _error = error; - if (!error) { + 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; @@ -64,7 +82,7 @@ void GetMappingRequest::start() { GetAllMappingsRequest::GetAllMappingsRequest() { }; -void GetAllMappingsRequest::start() { +void GetAllMappingsRequest::doStart() { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); return; @@ -72,8 +90,20 @@ void GetAllMappingsRequest::start() { auto assetClient = DependencyManager::get(); assetClient->getAllAssetMappings([this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { - // read message - _error = error; + 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); @@ -92,7 +122,7 @@ void GetAllMappingsRequest::start() { SetMappingRequest::SetMappingRequest(AssetPath path, AssetHash hash) : _path(path), _hash(hash) { }; -void SetMappingRequest::start() { +void SetMappingRequest::doStart() { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); return; @@ -100,8 +130,22 @@ void SetMappingRequest::start() { auto assetClient = DependencyManager::get(); assetClient->setAssetMapping(_path, _hash, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { - // read message - _error = error; + 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; } @@ -112,7 +156,7 @@ void SetMappingRequest::start() { DeleteMappingRequest::DeleteMappingRequest(AssetPath path) : _path(path) { }; -void DeleteMappingRequest::start() { +void DeleteMappingRequest::doStart() { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); return; @@ -120,8 +164,22 @@ void DeleteMappingRequest::start() { auto assetClient = DependencyManager::get(); assetClient->deleteAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { - // read message - _error = error; + 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); } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index f95f4bc9bc..b51e7f5316 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -43,78 +43,94 @@ using GetInfoCallback = std::function; using ProgressCallback = std::function; +class MappingRequest : public QObject { + Q_OBJECT +public: + enum Error { + NoError, + NotFound, + NetworkError, + PermissionDenied, + UnknownError + }; -class GetMappingRequest : public QObject { + 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); - Q_INVOKABLE void start(); - - AssetHash getHash() { return _hash; } - AssetServerError getError() { return _error; } + AssetHash getHash() const { return _hash; } signals: void finished(GetMappingRequest* thisRequest); private: + virtual void doStart() override; + AssetPath _path; AssetHash _hash; - AssetServerError _error { AssetServerError::NoError }; }; -class SetMappingRequest : public QObject { +class SetMappingRequest : public MappingRequest { Q_OBJECT public: SetMappingRequest(AssetPath path, AssetHash hash); - Q_INVOKABLE void start(); - - AssetHash getHash() { return _hash; } - AssetServerError getError() { return _error; } + AssetHash getHash() const { return _hash; } signals: void finished(SetMappingRequest* thisRequest); private: + virtual void doStart() override; + AssetPath _path; AssetHash _hash; - AssetServerError _error { AssetServerError::NoError }; }; -class DeleteMappingRequest : public QObject { +class DeleteMappingRequest : public MappingRequest { Q_OBJECT public: DeleteMappingRequest(AssetPath path); Q_INVOKABLE void start(); - AssetServerError getError() { return _error; } - signals: void finished(DeleteMappingRequest* thisRequest); private: + virtual void doStart() override; + AssetPath _path; - AssetServerError _error { AssetServerError::NoError }; }; -class GetAllMappingsRequest : public QObject { +class GetAllMappingsRequest : public MappingRequest { Q_OBJECT public: GetAllMappingsRequest(); Q_INVOKABLE void start(); - AssetServerError getError() { return _error; } - AssetMapping getMappings() { return _mappings; } + AssetMapping getMappings() const { return _mappings; } signals: void finished(GetAllMappingsRequest* thisRequest); private: + virtual void doStart() override; + std::map _mappings; - AssetServerError _error { AssetServerError::NoError }; }; From 93d3fb5ccfc983c8c3e154baa3da6ef774ea5688 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 11:19:08 -0800 Subject: [PATCH 042/209] Fix network error response for mapping requests --- libraries/networking/src/AssetClient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index b447380e5c..1df9fae192 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -703,7 +703,7 @@ void AssetClient::handleNodeKilled(SharedNodePointer node) { auto messageMapIt = _pendingMappingRequests.find(node); if (messageMapIt != _pendingMappingRequests.end()) { for (const auto& value : messageMapIt->second) { - value.second(false, AssetServerError::PermissionDenied, QSharedPointer()); + value.second(false, AssetServerError::NoError, QSharedPointer()); } messageMapIt->second.clear(); } From 5368ae3f9144c1b2cb01c7330eb29433c642e998 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 11:20:15 -0800 Subject: [PATCH 043/209] Remove extraneous thread checks in MappingRequest subclasses --- libraries/networking/src/AssetClient.cpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 1df9fae192..7631ec5292 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -83,11 +83,6 @@ GetAllMappingsRequest::GetAllMappingsRequest() { }; void GetAllMappingsRequest::doStart() { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); - return; - } - auto assetClient = DependencyManager::get(); assetClient->getAllAssetMappings([this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { if (!responseReceived) { @@ -123,11 +118,6 @@ SetMappingRequest::SetMappingRequest(AssetPath path, AssetHash hash) : _path(pat }; void SetMappingRequest::doStart() { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); - return; - } - auto assetClient = DependencyManager::get(); assetClient->setAssetMapping(_path, _hash, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { if (!responseReceived) { @@ -157,11 +147,6 @@ DeleteMappingRequest::DeleteMappingRequest(AssetPath path) : _path(path) { }; void DeleteMappingRequest::doStart() { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); - return; - } - auto assetClient = DependencyManager::get(); assetClient->deleteAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { if (!responseReceived) { From 063826638e8ef963e6b768b87083b726acb28180 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 11:39:28 -0800 Subject: [PATCH 044/209] move handling of get all operation to sep method --- assignment-client/src/assets/AssetServer.cpp | 21 +++++++++++++------- assignment-client/src/assets/AssetServer.h | 1 + 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 4ff9715a7d..fadb6fcc13 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -190,13 +190,7 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me break; } case AssetMappingOperationType::GetAll: { - replyPacket->writePrimitive(AssetServerError::NoError); - auto count = _fileMappings.size(); - replyPacket->writePrimitive(count); - for (auto it = _fileMappings.cbegin(); it != _fileMappings.cend(); ++ it) { - replyPacket->writeString(it.key()); - replyPacket->write(QByteArray::fromHex(it.value().toString().toLocal8Bit())); - } + handleGetAllMappingOperation(*message, senderNode, *replyPacket); break; } case AssetMappingOperationType::Set: { @@ -229,6 +223,19 @@ void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNode } } +void AssetServer::handleGetAllMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket) { + replyPacket.writePrimitive(AssetServerError::NoError); + + auto count = _fileMappings.size(); + + replyPacket.writePrimitive(count); + + for (auto it = _fileMappings.cbegin(); it != _fileMappings.cend(); ++ it) { + replyPacket.writeString(it.key()); + replyPacket.write(QByteArray::fromHex(it.value().toString().toUtf8())); + } +} + void AssetServer::handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket) { if (senderNode->getCanRez()) { QString assetPath = message.readString(); diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index c4d59a7450..45ec7c6750 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -42,6 +42,7 @@ private: using Mappings = QVariantHash; void handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); + void handleGetAllMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); void handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); void handleDeleteMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); From 4236d8e147ef7ecd05f4c791d380cec03924698e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 11:40:35 -0800 Subject: [PATCH 045/209] replace toLocal8Bit with toUtf8 for hex conversions --- assignment-client/src/assets/AssetServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index fadb6fcc13..2b294fd659 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -215,7 +215,7 @@ void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNode auto assetHash = it->toString(); qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; replyPacket.writePrimitive(AssetServerError::NoError); - replyPacket.write(QByteArray::fromHex(assetHash.toLocal8Bit())); + replyPacket.write(QByteArray::fromHex(assetHash.toUtf8())); } else { qDebug() << "Mapping not found for: " << assetPath; From 8107287e6c69551cb894c4ce872fde6525c4a4ba Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 11:42:57 -0800 Subject: [PATCH 046/209] remove start from mapping request subclasses --- libraries/networking/src/AssetClient.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 19544d18e0..cc0eaab035 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -104,8 +104,6 @@ class DeleteMappingRequest : public MappingRequest { public: DeleteMappingRequest(AssetPath path); - Q_INVOKABLE void start(); - signals: void finished(DeleteMappingRequest* thisRequest); @@ -120,8 +118,6 @@ class GetAllMappingsRequest : public MappingRequest { public: GetAllMappingsRequest(); - Q_INVOKABLE void start(); - AssetMapping getMappings() const { return _mappings; } signals: From 7ecfc20dc2000c329db12fa3f05b4a2d12a672f6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 11:47:11 -0800 Subject: [PATCH 047/209] add error handling for asset-server files directory --- assignment-client/src/assets/AssetServer.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 2b294fd659..2d6301e2b8 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -100,10 +100,13 @@ void AssetServer::completeSetup() { qDebug() << "Creating resources directory"; _resourcesDirectory.mkpath("."); - _resourcesDirectory.mkpath(ASSET_FILES_SUBDIR); + _filesDirectory = _resourcesDirectory; - _filesDirectory = _resourcesDirectory; - _filesDirectory.cd(ASSET_FILES_SUBDIR); + if (!_resourcesDirectory.mkpath(ASSET_FILES_SUBDIR) || !_filesDirectory.cd(ASSET_FILES_SUBDIR)) { + qCritical() << "Unable to create file directory for asset-server files. Stopping assignment."; + setFinished(true); + return; + } // load whatever mappings we currently have from the local file loadMappingsFromFile(); From 4608eddb401e815f3af6d58270ac271cdf84d437 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 11:47:55 -0800 Subject: [PATCH 048/209] remove an extra blank line --- assignment-client/src/assets/AssetServer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 2d6301e2b8..a08bad3212 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -162,7 +162,6 @@ void AssetServer::performMappingMigration() { if (it == _fileMappings.end()) { _fileMappings[fakeFileName] = hash; - if (writeMappingsToFile()) { // mapping added and persisted, we can remove the migrated file oldFile.remove(); From c4845e5ae542caff9163b987f19aec0b69b31a16 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 11:50:23 -0800 Subject: [PATCH 049/209] remove getMapping call from AssetServer that is unused --- assignment-client/src/assets/AssetServer.cpp | 4 ---- assignment-client/src/assets/AssetServer.h | 3 --- 2 files changed, 7 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index a08bad3212..4768905b25 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -455,10 +455,6 @@ bool AssetServer::writeMappingsToFile() { return false; } -AssetHash AssetServer::getMapping(AssetPath path) { - return _fileMappings.value(path).toString(); -} - bool AssetServer::setMapping(AssetPath path, AssetHash hash) { // remember what the old mapping was in case persistence fails auto oldMapping = _fileMappings.value(path).toString(); diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 45ec7c6750..53a76248d6 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -50,9 +50,6 @@ private: void loadMappingsFromFile(); bool writeMappingsToFile(); - /// Return the hash mapping for AssetPath `path` - AssetHash getMapping(AssetPath path); - /// Set the mapping for path to hash bool setMapping(AssetPath path, AssetHash hash); From 88c1892bf657fce79d2edadefd2e6d6aa8d7f919 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 11:51:59 -0800 Subject: [PATCH 050/209] remove a comment block re-added in merge --- libraries/networking/src/AssetRequest.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/networking/src/AssetRequest.h b/libraries/networking/src/AssetRequest.h index 4c35a46fe7..ac4485a683 100644 --- a/libraries/networking/src/AssetRequest.h +++ b/libraries/networking/src/AssetRequest.h @@ -52,9 +52,6 @@ signals: void finished(AssetRequest* thisRequest); void progress(qint64 totalReceived, qint64 total); -//private slots: - //void getAssetCallback(bool responseReceived, AssetServerError serverError, const QByteArray& data); - private: State _state = NotStarted; Error _error = NoError; From e92a9c9741291b2245f7eda1152de0fd89c51c12 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 11:53:53 -0800 Subject: [PATCH 051/209] fix comment for asset packet version push --- libraries/networking/src/udt/PacketHeaders.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 2c53e01b2a..cbb3374e8c 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -55,7 +55,7 @@ PacketVersion versionForPacketType(PacketType packetType) { return 18; // ICE Server Heartbeat signing case PacketType::AssetGetInfo: case PacketType::AssetGet: - // Introduction of ATP Mappings + // Removal of extension from Asset requests return 18; default: return 17; From 7cc774c5f4f8e2d615e1a13da56a6c944322973f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 11:55:29 -0800 Subject: [PATCH 052/209] indentation fix for _filesDirectory in AssetServer --- assignment-client/src/assets/AssetServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 4768905b25..c6eb314723 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -100,7 +100,7 @@ void AssetServer::completeSetup() { qDebug() << "Creating resources directory"; _resourcesDirectory.mkpath("."); - _filesDirectory = _resourcesDirectory; + _filesDirectory = _resourcesDirectory; if (!_resourcesDirectory.mkpath(ASSET_FILES_SUBDIR) || !_filesDirectory.cd(ASSET_FILES_SUBDIR)) { qCritical() << "Unable to create file directory for asset-server files. Stopping assignment."; From 1ece9aac2682c5cad73e6a1d80344c928790c184 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 12:08:02 -0800 Subject: [PATCH 053/209] remove extension from asset upload task --- .../src/assets/UploadAssetTask.cpp | 9 ++------- libraries/networking/src/AssetClient.cpp | 17 +++++++---------- libraries/networking/src/AssetClient.h | 6 +++--- libraries/networking/src/AssetUpload.cpp | 14 ++++---------- libraries/networking/src/AssetUpload.h | 4 +--- libraries/networking/src/udt/PacketHeaders.cpp | 1 + .../src/RecordingScriptingInterface.cpp | 4 ++-- 7 files changed, 20 insertions(+), 35 deletions(-) diff --git a/assignment-client/src/assets/UploadAssetTask.cpp b/assignment-client/src/assets/UploadAssetTask.cpp index 114fd20320..0856a29e1f 100644 --- a/assignment-client/src/assets/UploadAssetTask.cpp +++ b/assignment-client/src/assets/UploadAssetTask.cpp @@ -37,15 +37,10 @@ void UploadAssetTask::run() { MessageID messageID; buffer.read(reinterpret_cast(&messageID), sizeof(messageID)); - uint8_t extensionLength; - buffer.read(reinterpret_cast(&extensionLength), sizeof(extensionLength)); - - QByteArray extension = buffer.read(extensionLength); - uint64_t fileSize; buffer.read(reinterpret_cast(&fileSize), sizeof(fileSize)); - qDebug() << "UploadAssetTask reading a file of " << fileSize << "bytes and extension" << extension << "from" + qDebug() << "UploadAssetTask reading a file of " << fileSize << "bytes from" << uuidStringWithoutCurlyBraces(_senderNode->getUUID()); auto replyPacket = NLPacket::create(PacketType::AssetUploadReply); @@ -62,7 +57,7 @@ void UploadAssetTask::run() { qDebug() << "Hash for uploaded file from" << uuidStringWithoutCurlyBraces(_senderNode->getUUID()) << "is: (" << hexHash << ") "; - QFile file { _resourcesDir.filePath(QString(hexHash)) + "." + QString(extension) }; + QFile file { _resourcesDir.filePath(QString(hexHash)) }; if (file.exists()) { qDebug() << "[WARNING] This file already exists: " << hexHash; diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index b022052409..a443cd3078 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -328,9 +328,9 @@ AssetUpload* AssetClient::createUpload(const QString& filename) { } } -AssetUpload* AssetClient::createUpload(const QByteArray& data, const QString& extension) { +AssetUpload* AssetClient::createUpload(const QByteArray& data) { if (haveAssetServer()) { - auto upload = new AssetUpload(data, extension); + auto upload = new AssetUpload(data); upload->moveToThread(thread()); @@ -579,7 +579,7 @@ bool AssetClient::setAssetMapping(const QString& path, const AssetHash& hash, Ma return false; } -bool AssetClient::uploadAsset(const QByteArray& data, const QString& extension, UploadResultCallback callback) { +bool AssetClient::uploadAsset(const QByteArray& data, UploadResultCallback callback) { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); @@ -589,9 +589,6 @@ bool AssetClient::uploadAsset(const QByteArray& data, const QString& extension, auto messageID = ++_currentID; packetList->writePrimitive(messageID); - packetList->writePrimitive(static_cast(extension.length())); - packetList->write(extension.toLatin1().constData(), extension.length()); - uint64_t size = data.length(); packetList->writePrimitive(size); packetList->write(data.constData(), size); @@ -692,17 +689,17 @@ void AssetClient::handleNodeKilled(SharedNodePointer node) { _mappingCache.clear(); } -void AssetScriptingInterface::uploadData(QString data, QString extension, QScriptValue callback) { +void AssetScriptingInterface::uploadData(QString data, QScriptValue callback) { QByteArray dataByteArray = data.toUtf8(); - auto upload = DependencyManager::get()->createUpload(dataByteArray, extension); + 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, extension](AssetUpload* upload, const QString& hash) mutable { + QObject::connect(upload, &AssetUpload::finished, this, [this, callback](AssetUpload* upload, const QString& hash) mutable { if (callback.isFunction()) { - QString url = "atp://" + hash + "." + extension; + QString url = "atp://" + hash; QScriptValueList args { url }; callback.call(_engine->currentContext()->thisObject(), args); } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index cc0eaab035..44a62f834a 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -140,7 +140,7 @@ public: Q_INVOKABLE SetMappingRequest* createSetMappingRequest(const AssetPath& path, const AssetHash& hash); Q_INVOKABLE AssetRequest* createRequest(const AssetHash& hash); Q_INVOKABLE AssetUpload* createUpload(const QString& filename); - Q_INVOKABLE AssetUpload* createUpload(const QByteArray& data, const QString& extension); + Q_INVOKABLE AssetUpload* createUpload(const QByteArray& data); public slots: void init(); @@ -165,7 +165,7 @@ private: bool getAssetInfo(const QString& hash, GetInfoCallback callback); bool getAsset(const QString& hash, DataOffset start, DataOffset end, ReceivedAssetCallback callback, ProgressCallback progressCallback); - bool uploadAsset(const QByteArray& data, const QString& extension, UploadResultCallback callback); + bool uploadAsset(const QByteArray& data, UploadResultCallback callback); struct GetAssetCallbacks { ReceivedAssetCallback completeCallback; @@ -194,7 +194,7 @@ class AssetScriptingInterface : public QObject { public: AssetScriptingInterface(QScriptEngine* engine); - Q_INVOKABLE void uploadData(QString data, QString extension, QScriptValue callback); + 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); diff --git a/libraries/networking/src/AssetUpload.cpp b/libraries/networking/src/AssetUpload.cpp index 1189c341b1..754d632cce 100644 --- a/libraries/networking/src/AssetUpload.cpp +++ b/libraries/networking/src/AssetUpload.cpp @@ -19,9 +19,8 @@ const QString AssetUpload::PERMISSION_DENIED_ERROR = "You do not have permission to upload content to this asset-server."; -AssetUpload::AssetUpload(const QByteArray& data, const QString& extension) : - _data(data), - _extension(extension) +AssetUpload::AssetUpload(const QByteArray& data) : + _data(data) { } @@ -59,12 +58,7 @@ void AssetUpload::start() { // try to open the file at the given filename QFile file { _filename }; - if (file.open(QIODevice::ReadOnly)) { - - // file opened, read the data and grab the extension - _extension = QFileInfo(_filename).suffix(); - _extension = _extension.toLower(); - + if (file.open(QIODevice::ReadOnly)) { _data = file.readAll(); } else { // we couldn't open the file - set the error result @@ -82,7 +76,7 @@ void AssetUpload::start() { qCDebug(asset_client) << "Attempting to upload" << _filename << "to asset-server."; } - assetClient->uploadAsset(_data, _extension, [this](bool responseReceived, AssetServerError error, const QString& hash){ + assetClient->uploadAsset(_data, [this](bool responseReceived, AssetServerError error, const QString& hash){ if (!responseReceived) { _error = NetworkError; } else { diff --git a/libraries/networking/src/AssetUpload.h b/libraries/networking/src/AssetUpload.h index 92f677cbf2..656c1a281e 100644 --- a/libraries/networking/src/AssetUpload.h +++ b/libraries/networking/src/AssetUpload.h @@ -38,12 +38,11 @@ public: static const QString PERMISSION_DENIED_ERROR; AssetUpload(const QString& filename); - AssetUpload(const QByteArray& data, const QString& extension); + AssetUpload(const QByteArray& data); Q_INVOKABLE void start(); const QString& getFilename() const { return _filename; } - const QString& getExtension() const { return _extension; } const Error& getError() const { return _error; } QString getErrorString() const; @@ -54,7 +53,6 @@ signals: private: QString _filename; QByteArray _data; - QString _extension; Error _error; }; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index cbb3374e8c..df1a6f1bec 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -55,6 +55,7 @@ PacketVersion versionForPacketType(PacketType packetType) { return 18; // ICE Server Heartbeat signing case PacketType::AssetGetInfo: case PacketType::AssetGet: + case PacketType::AssetUpload: // Removal of extension from Asset requests return 18; default: diff --git a/libraries/script-engine/src/RecordingScriptingInterface.cpp b/libraries/script-engine/src/RecordingScriptingInterface.cpp index 25abf2e09e..710f342322 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.cpp +++ b/libraries/script-engine/src/RecordingScriptingInterface.cpp @@ -198,13 +198,13 @@ bool RecordingScriptingInterface::saveRecordingToAsset(QScriptValue getClipAtpUr return false; } - if (auto upload = DependencyManager::get()->createUpload(recording::Clip::toBuffer(_lastClip), HFR_EXTENSION)) { + if (auto upload = DependencyManager::get()->createUpload(recording::Clip::toBuffer(_lastClip))) { QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { QString clip_atp_url = ""; if (upload->getError() == AssetUpload::NoError) { - clip_atp_url = QString("%1:%2.%3").arg(URL_SCHEME_ATP, hash, upload->getExtension()); + clip_atp_url = QString("%1:%2").arg(URL_SCHEME_ATP, hash); upload->deleteLater(); } else { qCWarning(scriptengine) << "Error during the Asset upload."; From 8fa32e75b2c06e08785b6b92cb47fc1b4b787ea2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 12:18:39 -0800 Subject: [PATCH 054/209] client side fixes for upload with no extension --- assignment-client/src/assets/AssetServer.cpp | 18 ++++++++++++------ interface/src/Application.cpp | 6 +++--- interface/src/assets/ATPAssetMigrator.cpp | 2 +- interface/src/ui/AssetUploadDialogFactory.cpp | 2 +- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index c6eb314723..cbcce9d45e 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -421,14 +421,20 @@ void AssetServer::loadMappingsFromFile() { QFile mapFile { mapFilePath }; if (mapFile.exists()) { if (mapFile.open(QIODevice::ReadOnly)) { - auto jsonDocument = QJsonDocument::fromJson(mapFile.readAll()); - _fileMappings = jsonDocument.object().toVariantHash(); + QJsonParseError error; - qInfo() << "Loaded" << _fileMappings.count() << "mappings from map file at" << mapFilePath; - } else { - qCritical() << "Failed to read mapping file at" << mapFilePath << "- assignment with not continue."; - setFinished(true); + auto jsonDocument = QJsonDocument::fromJson(mapFile.readAll(), &error); + + if (error.error == QJsonParseError::NoError) { + _fileMappings = jsonDocument.object().toVariantHash(); + + qInfo() << "Loaded" << _fileMappings.count() << "mappings from map file at" << mapFilePath; + return; + } } + + qCritical() << "Failed to read mapping file at" << mapFilePath << "- assignment with not continue."; + setFinished(true); } else { qInfo() << "No existing mappings loaded from file since no file was found at" << mapFilePath; } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 660e597752..fdd9a2c008 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4334,14 +4334,14 @@ void Application::modelUploadFinished(AssetUpload* upload, const QString& hash) auto filename = QFileInfo(upload->getFilename()).fileName(); if ((upload->getError() == AssetUpload::NoError) && - (FBX_EXTENSION.endsWith(upload->getExtension(), Qt::CaseInsensitive) || - OBJ_EXTENSION.endsWith(upload->getExtension(), Qt::CaseInsensitive))) { + (filename.endsWith(FBX_EXTENSION, Qt::CaseInsensitive) || + filename.endsWith(OBJ_EXTENSION, Qt::CaseInsensitive))) { auto entities = DependencyManager::get(); EntityItemProperties properties; properties.setType(EntityTypes::Model); - properties.setModelURL(QString("%1:%2.%3").arg(URL_SCHEME_ATP).arg(hash).arg(upload->getExtension())); + properties.setModelURL(QString("%1:%2").arg(URL_SCHEME_ATP).arg(hash); properties.setPosition(_myCamera.getPosition() + _myCamera.getOrientation() * Vectors::FRONT * 2.0f); properties.setName(QUrl(upload->getFilename()).fileName()); diff --git a/interface/src/assets/ATPAssetMigrator.cpp b/interface/src/assets/ATPAssetMigrator.cpp index dba2047da1..51b2ac558a 100644 --- a/interface/src/assets/ATPAssetMigrator.cpp +++ b/interface/src/assets/ATPAssetMigrator.cpp @@ -142,7 +142,7 @@ void ATPAssetMigrator::migrateResource(ResourceRequest* request) { QFileInfo assetInfo { request->getUrl().fileName() }; - auto upload = assetClient->createUpload(request->getData(), assetInfo.completeSuffix()); + auto upload = assetClient->createUpload(request->getData()); if (upload) { // add this URL to our hash of AssetUpload to original URL diff --git a/interface/src/ui/AssetUploadDialogFactory.cpp b/interface/src/ui/AssetUploadDialogFactory.cpp index 9cd319815b..46f07cb7df 100644 --- a/interface/src/ui/AssetUploadDialogFactory.cpp +++ b/interface/src/ui/AssetUploadDialogFactory.cpp @@ -87,7 +87,7 @@ void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const Q // setup the line edit to hold the copiable text QLineEdit* lineEdit = new QLineEdit; - QString atpURL = QString("%1:%2.%3").arg(URL_SCHEME_ATP).arg(hash).arg(upload->getExtension()); + QString atpURL = QString("%1:%2").arg(URL_SCHEME_ATP).arg(hash); // set the ATP URL as the text value so it's copiable lineEdit->insert(atpURL); From cf5de317bab54554ae639787eda02c9d420861b1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 12:21:54 -0800 Subject: [PATCH 055/209] use correct error handling for MappingRequest errors --- libraries/networking/src/AssetResourceRequest.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index d4188467ab..fcc4e12456 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -72,14 +72,14 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) { Q_ASSERT(request == _assetMappingRequest); switch (request->getError()) { - case AssetServerError::NoError: + case MappingRequest::NoError: // we have no error, we should have a resulting hash - use that to send of a request for that asset qDebug() << "Got mapping for:" << path << "=>" << request->getHash(); requestHash(request->getHash()); break; - case AssetServerError::AssetNotFound: + case MappingRequest::NotFound: // no result for the mapping request, set error to not found _result = NotFound; @@ -90,6 +90,12 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) { break; default: // these are unexpected errors for a GetMappingRequest object + _result = Error; + + // since we've failed we know we are finished + _state = Finished; + emit finished(); + break; } From 28af9c51e6f620d875db4a7982fcfb701ede6c3f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 12:22:13 -0800 Subject: [PATCH 056/209] add a missing parenthesis --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fdd9a2c008..c4c94a1ed5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4341,7 +4341,7 @@ void Application::modelUploadFinished(AssetUpload* upload, const QString& hash) EntityItemProperties properties; properties.setType(EntityTypes::Model); - properties.setModelURL(QString("%1:%2").arg(URL_SCHEME_ATP).arg(hash); + properties.setModelURL(QString("%1:%2").arg(URL_SCHEME_ATP).arg(hash)); properties.setPosition(_myCamera.getPosition() + _myCamera.getOrientation() * Vectors::FRONT * 2.0f); properties.setName(QUrl(upload->getFilename()).fileName()); From 969244927b291e5869ab16d398592ad06f6be15a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 13:09:20 -0800 Subject: [PATCH 057/209] use extension for entity add for drag and drop upload --- interface/src/Application.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c4c94a1ed5..a079c3ccbe 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4331,7 +4331,8 @@ bool Application::askToUploadAsset(const QString& filename) { } void Application::modelUploadFinished(AssetUpload* upload, const QString& hash) { - auto filename = QFileInfo(upload->getFilename()).fileName(); + auto fileInfo = QFileInfo(upload->getFilename()); + auto filename = fileInfo.fileName(); if ((upload->getError() == AssetUpload::NoError) && (filename.endsWith(FBX_EXTENSION, Qt::CaseInsensitive) || @@ -4341,7 +4342,7 @@ void Application::modelUploadFinished(AssetUpload* upload, const QString& hash) EntityItemProperties properties; properties.setType(EntityTypes::Model); - properties.setModelURL(QString("%1:%2").arg(URL_SCHEME_ATP).arg(hash)); + properties.setModelURL(QString("%1:%2.%3").arg(URL_SCHEME_ATP).arg(hash).arg(fileInfo.completeSuffix())); properties.setPosition(_myCamera.getPosition() + _myCamera.getOrientation() * Vectors::FRONT * 2.0f); properties.setName(QUrl(upload->getFilename()).fileName()); From 784f6699989593829291126e387e6cabd20e16f8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Mar 2016 18:30:25 -0800 Subject: [PATCH 058/209] First draft Assets Manager --- interface/resources/qml/AssetsManager.qml | 167 ++++++++++++++++++++ interface/resources/qml/hifi/MenuOption.qml | 1 + interface/src/Application.cpp | 5 + interface/src/Application.h | 1 + interface/src/Menu.cpp | 6 +- interface/src/Menu.h | 1 + 6 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 interface/resources/qml/AssetsManager.qml diff --git a/interface/resources/qml/AssetsManager.qml b/interface/resources/qml/AssetsManager.qml new file mode 100644 index 0000000000..ac64bc07c6 --- /dev/null +++ b/interface/resources/qml/AssetsManager.qml @@ -0,0 +1,167 @@ +// +// AssetsManager.qml +// +// Created by Clement on 3/1/16 +// 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 +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Dialogs 1.2 as OriginalDialogs +import Qt.labs.settings 1.0 + +import "styles-uit" +import "controls-uit" as HifiControls +import "windows-uit" + +Window { + id: root + objectName: "AssetsManager" + title: "Assets Server" + resizable: true + destroyOnInvisible: true + x: 40; y: 40 + implicitWidth: 384; implicitHeight: 640 + minSize: Qt.vector2d(200, 300) + + HifiConstants { id: hifi } + + property var scripts: ScriptDiscoveryService; + property var scriptsModel: scripts.scriptsModelFilter + property var runningScriptsModel: ListModel { } + + Settings { + category: "Overlay.AssetManager" + property alias x: root.x + property alias y: root.y + } + + Component.onCompleted: updateRunningScripts() + + function updateRunningScripts() { + var runningScripts = ScriptDiscoveryService.getRunning(); + runningScriptsModel.clear() + for (var i = 0; i < runningScripts.length; ++i) { + runningScriptsModel.append(runningScripts[i]); + } + } + + Column { + width: pane.contentWidth + + HifiControls.StaticSection { + name: "Asset Directory" + + Row { + id: buttonRow + anchors.left: parent.left + anchors.right: parent.right + + HifiControls.Button { + text: "<" + color: hifi.buttons.white + height: 26 + width: 26 + } + + HifiControls.Button { + text: "O" + color: hifi.buttons.white + height: 26 + width: 26 + } + } + + Item { + // Take the browseButton out of the column flow. + id: deleteButtonContainer + anchors.top: buttonRow.top + anchors.right: parent.right + + HifiControls.Button { + id: deleteButton + anchors.right: parent.right + + text: "DELETE SELECTION" + color: hifi.buttons.red + height: 26 + width: 130 + } + } + + HifiControls.Tree { + id: treeView + height: 155 + treeModel: scriptsModel + colorScheme: hifi.colorSchemes.light + anchors.left: parent.left + anchors.right: parent.right + } + } + + HifiControls.StaticSection { + name: "Upload File" + hasSeparator: true + + HifiControls.TextField { + id: fileUrl + anchors.left: parent.left + anchors.right: parent.right + anchors.rightMargin: chooseButton.width + hifi.dimensions.contentSpacing.x + + label: "Paste URL or choose file" + colorScheme: hifi.colorSchemes.light + } + + Item { + // Take the chooseButton out of the column flow. + id: chooseButtonContainer + anchors.top: fileUrl.top + anchors.right: parent.right + + HifiControls.Button { + id: chooseButton + anchors.right: parent.right + + text: "Choose" + color: hifi.buttons.white + enabled: true + + width: 100 + } + } + + CheckBox { + id: addToScene + anchors.left: parent.left + anchors.right: parent.right + anchors.rightMargin: uploadButton.width + hifi.dimensions.contentSpacing.x + + text: "Add to scene on upload" + checked: false + } + + Item { + // Take the browseButton out of the column flow. + id: uploadButtonContainer + anchors.top: addToScene.top + anchors.right: parent.right + + HifiControls.Button { + id: uploadButton + anchors.right: parent.right + + text: "Upload" + color: hifi.buttons.blue + enabled: true + height: 30 + width: 155 + } + } + } + } +} + diff --git a/interface/resources/qml/hifi/MenuOption.qml b/interface/resources/qml/hifi/MenuOption.qml index 9ebf5adb54..4894834225 100644 --- a/interface/resources/qml/hifi/MenuOption.qml +++ b/interface/resources/qml/hifi/MenuOption.qml @@ -10,6 +10,7 @@ QtObject { readonly property string animDebugDrawPosition: "Debug Draw Position"; readonly property string antialiasing: "Antialiasing"; readonly property string assetMigration: "ATP Asset Migration"; + readonly property string assetsManager = "Assets Manager"; readonly property string atmosphere: "Atmosphere"; readonly property string attachments: "Attachments..."; readonly property string audioNetworkStats: "Audio Network Stats"; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a079c3ccbe..59d0b55dee 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4453,6 +4453,11 @@ void Application::toggleRunningScriptsWidget() { //} } +void Application::toggleAssetsManagerWidget() { + static const QUrl url("AssetsManager.qml"); + DependencyManager::get()->show(url, "AssetsManager"); +} + void Application::packageModel() { ModelPackager::package(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 3a727db533..de744e73ab 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -242,6 +242,7 @@ public slots: Q_INVOKABLE void loadScriptURLDialog(); void toggleLogDialog(); void toggleRunningScriptsWidget(); + void toggleAssetsManagerWidget(); void handleLocalServerConnection(); void readArgumentsFromLocalSocket(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d605516380..5c04c1ce38 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -99,10 +99,14 @@ Menu::Menu() { redoAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Z); addActionToQMenuAndActionHash(editMenu, redoAction); - // Edit > Running Sccripts + // Edit > Running Scripts addActionToQMenuAndActionHash(editMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J, qApp, SLOT(toggleRunningScriptsWidget())); + // Edit > Assets Manager + addActionToQMenuAndActionHash(editMenu, MenuOption::AssetsManager, 0, + qApp, SLOT(toggleAssetsManagerWidget())); + // Edit > Open and Run Script from File... [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, qApp, SLOT(loadDialog()), diff --git a/interface/src/Menu.h b/interface/src/Menu.h index fb00416af0..d08540973d 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -35,6 +35,7 @@ namespace MenuOption { const QString AnimDebugDrawDefaultPose = "Debug Draw Default Pose"; const QString AnimDebugDrawPosition= "Debug Draw Position"; const QString AssetMigration = "ATP Asset Migration"; + const QString AssetsManager = "Assets Manager"; const QString Attachments = "Attachments..."; const QString AudioNetworkStats = "Audio Network Stats"; const QString AudioNoiseReduction = "Audio Noise Reduction"; From 82d6d3ff01e2c9135f93bc14ac4eb8b1794c93b3 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Mar 2016 11:32:46 -0800 Subject: [PATCH 059/209] Small fix to buttons color --- .../resources/qml/controls-uit/Button.qml | 37 ++++++++++++++----- .../qml/styles-uit/HifiConstants.qml | 9 ++++- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/interface/resources/qml/controls-uit/Button.qml b/interface/resources/qml/controls-uit/Button.qml index 5daec8eb36..fd18bc2a6f 100644 --- a/interface/resources/qml/controls-uit/Button.qml +++ b/interface/resources/qml/controls-uit/Button.qml @@ -16,7 +16,10 @@ import "../styles-uit" Original.Button { id: button + property int color: 0 + property int colorScheme: hifi.colorShemes.light + width: 120 height: 28 @@ -24,27 +27,43 @@ Original.Button { background: Rectangle { radius: hifi.buttons.radius + gradient: Gradient { GradientStop { position: 0.2 - color: enabled - ? (!pressed && button.color != hifi.buttons.black || (!hovered || pressed) && button.color == hifi.buttons.black - ? hifi.buttons.colorStart[button.color] : hifi.buttons.colorFinish[button.color]) - : hifi.buttons.colorStart[hifi.buttons.white] + color: { + if (!enabled) { + hifi.buttons.disabledColorStart[button.colorScheme] + } else if (pressed) { + hifi.buttons.pressedColor[button.color] + } else if (hovered) { + hifi.buttons.hoveredColor[button.color] + } else { + hifi.buttons.colorStart[button.color] + } + } } GradientStop { position: 1.0 - color: enabled - ? ((!hovered || pressed) && button.color != hifi.buttons.black || !pressed && button.color == hifi.buttons.black - ? hifi.buttons.colorFinish[button.color] : hifi.buttons.colorStart[button.color]) - : hifi.buttons.colorFinish[hifi.buttons.white] + color: { + if (!enabled) { + hifi.buttons.disabledColorFinish[button.colorScheme] + } else if (pressed) { + hifi.buttons.pressedColor[button.color] + } else if (hovered) { + hifi.buttons.hoveredColor[button.color] + } else { + hifi.buttons.colorFinish[button.color] + } + } } } } label: RalewayBold { font.capitalization: Font.AllUppercase - color: enabled ? hifi.buttons.textColor[button.color] : hifi.colors.lightGrayText + color: enabled ? hifi.buttons.textColor[button.color] + : hifi.buttons.disabledTextColor[button.colorScheme] size: hifi.fontSizes.buttonLabel verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 108cf8a221..5f77052c63 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -159,8 +159,13 @@ Item { readonly property int red: 2 readonly property int black: 3 readonly property var textColor: [ colors.darkGray, colors.white, colors.white, colors.white ] - readonly property var colorStart: [ "#ffffff", "#00b4ef", "#d42043", "#343434" ] - readonly property var colorFinish: [ "#afafaf", "#1080b8", "#94132e", "#000000" ] + readonly property var colorStart: [ colors.white, colors.primaryHighlight, "#d42043", "#343434" ] + readonly property var colorFinish: [ colors.lightGrayText, colors.blueAccent, "#94132e", colors.black ] + readonly property var hoveredColor: [ colorStart[white], colorStart[blue], colorStart[red], colorFinish[black] ] + readonly property var pressedColor: [ colorFinish[white], colorFinish[blue], colorFinish[red], colorStart[black] ] + readonly property var disabledColorStart: [ colorStart[white], colors.baseGrayHighlight] + readonly property var disabledColorFinish: [ colorFinish[white], colors.baseGrayShadow] + readonly property var disabledTextColor: [ colors.lightGrayText, colors.baseGrayShadow] readonly property int radius: 5 } From 30a6dd86294d05cb7ea3f8696771e47b17d1afac Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Mar 2016 11:33:12 -0800 Subject: [PATCH 060/209] Update StaticSection --- interface/resources/qml/AssetsManager.qml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/AssetsManager.qml b/interface/resources/qml/AssetsManager.qml index ac64bc07c6..6f7297fe3b 100644 --- a/interface/resources/qml/AssetsManager.qml +++ b/interface/resources/qml/AssetsManager.qml @@ -52,8 +52,9 @@ Window { Column { width: pane.contentWidth - HifiControls.StaticSection { + HifiControls.ContentSection { name: "Asset Directory" + isFirst: true Row { id: buttonRow @@ -102,9 +103,8 @@ Window { } } - HifiControls.StaticSection { + HifiControls.ContentSection { name: "Upload File" - hasSeparator: true HifiControls.TextField { id: fileUrl From 6fecb4e1d180c52e2ab5d444a0d2f00d51db457f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Mar 2016 16:05:31 -0800 Subject: [PATCH 061/209] Window fixup --- interface/resources/qml/AssetsManager.qml | 22 ++++++++++++++----- .../qml/controls-uit/ContentSection.qml | 14 +++++++----- .../resources/qml/controls-uit/TextField.qml | 2 +- .../qml/styles-uit/HifiConstants.qml | 7 ++++++ .../resources/qml/windows-uit/Window.qml | 7 ++++-- 5 files changed, 38 insertions(+), 14 deletions(-) diff --git a/interface/resources/qml/AssetsManager.qml b/interface/resources/qml/AssetsManager.qml index 6f7297fe3b..e8bb4e1d9b 100644 --- a/interface/resources/qml/AssetsManager.qml +++ b/interface/resources/qml/AssetsManager.qml @@ -27,6 +27,8 @@ Window { implicitWidth: 384; implicitHeight: 640 minSize: Qt.vector2d(200, 300) + colorScheme: hifi.colorSchemes.light + HifiConstants { id: hifi } property var scripts: ScriptDiscoveryService; @@ -54,6 +56,8 @@ Window { HifiControls.ContentSection { name: "Asset Directory" + spacing: hifi.dimensions.contentSpacing.y + colorScheme: root.colorScheme isFirst: true Row { @@ -64,6 +68,7 @@ Window { HifiControls.Button { text: "<" color: hifi.buttons.white + colorScheme: root.colorScheme height: 26 width: 26 } @@ -71,6 +76,7 @@ Window { HifiControls.Button { text: "O" color: hifi.buttons.white + colorScheme: root.colorScheme height: 26 width: 26 } @@ -88,6 +94,7 @@ Window { text: "DELETE SELECTION" color: hifi.buttons.red + colorScheme: root.colorScheme height: 26 width: 130 } @@ -97,14 +104,16 @@ Window { id: treeView height: 155 treeModel: scriptsModel - colorScheme: hifi.colorSchemes.light + colorScheme: root.colorScheme anchors.left: parent.left anchors.right: parent.right } } HifiControls.ContentSection { - name: "Upload File" + name: "" + spacing: hifi.dimensions.contentSpacing.y + colorScheme: root.colorScheme HifiControls.TextField { id: fileUrl @@ -112,8 +121,9 @@ Window { anchors.right: parent.right anchors.rightMargin: chooseButton.width + hifi.dimensions.contentSpacing.x - label: "Paste URL or choose file" - colorScheme: hifi.colorSchemes.light + label: "Upload File" + placeholderText: "Paste URL or choose file" + colorScheme: root.colorScheme } Item { @@ -128,13 +138,14 @@ Window { text: "Choose" color: hifi.buttons.white + colorScheme: root.colorScheme enabled: true width: 100 } } - CheckBox { + HifiControls.CheckBox { id: addToScene anchors.left: parent.left anchors.right: parent.right @@ -156,6 +167,7 @@ Window { text: "Upload" color: hifi.buttons.blue + colorScheme: root.colorScheme enabled: true height: 30 width: 155 diff --git a/interface/resources/qml/controls-uit/ContentSection.qml b/interface/resources/qml/controls-uit/ContentSection.qml index d51ab9cd1b..1a03ee339c 100644 --- a/interface/resources/qml/controls-uit/ContentSection.qml +++ b/interface/resources/qml/controls-uit/ContentSection.qml @@ -14,10 +14,12 @@ import QtGraphicalEffects 1.0 import "../styles-uit" Column { - property string name: "Static Section" + property string name: "Content Section" property bool isFirst: false property bool isCollapsible: false // Set at creation. property bool isCollapsed: false + property int colorScheme: hifi.colorSchemes.light + readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light spacing: 0 // Defer spacing decisions to individual controls. @@ -60,14 +62,14 @@ Column { id: shadow width: frame.width height: 1 - color: hifi.colors.baseGrayShadow + color: hifi.colors.sectionSeparator1[colorScheme] x: -hifi.dimensions.contentMargin.x } Rectangle { width: frame.width height: 1 - color: hifi.colors.baseGrayHighlight + color: hifi.colors.sectionSeparator2[colorScheme] x: -hifi.dimensions.contentMargin.x anchors.top: shadow.bottom } @@ -104,7 +106,7 @@ Column { y: -2 size: hifi.fontSizes.disclosureButton text: isCollapsed ? hifi.glyphs.disclosureButtonExpand : hifi.glyphs.disclosureButtonCollapse - color: hifi.colors.lightGrayText + color: title.color visible: isCollapsible } @@ -124,8 +126,8 @@ Column { start: Qt.point(0, 0) end: Qt.point(0, 4) gradient: Gradient { - GradientStop { position: 0.0; color: hifi.colors.darkGray } - GradientStop { position: 1.0; color: hifi.colors.baseGray } // Equivalent of darkGray0 over baseGray background. + GradientStop { position: 0.0; color: hifi.colors.sectionGradiantStart[colorScheme] } + GradientStop { position: 1.0; color: hifi.colors.sectionGradiantFinish[colorScheme] } // Equivalent of darkGray0 over baseGray background. } cached: true } diff --git a/interface/resources/qml/controls-uit/TextField.qml b/interface/resources/qml/controls-uit/TextField.qml index ff1bbe8eb6..b0d657652e 100644 --- a/interface/resources/qml/controls-uit/TextField.qml +++ b/interface/resources/qml/controls-uit/TextField.qml @@ -38,7 +38,7 @@ TextField { : (textField.focus ? hifi.colors.white : hifi.colors.lightGrayText) background: Rectangle { color: isLightColorScheme - ? (textField.focus ? hifi.colors.white : hifi.colors.lightGray) + ? (textField.focus ? hifi.colors.white : hifi.colors.textFieldLightBackground) : (textField.focus ? hifi.colors.black : hifi.colors.baseGrayShadow) border.color: hifi.colors.primaryHighlight border.width: textField.focus ? 1 : 0 diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 5f77052c63..577b0a3c51 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -83,6 +83,13 @@ Item { readonly property color dropDownLightFinish: "#afafaf" readonly property color dropDownDarkStart: "#7d7d7d" readonly property color dropDownDarkFinish: "#6b6a6b" + readonly property color textFieldLightBackground: "#d4d4d4" + readonly property color sectionSeparator1: [ baseGrayHighlight, baseGrayShadow] + readonly property color sectionSeparator2: [ white, baseGrayHighlight] + readonly property color sectiongGradiantStart: [ darkGray, darkGray] + readonly property color sectionGradiantFinish: [ darkGray0, darkGray0] + readonly property color backgroundLight: faintGray + readonly property color backgroundDark: baseGray } Item { diff --git a/interface/resources/qml/windows-uit/Window.qml b/interface/resources/qml/windows-uit/Window.qml index 429c6d5dcc..90f973e796 100644 --- a/interface/resources/qml/windows-uit/Window.qml +++ b/interface/resources/qml/windows-uit/Window.qml @@ -52,6 +52,9 @@ Fadable { // property bool pinned: false property bool resizable: false + property int colorScheme: hifi.colorSchemes.dark + readonly property int isLightScheme: colorScheme == hifi.colorSchemes.light + property vector2d minSize: Qt.vector2d(100, 100) property vector2d maxSize: Qt.vector2d(1280, 720) @@ -137,7 +140,7 @@ Fadable { id: contentBackground anchors.fill: parent anchors.rightMargin: parent.isScrolling ? 11 : 0 - color: hifi.colors.baseGray + color: isLightScheme ? hifi.colors.backgroundLight : hifi.colors.backgroundDark visible: modality != Qt.ApplicationModal } @@ -217,7 +220,7 @@ Fadable { } width: parent.contentWidth height: footer.height + 2 * hifi.dimensions.contentSpacing.y - color: hifi.colors.baseGray + color: isLightScheme ? hifi.colors.backgroundLight : hifi.colors.backgroundDark visible: footer.height > 0 Item { From d0e29846f4f40aa9cf34867bbc7bd5e7716a6c10 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Mar 2016 18:01:53 -0800 Subject: [PATCH 062/209] Add GlyphButton --- interface/resources/qml/AssetsManager.qml | 8 +-- .../resources/qml/controls-uit/Button.qml | 34 +++++---- .../qml/controls-uit/GlyphButton.qml | 71 +++++++++++++++++++ .../qml/styles-uit/HifiConstants.qml | 4 ++ 4 files changed, 95 insertions(+), 22 deletions(-) create mode 100644 interface/resources/qml/controls-uit/GlyphButton.qml diff --git a/interface/resources/qml/AssetsManager.qml b/interface/resources/qml/AssetsManager.qml index e8bb4e1d9b..7b0dfd4cec 100644 --- a/interface/resources/qml/AssetsManager.qml +++ b/interface/resources/qml/AssetsManager.qml @@ -65,16 +65,16 @@ Window { anchors.left: parent.left anchors.right: parent.right - HifiControls.Button { - text: "<" + HifiControls.GlyphButton { + glyph: hifi.glyphs.back color: hifi.buttons.white colorScheme: root.colorScheme height: 26 width: 26 } - HifiControls.Button { - text: "O" + HifiControls.GlyphButton { + glyph: hifi.glyphs.reload color: hifi.buttons.white colorScheme: root.colorScheme height: 26 diff --git a/interface/resources/qml/controls-uit/Button.qml b/interface/resources/qml/controls-uit/Button.qml index fd18bc2a6f..140abb0a07 100644 --- a/interface/resources/qml/controls-uit/Button.qml +++ b/interface/resources/qml/controls-uit/Button.qml @@ -15,8 +15,6 @@ import QtQuick.Controls.Styles 1.4 import "../styles-uit" Original.Button { - id: button - property int color: 0 property int colorScheme: hifi.colorShemes.light @@ -32,28 +30,28 @@ Original.Button { GradientStop { position: 0.2 color: { - if (!enabled) { - hifi.buttons.disabledColorStart[button.colorScheme] - } else if (pressed) { - hifi.buttons.pressedColor[button.color] - } else if (hovered) { - hifi.buttons.hoveredColor[button.color] + if (!control.enabled) { + hifi.buttons.disabledColorStart[control.colorScheme] + } else if (control.pressed) { + hifi.buttons.pressedColor[control.color] + } else if (control.hovered) { + hifi.buttons.hoveredColor[control.color] } else { - hifi.buttons.colorStart[button.color] + hifi.buttons.colorStart[control.color] } } } GradientStop { position: 1.0 color: { - if (!enabled) { - hifi.buttons.disabledColorFinish[button.colorScheme] - } else if (pressed) { - hifi.buttons.pressedColor[button.color] - } else if (hovered) { - hifi.buttons.hoveredColor[button.color] + if (!control.enabled) { + hifi.buttons.disabledColorFinish[control.colorScheme] + } else if (control.pressed) { + hifi.buttons.pressedColor[control.color] + } else if (control.hovered) { + hifi.buttons.hoveredColor[control.color] } else { - hifi.buttons.colorFinish[button.color] + hifi.buttons.colorFinish[control.color] } } } @@ -62,8 +60,8 @@ Original.Button { label: RalewayBold { font.capitalization: Font.AllUppercase - color: enabled ? hifi.buttons.textColor[button.color] - : hifi.buttons.disabledTextColor[button.colorScheme] + color: enabled ? hifi.buttons.textColor[control.color] + : hifi.buttons.disabledTextColor[control.colorScheme] size: hifi.fontSizes.buttonLabel verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter diff --git a/interface/resources/qml/controls-uit/GlyphButton.qml b/interface/resources/qml/controls-uit/GlyphButton.qml new file mode 100644 index 0000000000..c4ee53c04f --- /dev/null +++ b/interface/resources/qml/controls-uit/GlyphButton.qml @@ -0,0 +1,71 @@ +// +// GlyphButton.qml +// +// Created by Clement on 3/7/16 +// 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 +// + + +import QtQuick 2.5 +import QtQuick.Controls 1.4 as Original +import QtQuick.Controls.Styles 1.4 + +import "../styles-uit" + +Original.Button { + property int color: 0 + property int colorScheme: hifi.colorShemes.light + property string glyph: "" + + width: 120 + height: 28 + + style: ButtonStyle { + + background: Rectangle { + radius: hifi.buttons.radius + + gradient: Gradient { + GradientStop { + position: 0.2 + color: { + if (!control.enabled) { + hifi.buttons.disabledColorStart[control.colorScheme] + } else if (control.pressed) { + hifi.buttons.pressedColor[control.color] + } else if (control.hovered) { + hifi.buttons.hoveredColor[control.color] + } else { + hifi.buttons.colorStart[control.color] + } + } + } + GradientStop { + position: 1.0 + color: { + if (!control.enabled) { + hifi.buttons.disabledColorFinish[control.colorScheme] + } else if (control.pressed) { + hifi.buttons.pressedColor[control.color] + } else if (control.hovered) { + hifi.buttons.hoveredColor[control.color] + } else { + hifi.buttons.colorFinish[control.color] + } + } + } + } + } + + label: HiFiGlyphs { + color: enabled ? hifi.buttons.textColor[control.color] + : hifi.buttons.disabledTextColor[control.colorScheme] + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: control.glyph + } + } +} diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 577b0a3c51..a63385c57d 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -157,6 +157,10 @@ Item { readonly property string pinInverted: "z" readonly property string reloadSmall: "a" readonly property string resizeHandle: "A" + readonly property string upload: "j" + readonly property string reload: "a" + readonly property string back: "1" + } Item { From 320bd2b4d48f27c5b69426d85104a79799449bcc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 10:21:55 -0800 Subject: [PATCH 063/209] Reset ContentSection scheme --- .../resources/qml/controls-uit/ContentSection.qml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/interface/resources/qml/controls-uit/ContentSection.qml b/interface/resources/qml/controls-uit/ContentSection.qml index 1a03ee339c..6f106a8347 100644 --- a/interface/resources/qml/controls-uit/ContentSection.qml +++ b/interface/resources/qml/controls-uit/ContentSection.qml @@ -18,8 +18,6 @@ Column { property bool isFirst: false property bool isCollapsible: false // Set at creation. property bool isCollapsed: false - property int colorScheme: hifi.colorSchemes.light - readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light spacing: 0 // Defer spacing decisions to individual controls. @@ -62,14 +60,14 @@ Column { id: shadow width: frame.width height: 1 - color: hifi.colors.sectionSeparator1[colorScheme] + color: hifi.colors.baseGrayShadow x: -hifi.dimensions.contentMargin.x } Rectangle { width: frame.width height: 1 - color: hifi.colors.sectionSeparator2[colorScheme] + color: hifi.colors.baseGrayHighlight x: -hifi.dimensions.contentMargin.x anchors.top: shadow.bottom } @@ -106,7 +104,7 @@ Column { y: -2 size: hifi.fontSizes.disclosureButton text: isCollapsed ? hifi.glyphs.disclosureButtonExpand : hifi.glyphs.disclosureButtonCollapse - color: title.color + color: hifi.colors.lightGrayText visible: isCollapsible } @@ -126,8 +124,8 @@ Column { start: Qt.point(0, 0) end: Qt.point(0, 4) gradient: Gradient { - GradientStop { position: 0.0; color: hifi.colors.sectionGradiantStart[colorScheme] } - GradientStop { position: 1.0; color: hifi.colors.sectionGradiantFinish[colorScheme] } // Equivalent of darkGray0 over baseGray background. + GradientStop { position: 0.0; color: hifi.colors.darkGray } + GradientStop { position: 1.0; color: hifi.colors.baseGray } // Equivalent of darkGray0 over baseGray background. } cached: true } From 51be88d4c35d873e89695161784f2456a9068df2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 10:23:37 -0800 Subject: [PATCH 064/209] Reset Window changes --- interface/resources/qml/windows-uit/Window.qml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/windows-uit/Window.qml b/interface/resources/qml/windows-uit/Window.qml index 90f973e796..429c6d5dcc 100644 --- a/interface/resources/qml/windows-uit/Window.qml +++ b/interface/resources/qml/windows-uit/Window.qml @@ -52,9 +52,6 @@ Fadable { // property bool pinned: false property bool resizable: false - property int colorScheme: hifi.colorSchemes.dark - readonly property int isLightScheme: colorScheme == hifi.colorSchemes.light - property vector2d minSize: Qt.vector2d(100, 100) property vector2d maxSize: Qt.vector2d(1280, 720) @@ -140,7 +137,7 @@ Fadable { id: contentBackground anchors.fill: parent anchors.rightMargin: parent.isScrolling ? 11 : 0 - color: isLightScheme ? hifi.colors.backgroundLight : hifi.colors.backgroundDark + color: hifi.colors.baseGray visible: modality != Qt.ApplicationModal } @@ -220,7 +217,7 @@ Fadable { } width: parent.contentWidth height: footer.height + 2 * hifi.dimensions.contentSpacing.y - color: isLightScheme ? hifi.colors.backgroundLight : hifi.colors.backgroundDark + color: hifi.colors.baseGray visible: footer.height > 0 Item { From e0371929a2baa5d52e334de596f3f32d2f8efdd1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 10:27:18 -0800 Subject: [PATCH 065/209] Remove unused variables --- interface/resources/qml/AssetsManager.qml | 6 ++---- interface/resources/qml/styles-uit/HifiConstants.qml | 6 ------ 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/interface/resources/qml/AssetsManager.qml b/interface/resources/qml/AssetsManager.qml index 7b0dfd4cec..dd83f7e488 100644 --- a/interface/resources/qml/AssetsManager.qml +++ b/interface/resources/qml/AssetsManager.qml @@ -27,7 +27,7 @@ Window { implicitWidth: 384; implicitHeight: 640 minSize: Qt.vector2d(200, 300) - colorScheme: hifi.colorSchemes.light + property int colorScheme: hifi.colorSchemes.dark HifiConstants { id: hifi } @@ -57,13 +57,13 @@ Window { HifiControls.ContentSection { name: "Asset Directory" spacing: hifi.dimensions.contentSpacing.y - colorScheme: root.colorScheme isFirst: true Row { id: buttonRow anchors.left: parent.left anchors.right: parent.right + spacing: hifi.dimensions.contentSpacing.x HifiControls.GlyphButton { glyph: hifi.glyphs.back @@ -113,7 +113,6 @@ Window { HifiControls.ContentSection { name: "" spacing: hifi.dimensions.contentSpacing.y - colorScheme: root.colorScheme HifiControls.TextField { id: fileUrl @@ -176,4 +175,3 @@ Window { } } } - diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index a63385c57d..be8e7d8330 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -84,12 +84,6 @@ Item { readonly property color dropDownDarkStart: "#7d7d7d" readonly property color dropDownDarkFinish: "#6b6a6b" readonly property color textFieldLightBackground: "#d4d4d4" - readonly property color sectionSeparator1: [ baseGrayHighlight, baseGrayShadow] - readonly property color sectionSeparator2: [ white, baseGrayHighlight] - readonly property color sectiongGradiantStart: [ darkGray, darkGray] - readonly property color sectionGradiantFinish: [ darkGray0, darkGray0] - readonly property color backgroundLight: faintGray - readonly property color backgroundDark: baseGray } Item { From ded449072fbbf4ae27efd33a7e3f8cbdbab2e3a9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 10:35:22 -0800 Subject: [PATCH 066/209] Rename window --- .../resources/qml/{AssetsManager.qml => AssetServer.qml} | 6 +++--- interface/resources/qml/hifi/MenuOption.qml | 2 +- interface/src/Application.cpp | 6 +++--- interface/src/Application.h | 2 +- interface/src/Menu.cpp | 6 +++--- interface/src/Menu.h | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) rename interface/resources/qml/{AssetsManager.qml => AssetServer.qml} (98%) diff --git a/interface/resources/qml/AssetsManager.qml b/interface/resources/qml/AssetServer.qml similarity index 98% rename from interface/resources/qml/AssetsManager.qml rename to interface/resources/qml/AssetServer.qml index dd83f7e488..dfa0f7bfbd 100644 --- a/interface/resources/qml/AssetsManager.qml +++ b/interface/resources/qml/AssetServer.qml @@ -1,5 +1,5 @@ // -// AssetsManager.qml +// AssetsServer.qml // // Created by Clement on 3/1/16 // Copyright 2016 High Fidelity, Inc. @@ -19,7 +19,7 @@ import "windows-uit" Window { id: root - objectName: "AssetsManager" + objectName: "AssetsServer" title: "Assets Server" resizable: true destroyOnInvisible: true @@ -36,7 +36,7 @@ Window { property var runningScriptsModel: ListModel { } Settings { - category: "Overlay.AssetManager" + category: "Overlay.AssetServer" property alias x: root.x property alias y: root.y } diff --git a/interface/resources/qml/hifi/MenuOption.qml b/interface/resources/qml/hifi/MenuOption.qml index 4894834225..477197f57e 100644 --- a/interface/resources/qml/hifi/MenuOption.qml +++ b/interface/resources/qml/hifi/MenuOption.qml @@ -10,7 +10,7 @@ QtObject { readonly property string animDebugDrawPosition: "Debug Draw Position"; readonly property string antialiasing: "Antialiasing"; readonly property string assetMigration: "ATP Asset Migration"; - readonly property string assetsManager = "Assets Manager"; + readonly property string assetServer = "Asset Server"; readonly property string atmosphere: "Atmosphere"; readonly property string attachments: "Attachments..."; readonly property string audioNetworkStats: "Audio Network Stats"; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 59d0b55dee..85ae8604e8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4453,9 +4453,9 @@ void Application::toggleRunningScriptsWidget() { //} } -void Application::toggleAssetsManagerWidget() { - static const QUrl url("AssetsManager.qml"); - DependencyManager::get()->show(url, "AssetsManager"); +void Application::toggleAssetServerWidget() { + static const QUrl url("AssetServer.qml"); + DependencyManager::get()->show(url, "AssetServer"); } void Application::packageModel() { diff --git a/interface/src/Application.h b/interface/src/Application.h index de744e73ab..956eb5a1ea 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -242,7 +242,7 @@ public slots: Q_INVOKABLE void loadScriptURLDialog(); void toggleLogDialog(); void toggleRunningScriptsWidget(); - void toggleAssetsManagerWidget(); + void toggleAssetServerWidget(); void handleLocalServerConnection(); void readArgumentsFromLocalSocket(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 5c04c1ce38..e9f45a6b9a 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -103,9 +103,9 @@ Menu::Menu() { addActionToQMenuAndActionHash(editMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J, qApp, SLOT(toggleRunningScriptsWidget())); - // Edit > Assets Manager - addActionToQMenuAndActionHash(editMenu, MenuOption::AssetsManager, 0, - qApp, SLOT(toggleAssetsManagerWidget())); + // Edit > Asset Server + addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, 0, + qApp, SLOT(toggleAssetServerWidget())); // Edit > Open and Run Script from File... [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index d08540973d..c605813753 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -35,7 +35,7 @@ namespace MenuOption { const QString AnimDebugDrawDefaultPose = "Debug Draw Default Pose"; const QString AnimDebugDrawPosition= "Debug Draw Position"; const QString AssetMigration = "ATP Asset Migration"; - const QString AssetsManager = "Assets Manager"; + const QString AssetServer = "Asset Server"; const QString Attachments = "Attachments..."; const QString AudioNetworkStats = "Audio Network Stats"; const QString AudioNoiseReduction = "Audio Noise Reduction"; From e32fd4524c09192134f711f97c6e6e026c6bc6cc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 11:46:02 -0800 Subject: [PATCH 067/209] Start wiring UI --- interface/resources/qml/AssetServer.qml | 35 ++++++++++++++++++------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index dfa0f7bfbd..9920003c90 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -33,7 +33,6 @@ Window { property var scripts: ScriptDiscoveryService; property var scriptsModel: scripts.scriptsModelFilter - property var runningScriptsModel: ListModel { } Settings { category: "Overlay.AssetServer" @@ -41,14 +40,24 @@ Window { property alias y: root.y } - Component.onCompleted: updateRunningScripts() - function updateRunningScripts() { - var runningScripts = ScriptDiscoveryService.getRunning(); - runningScriptsModel.clear() - for (var i = 0; i < runningScripts.length; ++i) { - runningScriptsModel.append(runningScripts[i]); - } + function reload() { + print("reload"); + } + + function goBack() { + print("goBack"); + } + + function uploadFile(fileUrl) { + var shouldAddToScene = addToScene.enabled; + print("uploadFile: " + shouldAddToScene); + + } + + function deleteFile() { + print("deleteFile"); + } Column { @@ -71,6 +80,8 @@ Window { colorScheme: root.colorScheme height: 26 width: 26 + + onClicked: root.goBack() } HifiControls.GlyphButton { @@ -79,6 +90,8 @@ Window { colorScheme: root.colorScheme height: 26 width: 26 + + onClicked: root.reload() } } @@ -97,6 +110,8 @@ Window { colorScheme: root.colorScheme height: 26 width: 130 + + onClicked: root.deleteFile() } } @@ -167,9 +182,11 @@ Window { text: "Upload" color: hifi.buttons.blue colorScheme: root.colorScheme - enabled: true height: 30 width: 155 + + enabled: fileUrl.text != "" + onClicked: root.uploadFile(fileUrl.text) } } } From 74fb1aab559b18493fdb466a8e104cb1b810420a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 13:15:04 -0800 Subject: [PATCH 068/209] Add file dialog --- interface/resources/qml/AssetServer.qml | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 9920003c90..bc41ba7e42 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -16,6 +16,7 @@ import Qt.labs.settings 1.0 import "styles-uit" import "controls-uit" as HifiControls import "windows-uit" +import "dialogs" Window { id: root @@ -38,6 +39,7 @@ Window { category: "Overlay.AssetServer" property alias x: root.x property alias y: root.y + property alias directory: "" } @@ -49,9 +51,8 @@ Window { print("goBack"); } - function uploadFile(fileUrl) { - var shouldAddToScene = addToScene.enabled; - print("uploadFile: " + shouldAddToScene); + function uploadFile(fileUrl, addToScene) { + print("uploadFile: " + fileUrl + " " + addToScene); } @@ -117,7 +118,7 @@ Window { HifiControls.Tree { id: treeView - height: 155 + height: 250 treeModel: scriptsModel colorScheme: root.colorScheme anchors.left: parent.left @@ -129,6 +130,11 @@ Window { name: "" spacing: hifi.dimensions.contentSpacing.y + Component { + id: fileBrowserBuilder; + FileDialog { selectDirectory: true } + } + HifiControls.TextField { id: fileUrl anchors.left: parent.left @@ -156,6 +162,14 @@ Window { enabled: true width: 100 + + onClicked: { + var browser = fileBrowserBuilder.createObject(desktop, { selectDirectory: true, folder: fileDialogHelper.pathToUrl(preference.value) }); + browser.selectedFile.connect(function(url){ + console.log(url); + fileUrl.text = fileDialogHelper.urlToPath(url); + }); + } } } @@ -186,7 +200,7 @@ Window { width: 155 enabled: fileUrl.text != "" - onClicked: root.uploadFile(fileUrl.text) + onClicked: root.uploadFile(fileUrl.text, addToScene.checked) } } } From 0bed46d43a89953182cd5aa4f3a64e556d2b0037 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 13:24:36 -0800 Subject: [PATCH 069/209] Fix typos and file browser directory --- interface/resources/qml/AssetServer.qml | 18 +++++++++++------- .../resources/qml/controls-uit/Button.qml | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index bc41ba7e42..c688e30cef 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -1,5 +1,5 @@ // -// AssetsServer.qml +// AssetServer.qml // // Created by Clement on 3/1/16 // Copyright 2016 High Fidelity, Inc. @@ -20,8 +20,8 @@ import "dialogs" Window { id: root - objectName: "AssetsServer" - title: "Assets Server" + objectName: "AssetServer" + title: "Asset Server" resizable: true destroyOnInvisible: true x: 40; y: 40 @@ -34,12 +34,13 @@ Window { property var scripts: ScriptDiscoveryService; property var scriptsModel: scripts.scriptsModelFilter + property var currentDirectory: "" Settings { category: "Overlay.AssetServer" property alias x: root.x property alias y: root.y - property alias directory: "" + property alias directory: root.currentDirectory } @@ -97,7 +98,7 @@ Window { } Item { - // Take the browseButton out of the column flow. + // Take the deleteButotn out of the column flow. id: deleteButtonContainer anchors.top: buttonRow.top anchors.right: parent.right @@ -164,7 +165,10 @@ Window { width: 100 onClicked: { - var browser = fileBrowserBuilder.createObject(desktop, { selectDirectory: true, folder: fileDialogHelper.pathToUrl(preference.value) }); + var browser = fileBrowserBuilder.createObject(desktop, { + selectDirectory: true, + folder: fileDialogHelper.pathToUrl(currentDirectory) + }); browser.selectedFile.connect(function(url){ console.log(url); fileUrl.text = fileDialogHelper.urlToPath(url); @@ -184,7 +188,7 @@ Window { } Item { - // Take the browseButton out of the column flow. + // Take the uploadButton out of the column flow. id: uploadButtonContainer anchors.top: addToScene.top anchors.right: parent.right diff --git a/interface/resources/qml/controls-uit/Button.qml b/interface/resources/qml/controls-uit/Button.qml index 140abb0a07..e7c8320ae6 100644 --- a/interface/resources/qml/controls-uit/Button.qml +++ b/interface/resources/qml/controls-uit/Button.qml @@ -16,7 +16,7 @@ import "../styles-uit" Original.Button { property int color: 0 - property int colorScheme: hifi.colorShemes.light + property int colorScheme: hifi.colorSchemes.light width: 120 height: 28 From 793d20306db508b6a4e49f61801c25f876e0ced9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 14:24:03 -0800 Subject: [PATCH 070/209] handle multiple paths for mapping delete operations --- assignment-client/src/assets/AssetServer.cpp | 45 +++++++++++++------- assignment-client/src/assets/AssetServer.h | 6 +-- libraries/networking/src/AssetClient.cpp | 33 ++++++++------ libraries/networking/src/AssetClient.h | 20 ++++----- libraries/networking/src/AssetUtils.h | 1 + 5 files changed, 64 insertions(+), 41 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index cbcce9d45e..52a019aff6 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -200,7 +200,7 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me break; } case AssetMappingOperationType::Delete: { - handleDeleteMappingOperation(*message, senderNode, *replyPacket); + handleDeleteMappingsOperation(*message, senderNode, *replyPacket); break; } } @@ -253,11 +253,18 @@ void AssetServer::handleSetMappingOperation(ReceivedMessage& message, SharedNode } } -void AssetServer::handleDeleteMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket) { +void AssetServer::handleDeleteMappingsOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket) { if (senderNode->getCanRez()) { - QString assetPath = message.readString(); + int numberOfDeletedMappings { 0 }; + message.readPrimitive(&numberOfDeletedMappings); - if (deleteMapping(assetPath)) { + QStringList mappingsToDelete; + + for (int i = 0; i < numberOfDeletedMappings; ++i) { + mappingsToDelete << message.readString(); + } + + if (deleteMappings(mappingsToDelete)) { replyPacket.writePrimitive(AssetServerError::NoError); } else { replyPacket.writePrimitive(AssetServerError::MappingOperationFailed); @@ -484,20 +491,28 @@ bool AssetServer::setMapping(AssetPath path, AssetHash hash) { } } -bool AssetServer::deleteMapping(AssetPath path) { - // keep the old mapping in case the delete fails - auto oldMapping = _fileMappings.take(path); +bool AssetServer::deleteMappings(const AssetPathList& paths) { + // take a copy of the current mappings in case persistence of these deletes fails + auto oldMappings = _fileMappings; - if (!oldMapping.isNull()) { - // deleted the old mapping, attempt to persist to file - if (writeMappingsToFile()) { - // persistence succeeded we are good to go - return true; + // enumerate the paths to delete and remove them all + for (auto& path : paths) { + auto oldMapping = _fileMappings.take(path); + if (!oldMapping.isNull()) { + qDebug() << "Deleted a mapping:" << path << "=>" << oldMapping.toString(); } else { - // we didn't delete the previous mapping, put it back in our in-memory representation - _fileMappings[path] = oldMapping.toString(); + qDebug() << "Unable to delete a mapping that was not found:" << path; } } - return false; + // deleted the old mappings, attempt to persist to file + if (writeMappingsToFile()) { + // persistence succeeded we are good to go + return true; + } else { + // we didn't delete the previous mapping, put it back in our in-memory representation + _fileMappings = oldMappings; + + return false; + } } diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 53a76248d6..f81fcf46b3 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -44,7 +44,7 @@ private: void handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); void handleGetAllMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); void handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); - void handleDeleteMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); + void handleDeleteMappingsOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); // Mapping file operations must be called from main assignment thread only void loadMappingsFromFile(); @@ -53,8 +53,8 @@ private: /// Set the mapping for path to hash bool setMapping(AssetPath path, AssetHash hash); - /// Delete mapping `path`. Return `true` if mapping existed, else `false`. - bool deleteMapping(AssetPath path); + /// Delete mapping `path`. Returns `true` if deletion of mappings succeeds, else `false`. + bool deleteMappings(const AssetPathList& paths); static void writeError(NLPacketList* packetList, AssetServerError error); diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index a443cd3078..8b4ff50d89 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -38,7 +38,7 @@ void MappingRequest::start() { doStart(); }; -GetMappingRequest::GetMappingRequest(AssetPath path) : _path(path) { +GetMappingRequest::GetMappingRequest(const AssetPath& path) : _path(path) { }; void GetMappingRequest::doStart() { @@ -113,7 +113,7 @@ void GetAllMappingsRequest::doStart() { }); }; -SetMappingRequest::SetMappingRequest(AssetPath path, AssetHash hash) : _path(path), _hash(hash) { +SetMappingRequest::SetMappingRequest(const AssetPath& path, const AssetHash& hash) : _path(path), _hash(hash) { }; void SetMappingRequest::doStart() { @@ -142,12 +142,12 @@ void SetMappingRequest::doStart() { }); }; -DeleteMappingRequest::DeleteMappingRequest(AssetPath path) : _path(path) { +DeleteMappingsRequest::DeleteMappingsRequest(const AssetPathList& paths) : _paths(paths) { }; -void DeleteMappingRequest::doStart() { +void DeleteMappingsRequest::doStart() { auto assetClient = DependencyManager::get(); - assetClient->deleteAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { + assetClient->deleteAssetMappings(_paths, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { if (!responseReceived) { _error = NetworkError; } else { @@ -165,7 +165,10 @@ void DeleteMappingRequest::doStart() { } if (!error) { - assetClient->_mappingCache.remove(_path); + // enumerate the paths and remove them from the cache + for (auto& path : _paths) { + assetClient->_mappingCache.remove(path); + } } emit finished(this); }); @@ -289,8 +292,8 @@ GetAllMappingsRequest* AssetClient::createGetAllMappingsRequest() { return new GetAllMappingsRequest(); } -DeleteMappingRequest* AssetClient::createDeleteMappingRequest(const AssetPath& path) { - return new DeleteMappingRequest(path); +DeleteMappingsRequest* AssetClient::createDeleteMappingsRequest(const AssetPathList& paths) { + return new DeleteMappingsRequest(paths); } SetMappingRequest* AssetClient::createSetMappingRequest(const AssetPath& path, const AssetHash& hash) { @@ -530,7 +533,7 @@ bool AssetClient::getAllAssetMappings(MappingOperationCallback callback) { return false; } -bool AssetClient::deleteAssetMapping(const AssetPath& path, MappingOperationCallback callback) { +bool AssetClient::deleteAssetMappings(const AssetPathList& paths, MappingOperationCallback callback) { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); @@ -542,7 +545,11 @@ bool AssetClient::deleteAssetMapping(const AssetPath& path, MappingOperationCall packetList->writePrimitive(AssetMappingOperationType::Delete); - packetList->writeString(path); + packetList->writePrimitive(int(paths.size())); + + for (auto& path: paths) { + packetList->writeString(path); + } nodeList->sendPacketList(std::move(packetList), *assetServer); @@ -787,11 +794,11 @@ void AssetScriptingInterface::getMapping(QString path, QScriptValue callback) { request->start(); } -void AssetScriptingInterface::deleteMapping(QString path, QScriptValue callback) { +void AssetScriptingInterface::deleteMappings(QStringList paths, QScriptValue callback) { auto assetClient = DependencyManager::get(); - auto request = assetClient->createDeleteMappingRequest(path); + auto request = assetClient->createDeleteMappingsRequest(paths); - connect(request, &DeleteMappingRequest::finished, this, [this, callback](DeleteMappingRequest* request) mutable { + connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { QScriptValueList args { uint8_t(request->getError()) }; callback.call(_engine->currentContext()->thisObject(), args); diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 44a62f834a..8eba65ecc5 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -68,7 +68,7 @@ private: class GetMappingRequest : public MappingRequest { Q_OBJECT public: - GetMappingRequest(AssetPath path); + GetMappingRequest(const AssetPath& path); AssetHash getHash() const { return _hash; } @@ -85,7 +85,7 @@ private: class SetMappingRequest : public MappingRequest { Q_OBJECT public: - SetMappingRequest(AssetPath path, AssetHash hash); + SetMappingRequest(const AssetPath& path, const AssetHash& hash); AssetHash getHash() const { return _hash; } @@ -99,18 +99,18 @@ private: AssetHash _hash; }; -class DeleteMappingRequest : public MappingRequest { +class DeleteMappingsRequest : public MappingRequest { Q_OBJECT public: - DeleteMappingRequest(AssetPath path); + DeleteMappingsRequest(const AssetPathList& path); signals: - void finished(DeleteMappingRequest* thisRequest); + void finished(DeleteMappingsRequest* thisRequest); private: virtual void doStart() override; - AssetPath _path; + AssetPathList _paths; }; class GetAllMappingsRequest : public MappingRequest { @@ -136,7 +136,7 @@ public: Q_INVOKABLE GetMappingRequest* createGetMappingRequest(const AssetPath& path); Q_INVOKABLE GetAllMappingsRequest* createGetAllMappingsRequest(); - Q_INVOKABLE DeleteMappingRequest* createDeleteMappingRequest(const AssetPath& path); + Q_INVOKABLE DeleteMappingsRequest* createDeleteMappingsRequest(const AssetPathList& paths); Q_INVOKABLE SetMappingRequest* createSetMappingRequest(const AssetPath& path, const AssetHash& hash); Q_INVOKABLE AssetRequest* createRequest(const AssetHash& hash); Q_INVOKABLE AssetUpload* createUpload(const QString& filename); @@ -160,7 +160,7 @@ 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 deleteAssetMappings(const AssetPathList& paths, MappingOperationCallback callback); bool getAssetInfo(const QString& hash, GetInfoCallback callback); bool getAsset(const QString& hash, DataOffset start, DataOffset end, @@ -185,7 +185,7 @@ private: friend class GetMappingRequest; friend class GetAllMappingsRequest; friend class SetMappingRequest; - friend class DeleteMappingRequest; + friend class DeleteMappingsRequest; }; @@ -198,7 +198,7 @@ public: 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 deleteMappings(QStringList paths, QScriptValue callback); Q_INVOKABLE void getAllMappings(QScriptValue callback); protected: QSet _pendingRequests; diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 08988e4791..8925238b0e 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -25,6 +25,7 @@ using DataOffset = int64_t; using AssetPath = QString; using AssetHash = QString; using AssetMapping = std::map; +using AssetPathList = QStringList; const size_t SHA256_HASH_LENGTH = 32; const size_t SHA256_HASH_HEX_LENGTH = 64; From f9f42a085ac185fa58573fbc2e5baf3e112c1024 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 14:43:55 -0800 Subject: [PATCH 071/209] 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 072/209] 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 073/209] 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 074/209] 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 075/209] 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); } } From 254e04c4b7dd5d97c92364f68185ef5e4bbf2b59 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 16:09:42 -0800 Subject: [PATCH 076/209] UI change --- interface/resources/qml/AssetServer.qml | 70 ++++++++++++++----------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index c688e30cef..e260b5e8d7 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -43,29 +43,36 @@ Window { property alias directory: root.currentDirectory } - function reload() { print("reload"); } - - function goBack() { - print("goBack"); + function addToWorld() { + print("addToWorld"); } - - function uploadFile(fileUrl, addToScene) { - print("uploadFile: " + fileUrl + " " + addToScene); - + function renameFile() { + print("renameFile"); } - function deleteFile() { print("deleteFile"); } + function uploadFile(fileUrl, addToScene) { + var object = desktop.inputDialog({ + label: "Enter asset path", + //placeholderText: "atp:/myFolder/myFile.ext" + }); + object.selected.connect(function(value) { + print(value); + }); + print("uploadFile: " + fileUrl + " " + addToScene); + } + Column { width: pane.contentWidth HifiControls.ContentSection { + id: assetDirectory name: "Asset Directory" spacing: hifi.dimensions.contentSpacing.y isFirst: true @@ -76,16 +83,6 @@ Window { anchors.right: parent.right spacing: hifi.dimensions.contentSpacing.x - HifiControls.GlyphButton { - glyph: hifi.glyphs.back - color: hifi.buttons.white - colorScheme: root.colorScheme - height: 26 - width: 26 - - onClicked: root.goBack() - } - HifiControls.GlyphButton { glyph: hifi.glyphs.reload color: hifi.buttons.white @@ -95,23 +92,35 @@ Window { onClicked: root.reload() } - } - Item { - // Take the deleteButotn out of the column flow. - id: deleteButtonContainer - anchors.top: buttonRow.top - anchors.right: parent.right + HifiControls.Button { + text: "ADD TO WORLD" + color: hifi.buttons.white + colorScheme: root.colorScheme + height: 26 + width: 120 + + onClicked: root.addToWorld() + } + + HifiControls.Button { + text: "RENAME" + color: hifi.buttons.white + colorScheme: root.colorScheme + height: 26 + width: 80 + + onClicked: root.renameFile() + } HifiControls.Button { id: deleteButton - anchors.right: parent.right - text: "DELETE SELECTION" + text: "DELETE" color: hifi.buttons.red colorScheme: root.colorScheme height: 26 - width: 130 + width: 80 onClicked: root.deleteFile() } @@ -119,7 +128,7 @@ Window { HifiControls.Tree { id: treeView - height: 250 + height: 400 treeModel: scriptsModel colorScheme: root.colorScheme anchors.left: parent.left @@ -128,6 +137,7 @@ Window { } HifiControls.ContentSection { + id: uploadSection name: "" spacing: hifi.dimensions.contentSpacing.y @@ -166,7 +176,7 @@ Window { onClicked: { var browser = fileBrowserBuilder.createObject(desktop, { - selectDirectory: true, + selectDirectory: false, folder: fileDialogHelper.pathToUrl(currentDirectory) }); browser.selectedFile.connect(function(url){ From 028c7ab6baacc7ceeb21850988c5b217d415e4ab Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 16:40:54 -0800 Subject: [PATCH 077/209] Add text box --- interface/resources/qml/AssetServer.qml | 57 +++++++++++-------- .../resources/qml/dialogs/QueryDialog.qml | 1 + 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index e260b5e8d7..49c7bd4363 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -34,7 +34,7 @@ Window { property var scripts: ScriptDiscoveryService; property var scriptsModel: scripts.scriptsModelFilter - property var currentDirectory: "" + property var currentDirectory; Settings { category: "Overlay.AssetServer" @@ -57,15 +57,35 @@ Window { } - function uploadFile(fileUrl, addToScene) { + function chooseClicked() { + var browser = fileBrowserBuilder.createObject(desktop, { + selectDirectory: false, + folder: fileDialogHelper.pathToUrl(currentDirectory) + }); + browser.selectedFile.connect(function(url){ + console.log(url); + fileUrlTextField.text = fileDialogHelper.urlToPath(url); + }); + + } + + function uploadClicked() { + var fileUrl = fileUrlTextField.text + var addToScene = addToSceneCheckBox.checked + var object = desktop.inputDialog({ - label: "Enter asset path", - //placeholderText: "atp:/myFolder/myFile.ext" + label: "Enter asset path:", + prefilledText: "atp:/myFolder/myFile.ext", + placeholderText: "Enter path here" }); - object.selected.connect(function(value) { - print(value); + object.selected.connect(function(destinationPath) { + console.log("Uploading " + fileUrl + " to " + destinationPath + " (addToScene: " + addToScene + ")"); + + + + + }); - print("uploadFile: " + fileUrl + " " + addToScene); } Column { @@ -147,7 +167,7 @@ Window { } HifiControls.TextField { - id: fileUrl + id: fileUrlTextField anchors.left: parent.left anchors.right: parent.right anchors.rightMargin: chooseButton.width + hifi.dimensions.contentSpacing.x @@ -160,7 +180,7 @@ Window { Item { // Take the chooseButton out of the column flow. id: chooseButtonContainer - anchors.top: fileUrl.top + anchors.top: fileUrlTextField.top anchors.right: parent.right HifiControls.Button { @@ -174,21 +194,12 @@ Window { width: 100 - onClicked: { - var browser = fileBrowserBuilder.createObject(desktop, { - selectDirectory: false, - folder: fileDialogHelper.pathToUrl(currentDirectory) - }); - browser.selectedFile.connect(function(url){ - console.log(url); - fileUrl.text = fileDialogHelper.urlToPath(url); - }); - } + onClicked: root.chooseClicked() } } HifiControls.CheckBox { - id: addToScene + id: addToSceneCheckBox anchors.left: parent.left anchors.right: parent.right anchors.rightMargin: uploadButton.width + hifi.dimensions.contentSpacing.x @@ -200,7 +211,7 @@ Window { Item { // Take the uploadButton out of the column flow. id: uploadButtonContainer - anchors.top: addToScene.top + anchors.top: addToSceneCheckBox.top anchors.right: parent.right HifiControls.Button { @@ -213,8 +224,8 @@ Window { height: 30 width: 155 - enabled: fileUrl.text != "" - onClicked: root.uploadFile(fileUrl.text, addToScene.checked) + enabled: fileUrlTextField.text != "" + onClicked: root.uploadClicked() } } } diff --git a/interface/resources/qml/dialogs/QueryDialog.qml b/interface/resources/qml/dialogs/QueryDialog.qml index 948bbb1295..75c9640589 100644 --- a/interface/resources/qml/dialogs/QueryDialog.qml +++ b/interface/resources/qml/dialogs/QueryDialog.qml @@ -24,6 +24,7 @@ ModalWindow { // For text boxes property alias placeholderText: textResult.placeholderText + property alias prefilledText: textResult.text // For combo boxes property bool editable: true; From 169af80bc09cdaa8dddefc1fc9619945918886a6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 17:09:37 -0800 Subject: [PATCH 078/209] Add a couple dialogs --- interface/resources/qml/AssetServer.qml | 33 +++++++++++++++++++------ 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 49c7bd4363..94aa739892 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -50,15 +50,35 @@ Window { print("addToWorld"); } function renameFile() { - print("renameFile"); + var object = desktop.inputDialog({ + label: "Enter new path:", + prefilledText: "atp:/myFolder/myFile.ext", + placeholderText: "Enter path here" + }); + object.selected.connect(function(destinationPath) { + console.log("Renaming " + "fileUrl" + " to " + destinationPath); + + + + + + }); } function deleteFile() { - print("deleteFile"); + var object = desktop.messageBox({ + text: "Deleting", + informativeText: "You are about to delete the following file:\n" + "test" + "\nDo you want to continue?" + }); + object.selected.connect(function(button) { + + + + }); } function chooseClicked() { - var browser = fileBrowserBuilder.createObject(desktop, { + var browser = desktop.fileDialog({ selectDirectory: false, folder: fileDialogHelper.pathToUrl(currentDirectory) }); @@ -67,6 +87,8 @@ Window { fileUrlTextField.text = fileDialogHelper.urlToPath(url); }); + + } function uploadClicked() { @@ -161,11 +183,6 @@ Window { name: "" spacing: hifi.dimensions.contentSpacing.y - Component { - id: fileBrowserBuilder; - FileDialog { selectDirectory: true } - } - HifiControls.TextField { id: fileUrlTextField anchors.left: parent.left From 380480d4ee119da67dbac84927ceee21472193fa Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 18:06:56 -0800 Subject: [PATCH 079/209] Add a couple more dialogs --- interface/resources/qml/AssetServer.qml | 50 +++++++++++++++++-------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 94aa739892..34f6502b40 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -50,13 +50,18 @@ Window { print("addToWorld"); } function renameFile() { + var path = scriptsModel.data(treeView.currentIndex, 0x100); + if (!path) { + return; + } + var object = desktop.inputDialog({ label: "Enter new path:", - prefilledText: "atp:/myFolder/myFile.ext", + prefilledText: path, placeholderText: "Enter path here" }); object.selected.connect(function(destinationPath) { - console.log("Renaming " + "fileUrl" + " to " + destinationPath); + console.log("Renaming " + path + " to " + destinationPath); @@ -65,43 +70,56 @@ Window { }); } function deleteFile() { + var path = scriptsModel.data(treeView.currentIndex, 0x100); + if (!path) { + return; + } + var object = desktop.messageBox({ + icon: OriginalDialogs.StandardIcon.Question, + buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No, + defaultButton: OriginalDialogs.StandardButton.No, text: "Deleting", - informativeText: "You are about to delete the following file:\n" + "test" + "\nDo you want to continue?" + informativeText: "You are about to delete the following file:\n" + + path + + "\nDo you want to continue?" }); object.selected.connect(function(button) { + if (button === OriginalDialogs.StandardButton.Yes) { + console.log("Deleting " + path); - + } }); } function chooseClicked() { var browser = desktop.fileDialog({ selectDirectory: false, - folder: fileDialogHelper.pathToUrl(currentDirectory) + dir: currentDirectory }); browser.selectedFile.connect(function(url){ - console.log(url); fileUrlTextField.text = fileDialogHelper.urlToPath(url); + currentDirectory = browser.dir; }); - - - } function uploadClicked() { var fileUrl = fileUrlTextField.text - var addToScene = addToSceneCheckBox.checked + var addToWorld = addToWorldCheckBox.checked + + var path = scriptsModel.data(treeView.currentIndex, 0x100); + var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : ""; + var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); var object = desktop.inputDialog({ label: "Enter asset path:", - prefilledText: "atp:/myFolder/myFile.ext", + prefilledText: directory + filename, placeholderText: "Enter path here" }); object.selected.connect(function(destinationPath) { - console.log("Uploading " + fileUrl + " to " + destinationPath + " (addToScene: " + addToScene + ")"); + console.log("Uploading " + fileUrl + " to " + destinationPath + " (addToWorld: " + addToWorld + ")"); @@ -216,19 +234,19 @@ Window { } HifiControls.CheckBox { - id: addToSceneCheckBox + id: addToWorldCheckBox anchors.left: parent.left anchors.right: parent.right anchors.rightMargin: uploadButton.width + hifi.dimensions.contentSpacing.x - text: "Add to scene on upload" + text: "Add to world on upload" checked: false } Item { // Take the uploadButton out of the column flow. id: uploadButtonContainer - anchors.top: addToSceneCheckBox.top + anchors.top: addToWorldCheckBox.top anchors.right: parent.right HifiControls.Button { @@ -245,6 +263,8 @@ Window { onClicked: root.uploadClicked() } } + + HifiControls.VerticalSpacer {} } } } From b8df8f170d568df88d301006f8a0963b98c32bda Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 10:16:15 -0800 Subject: [PATCH 080/209] Add HF username as default username for bugsplat --- interface/src/main.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index f45a6c08b9..ed924108ef 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -143,6 +143,14 @@ int main(int argc, const char* argv[]) { QObject::connect(&server, &QLocalServer::newConnection, &app, &Application::handleLocalServerConnection); +#ifdef HAS_BUGSPLAT + AccountManager& accountManager = AccountManager::getInstance(); + mpSender.setDefaultUserName(accountManager.getAccountInfo().getUsername().toLatin1()); + QObject::connect(&accountManager, &AccountManager::usernameChanged, &app, [&mpSender](const QString& newUsername) { + mpSender.setDefaultUserName(newUsername); + }); +#endif + QTranslator translator; translator.load("i18n/interface_en"); app.installTranslator(&translator); From 806bae99aae2d32a51f227f9c0f1e47b8fbcbd3f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 10:18:22 -0800 Subject: [PATCH 081/209] Fix bugsplat username setting --- interface/src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index ed924108ef..3a4807ad6a 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -145,9 +145,9 @@ int main(int argc, const char* argv[]) { #ifdef HAS_BUGSPLAT AccountManager& accountManager = AccountManager::getInstance(); - mpSender.setDefaultUserName(accountManager.getAccountInfo().getUsername().toLatin1()); + mpSender.setDefaultUserName(accountManager.getAccountInfo().getUsername().toLatin1().constData()); QObject::connect(&accountManager, &AccountManager::usernameChanged, &app, [&mpSender](const QString& newUsername) { - mpSender.setDefaultUserName(newUsername); + mpSender.setDefaultUserName(newUsername.toLatin1().constData()); }); #endif From d20cf12941fc075e05708b64385cf50e845e85f2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 10:16:15 -0800 Subject: [PATCH 082/209] Add HF username as default username for bugsplat --- interface/src/main.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index f45a6c08b9..ed924108ef 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -143,6 +143,14 @@ int main(int argc, const char* argv[]) { QObject::connect(&server, &QLocalServer::newConnection, &app, &Application::handleLocalServerConnection); +#ifdef HAS_BUGSPLAT + AccountManager& accountManager = AccountManager::getInstance(); + mpSender.setDefaultUserName(accountManager.getAccountInfo().getUsername().toLatin1()); + QObject::connect(&accountManager, &AccountManager::usernameChanged, &app, [&mpSender](const QString& newUsername) { + mpSender.setDefaultUserName(newUsername); + }); +#endif + QTranslator translator; translator.load("i18n/interface_en"); app.installTranslator(&translator); From eb402eab758bb47165037ab809883bea11fccf2b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 10:18:22 -0800 Subject: [PATCH 083/209] Fix bugsplat username setting --- interface/src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index ed924108ef..3a4807ad6a 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -145,9 +145,9 @@ int main(int argc, const char* argv[]) { #ifdef HAS_BUGSPLAT AccountManager& accountManager = AccountManager::getInstance(); - mpSender.setDefaultUserName(accountManager.getAccountInfo().getUsername().toLatin1()); + mpSender.setDefaultUserName(accountManager.getAccountInfo().getUsername().toLatin1().constData()); QObject::connect(&accountManager, &AccountManager::usernameChanged, &app, [&mpSender](const QString& newUsername) { - mpSender.setDefaultUserName(newUsername); + mpSender.setDefaultUserName(newUsername.toLatin1().constData()); }); #endif From 5a0beec1f5a3c4dc02f39ffcc6dce41030632187 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 9 Mar 2016 11:43:56 -0800 Subject: [PATCH 084/209] Replace old drag&drop with new UI --- interface/resources/qml/AssetServer.qml | 1 + interface/resources/qml/hifi/MenuOption.qml | 1 - interface/src/Application.cpp | 94 ++------------------- interface/src/Application.h | 4 +- interface/src/Menu.cpp | 12 --- interface/src/Menu.h | 1 - 6 files changed, 11 insertions(+), 102 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 34f6502b40..ea2a082c8a 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -35,6 +35,7 @@ Window { property var scripts: ScriptDiscoveryService; property var scriptsModel: scripts.scriptsModelFilter property var currentDirectory; + property alias currentFileUrl: fileUrlTextField.text; Settings { category: "Overlay.AssetServer" diff --git a/interface/resources/qml/hifi/MenuOption.qml b/interface/resources/qml/hifi/MenuOption.qml index 477197f57e..da28d1daf3 100644 --- a/interface/resources/qml/hifi/MenuOption.qml +++ b/interface/resources/qml/hifi/MenuOption.qml @@ -155,7 +155,6 @@ QtObject { readonly property string toolWindow: "Tool Window"; readonly property string transmitterDrive: "Transmitter Drive"; readonly property string turnWithHead: "Turn using Head"; - readonly property string uploadAsset: "Upload File to Asset Server"; readonly property string useAudioForMouth: "Use Audio for Mouth"; readonly property string useCamera: "Use Camera"; readonly property string velocityFilter: "Velocity Filter"; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 85ae8604e8..a824c22b0f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -158,7 +158,6 @@ #include "Stars.h" #include "ui/AddressBarDialog.h" #include "ui/AvatarInputs.h" -#include "ui/AssetUploadDialogFactory.h" #include "ui/DialogsManager.h" #include "ui/LoginDialog.h" #include "ui/overlays/Cube3DOverlay.h" @@ -3937,9 +3936,6 @@ void Application::nodeAdded(SharedNodePointer node) { if (node->getType() == NodeType::AvatarMixer) { // new avatar mixer, send off our identity packet right away getMyAvatar()->sendIdentityPacket(); - } else if (node->getType() == NodeType::AssetServer) { - // the addition of an asset-server always re-enables the upload to asset server menu option - Menu::getInstance()->getActionForOption(MenuOption::UploadAsset)->setEnabled(true); } } @@ -3989,10 +3985,6 @@ void Application::nodeKilled(SharedNodePointer node) { } else if (node->getType() == NodeType::AvatarMixer) { // our avatar mixer has gone away - clear the hash of avatars DependencyManager::get()->clearOtherAvatars(); - } else if (node->getType() == NodeType::AssetServer - && !DependencyManager::get()->soloNodeOfType(NodeType::AssetServer)) { - // this was our last asset server - disable the menu option to upload an asset - Menu::getInstance()->getActionForOption(MenuOption::UploadAsset)->setEnabled(false); } } void Application::trackIncomingOctreePacket(ReceivedMessage& message, SharedNodePointer sendingNode, bool wasStatsPacket) { @@ -4218,7 +4210,10 @@ bool Application::acceptURL(const QString& urlString, bool defaultUpload) { } } - return defaultUpload && askToUploadAsset(urlString); + if (defaultUpload) { + toggleAssetServerWidget(urlString); + } + return defaultUpload; } void Application::setSessionUUID(const QUuid& sessionUUID) { @@ -4280,80 +4275,6 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) { return true; } -bool Application::askToUploadAsset(const QString& filename) { - if (!DependencyManager::get()->getThisNodeCanRez()) { - OffscreenUi::warning(_window, "Failed Upload", - QString("You don't have upload rights on that domain.\n\n")); - return false; - } - - QUrl url { filename }; - if (auto upload = DependencyManager::get()->createUpload(url.toLocalFile())) { - - QMessageBox messageBox; - messageBox.setWindowTitle("Asset upload"); - messageBox.setText("You are about to upload the following file to the asset server:\n" + - url.toDisplayString()); - messageBox.setInformativeText("Do you want to continue?"); - messageBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - messageBox.setDefaultButton(QMessageBox::Ok); - - // Option to drop model in world for models - if (filename.endsWith(FBX_EXTENSION, Qt::CaseInsensitive) || filename.endsWith(OBJ_EXTENSION, Qt::CaseInsensitive)) { - auto checkBox = new QCheckBox(&messageBox); - checkBox->setText("Add to scene"); - messageBox.setCheckBox(checkBox); - } - - if (messageBox.exec() != QMessageBox::Ok) { - upload->deleteLater(); - return false; - } - - // connect to the finished signal so we know when the AssetUpload is done - if (messageBox.checkBox() && (messageBox.checkBox()->checkState() == Qt::Checked)) { - // Custom behavior for models - QObject::connect(upload, &AssetUpload::finished, this, &Application::modelUploadFinished); - } else { - QObject::connect(upload, &AssetUpload::finished, - &AssetUploadDialogFactory::getInstance(), - &AssetUploadDialogFactory::handleUploadFinished); - } - - // start the upload now - upload->start(); - return true; - } - - // display a message box with the error - OffscreenUi::warning(_window, "Failed Upload", QString("Failed to upload %1.\n\n").arg(filename)); - return false; -} - -void Application::modelUploadFinished(AssetUpload* upload, const QString& hash) { - auto fileInfo = QFileInfo(upload->getFilename()); - auto filename = fileInfo.fileName(); - - if ((upload->getError() == AssetUpload::NoError) && - (filename.endsWith(FBX_EXTENSION, Qt::CaseInsensitive) || - filename.endsWith(OBJ_EXTENSION, Qt::CaseInsensitive))) { - - auto entities = DependencyManager::get(); - - EntityItemProperties properties; - properties.setType(EntityTypes::Model); - properties.setModelURL(QString("%1:%2.%3").arg(URL_SCHEME_ATP).arg(hash).arg(fileInfo.completeSuffix())); - properties.setPosition(_myCamera.getPosition() + _myCamera.getOrientation() * Vectors::FRONT * 2.0f); - properties.setName(QUrl(upload->getFilename()).fileName()); - - entities->addEntity(properties); - - upload->deleteLater(); - } else { - AssetUploadDialogFactory::getInstance().handleUploadFinished(upload, hash); - } -} - bool Application::askToWearAvatarAttachmentUrl(const QString& url) { QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); @@ -4453,9 +4374,12 @@ void Application::toggleRunningScriptsWidget() { //} } -void Application::toggleAssetServerWidget() { +void Application::toggleAssetServerWidget(QString filePath) { static const QUrl url("AssetServer.qml"); - DependencyManager::get()->show(url, "AssetServer"); + auto urlSetter = [=](QQmlContext* context, QObject* newObject){ + newObject->setProperty("currentFileUrl", filePath); + }; + DependencyManager::get()->show(url, "AssetServer", urlSetter); } void Application::packageModel() { diff --git a/interface/src/Application.h b/interface/src/Application.h index 956eb5a1ea..e73524ee66 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -242,7 +242,7 @@ public slots: Q_INVOKABLE void loadScriptURLDialog(); void toggleLogDialog(); void toggleRunningScriptsWidget(); - void toggleAssetServerWidget(); + void toggleAssetServerWidget(QString filePath = ""); void handleLocalServerConnection(); void readArgumentsFromLocalSocket(); @@ -303,8 +303,6 @@ private slots: bool acceptSnapshot(const QString& urlString); bool askToSetAvatarUrl(const QString& url); bool askToLoadScript(const QString& scriptFilenameOrURL); - bool askToUploadAsset(const QString& asset); - void modelUploadFinished(AssetUpload* upload, const QString& hash); bool askToWearAvatarAttachmentUrl(const QString& url); void displayAvatarAttachmentWarning(const QString& message) const; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index e9f45a6b9a..ab3add788d 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -35,7 +35,6 @@ #include "MainWindow.h" #include "render/DrawStatus.h" #include "scripting/MenuScriptingInterface.h" -#include "ui/AssetUploadDialogFactory.h" #include "ui/DialogsManager.h" #include "ui/StandAloneJSConsole.h" #include "InterfaceLogging.h" @@ -365,17 +364,6 @@ Menu::Menu() { // Developer > Assets >>> MenuWrapper* assetDeveloperMenu = developerMenu->addMenu("Assets"); - auto& assetDialogFactory = AssetUploadDialogFactory::getInstance(); - assetDialogFactory.setDialogParent(this); - QAction* assetUpload = addActionToQMenuAndActionHash(assetDeveloperMenu, - MenuOption::UploadAsset, - 0, - &assetDialogFactory, - SLOT(showDialog())); - - // disable the asset upload action by default - it gets enabled only if asset server becomes present - assetUpload->setEnabled(false); - auto& atpMigrator = ATPAssetMigrator::getInstance(); atpMigrator.setDialogParent(this); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index c605813753..b697bd5317 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -168,7 +168,6 @@ namespace MenuOption { const QString ToolWindow = "Tool Window"; const QString TransmitterDrive = "Transmitter Drive"; const QString TurnWithHead = "Turn using Head"; - const QString UploadAsset = "Upload File to Asset Server"; const QString UseAudioForMouth = "Use Audio for Mouth"; const QString UseCamera = "Use Camera"; const QString UseAnimPreAndPostRotations = "Use Anim Pre and Post Rotations"; From 03c38eada3952833bd3381fb91c8689f6de27411 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 12:06:33 -0800 Subject: [PATCH 085/209] add folder rename handling --- assignment-client/src/assets/AssetServer.cpp | 58 +++++++++++++++++--- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 13257967ac..403941221d 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -511,6 +511,10 @@ bool AssetServer::setMapping(const AssetPath& path, const AssetHash& hash) { } } +bool pathIsFolder(const AssetPath& path) { + return path.endsWith('/'); +} + bool AssetServer::deleteMappings(const AssetPathList& paths) { // take a copy of the current mappings in case persistence of these deletes fails auto oldMappings = _fileMappings; @@ -538,23 +542,59 @@ bool AssetServer::deleteMappings(const AssetPathList& paths) { } bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPath) { - // take the old hash to remove the old mapping - auto oldMapping = _fileMappings[oldPath].toString(); + if (pathIsFolder(oldPath)) { + if (!pathIsFolder(newPath)) { + // we were asked to rename a path to a folder to a path that isn't a folder, this is a fail + return false; + } - if (!oldMapping.isEmpty()) { - _fileMappings[newPath] = oldMapping; + // take a copy of the old mappings + auto oldMappings = _fileMappings; + + // iterate the current mappings and adjust any that matches the renamed folder + auto it = oldMappings.begin(); + while (it != oldMappings.end()) { + + if (it->toString().startsWith(oldPath)) { + auto oldKey = it.key(); + auto newKey = oldKey.replace(0, oldPath.size(), newPath); + + // remove the old version from the in memory file mappings + _fileMappings.remove(oldKey); + _fileMappings.insert(newKey, it.value()); + } + + ++it; + } if (writeMappingsToFile()) { - // persisted the renamed mapping, return success + // persisted the changed mappings return success return true; } else { - // we couldn't persist the renamed mapping, rollback and return failure - _fileMappings[oldPath] = oldMapping; + // couldn't persist the renamed paths, rollback and return failure + _fileMappings = oldMappings; return false; } } else { - // failed to find a mapping that was to be renamed, return failure - return false; + // 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; + } } } From a53b038ac2dee5616a36d4c08ba4d1392f51e95b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 12:10:36 -0800 Subject: [PATCH 086/209] add folder delete handling --- assignment-client/src/assets/AssetServer.cpp | 33 +++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 403941221d..ccd03aa2a3 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -521,11 +521,35 @@ bool AssetServer::deleteMappings(const AssetPathList& paths) { // enumerate the paths to delete and remove them all for (auto& path : paths) { - auto oldMapping = _fileMappings.take(path); - if (!oldMapping.isNull()) { - qDebug() << "Deleted a mapping:" << path << "=>" << oldMapping.toString(); + + // figure out if this path will delete a file or folder + if (pathIsFolder(path)) { + // enumerate the in memory file mappings and remove anything that matches + auto it = _fileMappings.begin(); + auto sizeBefore = _fileMappings.size(); + + while (it != _fileMappings.end()) { + if (it->toString().startsWith(path)) { + it = _fileMappings.erase(it); + } else { + ++it; + } + } + + auto sizeNow = _fileMappings.size(); + if (sizeBefore != sizeNow) { + qDebug() << "Deleted" << sizeBefore - sizeNow << "mappings in folder: " << path; + } else { + qDebug() << "Did not find any mappings in folder:" << path; + } + } else { - qDebug() << "Unable to delete a mapping that was not found:" << path; + auto oldMapping = _fileMappings.take(path); + if (!oldMapping.isNull()) { + qDebug() << "Deleted a mapping:" << path << "=>" << oldMapping.toString(); + } else { + qDebug() << "Unable to delete a mapping that was not found:" << path; + } } } @@ -542,6 +566,7 @@ bool AssetServer::deleteMappings(const AssetPathList& paths) { } bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPath) { + // figure out if this rename is for a file or folder if (pathIsFolder(oldPath)) { if (!pathIsFolder(newPath)) { // we were asked to rename a path to a folder to a path that isn't a folder, this is a fail From 6b8a71f96a02cf25893881dfeef1bc1a87c16706 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 12:16:36 -0800 Subject: [PATCH 087/209] add debug for mapping operations --- assignment-client/src/assets/AssetServer.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index ccd03aa2a3..9825e75c61 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -498,6 +498,7 @@ bool AssetServer::setMapping(const AssetPath& path, const AssetHash& hash) { // attempt to write to file if (writeMappingsToFile()) { // persistence succeeded, we are good to go + qDebug() << "Set mapping:" << path << "=>" << hash; return true; } else { // failed to persist this mapping to file - put back the old one in our in-memory representation @@ -507,6 +508,8 @@ bool AssetServer::setMapping(const AssetPath& path, const AssetHash& hash) { _fileMappings[path] = oldMapping; } + qWarning() << "Failed to persist mapping:" << path << "=>" << hash; + return false; } } @@ -578,8 +581,8 @@ bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPa // iterate the current mappings and adjust any that matches the renamed folder auto it = oldMappings.begin(); - while (it != oldMappings.end()) { + while (it != oldMappings.end()) { if (it->toString().startsWith(oldPath)) { auto oldKey = it.key(); auto newKey = oldKey.replace(0, oldPath.size(), newPath); @@ -593,12 +596,16 @@ bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPa } if (writeMappingsToFile()) { - // persisted the changed mappings return success + // persisted the changed mappings, return success + qDebug() << "Renamed mapping:" << oldPath << "=>" << newPath; + return true; } else { // couldn't persist the renamed paths, rollback and return failure _fileMappings = oldMappings; + qWarning() << "Failed to persist renamed mapping:" << oldPath << "=>" << newPath; + return false; } } else { @@ -610,11 +617,15 @@ bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPa if (writeMappingsToFile()) { // persisted the renamed mapping, return success + qDebug() << "Renamed mapping:" << oldPath << "=>" << newPath; + return true; } else { // we couldn't persist the renamed mapping, rollback and return failure _fileMappings[oldPath] = oldMapping; + qDebug() << "Failed to persist renamed mapping:" << oldPath << "=>" << newPath; + return false; } } else { From 5a197838f4785020776964499800c5babf8a6637 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 13:14:39 -0800 Subject: [PATCH 088/209] add a deleteMapping call for single path to scripting interface --- libraries/script-engine/src/AssetScriptingInterface.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/script-engine/src/AssetScriptingInterface.h b/libraries/script-engine/src/AssetScriptingInterface.h index 287300cac8..d01eb939e2 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.h +++ b/libraries/script-engine/src/AssetScriptingInterface.h @@ -29,6 +29,7 @@ public: 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 deleteMapping(QString path, QScriptValue callback) { deleteMappings(QStringList(path), callback); } Q_INVOKABLE void getAllMappings(QScriptValue callback); Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QScriptValue callback); protected: From a65d06c7ce2eba355bdd3abee72ac03e3ce2d6e1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 13:14:55 -0800 Subject: [PATCH 089/209] fix rename to take old mapping first --- assignment-client/src/assets/AssetServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 9825e75c61..ce95d7d4cb 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -610,7 +610,7 @@ bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPa } } else { // take the old hash to remove the old mapping - auto oldMapping = _fileMappings[oldPath].toString(); + auto oldMapping = _fileMappings.take(oldPath).toString(); if (!oldMapping.isEmpty()) { _fileMappings[newPath] = oldMapping; From 5e9751c6ed2b78c15e378b6da3bf76b3dcd9526a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 13:28:05 -0800 Subject: [PATCH 090/209] bug fixes for rename/delete operations --- assignment-client/src/assets/AssetServer.cpp | 23 ++++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index ce95d7d4cb..4f85a0f9e9 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -532,7 +532,7 @@ bool AssetServer::deleteMappings(const AssetPathList& paths) { auto sizeBefore = _fileMappings.size(); while (it != _fileMappings.end()) { - if (it->toString().startsWith(path)) { + if (it.key().startsWith(path)) { it = _fileMappings.erase(it); } else { ++it; @@ -573,6 +573,8 @@ bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPa if (pathIsFolder(oldPath)) { if (!pathIsFolder(newPath)) { // we were asked to rename a path to a folder to a path that isn't a folder, this is a fail + qWarning() << "Cannot rename mapping from folder path" << oldPath << "to file path" << newPath; + return false; } @@ -583,12 +585,12 @@ bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPa auto it = oldMappings.begin(); while (it != oldMappings.end()) { - if (it->toString().startsWith(oldPath)) { - auto oldKey = it.key(); - auto newKey = oldKey.replace(0, oldPath.size(), newPath); + if (it.key().startsWith(oldPath)) { + auto newKey = it.key(); + newKey.replace(0, oldPath.size(), newPath); // remove the old version from the in memory file mappings - _fileMappings.remove(oldKey); + _fileMappings.remove(it.key()); _fileMappings.insert(newKey, it.value()); } @@ -597,18 +599,25 @@ bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPa if (writeMappingsToFile()) { // persisted the changed mappings, return success - qDebug() << "Renamed mapping:" << oldPath << "=>" << newPath; + qDebug() << "Renamed folder mapping:" << oldPath << "=>" << newPath; return true; } else { // couldn't persist the renamed paths, rollback and return failure _fileMappings = oldMappings; - qWarning() << "Failed to persist renamed mapping:" << oldPath << "=>" << newPath; + qWarning() << "Failed to persist renamed folder mapping:" << oldPath << "=>" << newPath; return false; } } else { + if (pathIsFolder(newPath)) { + // we were asked to rename a path to a file to a path that is a folder, this is a fail + qWarning() << "Cannot rename mapping from file path" << oldPath << "to folder path" << newPath; + + return false; + } + // take the old hash to remove the old mapping auto oldMapping = _fileMappings.take(oldPath).toString(); From d3dc81c7a09cb8b37d8506c56e3e853e91ef864b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 13:37:39 -0800 Subject: [PATCH 091/209] add delete debug, handle rename in memory state rollback --- assignment-client/src/assets/AssetServer.cpp | 21 ++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 4f85a0f9e9..5543dfeed5 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -561,6 +561,8 @@ bool AssetServer::deleteMappings(const AssetPathList& paths) { // persistence succeeded we are good to go return true; } else { + qWarning() << "Failed to persist deleted mappings, rolling back"; + // we didn't delete the previous mapping, put it back in our in-memory representation _fileMappings = oldMappings; @@ -619,10 +621,13 @@ bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPa } // take the old hash to remove the old mapping - auto oldMapping = _fileMappings.take(oldPath).toString(); + auto oldSourceMapping = _fileMappings.take(oldPath).toString(); - if (!oldMapping.isEmpty()) { - _fileMappings[newPath] = oldMapping; + // in case we're overwriting, keep the current destination mapping for potential rollback + auto oldDestinationMapping = _fileMappings.value(newPath); + + if (!oldSourceMapping.isEmpty()) { + _fileMappings[newPath] = oldSourceMapping; if (writeMappingsToFile()) { // persisted the renamed mapping, return success @@ -631,7 +636,15 @@ bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPa return true; } else { // we couldn't persist the renamed mapping, rollback and return failure - _fileMappings[oldPath] = oldMapping; + _fileMappings[oldPath] = oldSourceMapping; + + if (!oldDestinationMapping.isNull()) { + // put back the overwritten mapping for the destination path + _fileMappings[newPath] = oldDestinationMapping.toString(); + } else { + // clear the new mapping + _fileMappings.remove(newPath); + } qDebug() << "Failed to persist renamed mapping:" << oldPath << "=>" << newPath; From a98640323722b8b17d9db345998b43aa26a82489 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 13:42:35 -0800 Subject: [PATCH 092/209] add a leading slash for faked migrated mappings --- assignment-client/src/assets/AssetServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 5543dfeed5..6dea815622 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -155,7 +155,7 @@ void AssetServer::performMappingMigration() { // add a new mapping with the old extension and a truncated version of the hash static const int TRUNCATED_HASH_NUM_CHAR = 16; - auto fakeFileName = hash.left(TRUNCATED_HASH_NUM_CHAR) + fullExtension; + auto fakeFileName = "/" + hash.left(TRUNCATED_HASH_NUM_CHAR) + fullExtension; qDebug() << "\tAdding a migration mapping from" << fakeFileName << "to" << hash; From fd5a5dd8f474ae419a1885e4b8ba8d6047f2814a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 16:53:04 -0800 Subject: [PATCH 093/209] Add QJSEngine compatible AssetMappingScriptInterface --- interface/src/Application.cpp | 1 + libraries/networking/src/AssetClient.cpp | 142 +++++++++++++++++++++++ libraries/networking/src/AssetClient.h | 34 ++++++ 3 files changed, 177 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 464e77ef6f..3551d58b53 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1267,6 +1267,7 @@ void Application::initializeUi() { rootContext->setContextProperty("Quat", new Quat()); rootContext->setContextProperty("Vec3", new Vec3()); rootContext->setContextProperty("Uuid", new ScriptUUID()); + rootContext->setContextProperty("Assets", new AssetMappingsScriptingInterface(engine)); rootContext->setContextProperty("AvatarList", DependencyManager::get().data()); diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 7c967e681a..42bfadee32 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -581,3 +581,145 @@ 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(); +} + +AssetMappingsScriptingInterface::AssetMappingsScriptingInterface(QJSEngine* engine) : + _engine(engine) +{ +} + +void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createSetMappingRequest(path, hash); + + connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetMappingRequest(path); + + connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()), request->getHash() }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createDeleteMappingsRequest(paths); + + connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetMappingsScriptingInterface::getAllMappings(QJSValue 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); + } + + QJSValueList args { uint8_t(request->getError()), map }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 87b8646be1..cec1bd3872 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -12,6 +12,7 @@ #ifndef hifi_AssetClient_h #define hifi_AssetClient_h +#include #include #include @@ -106,4 +107,37 @@ 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); +protected: + QSet _pendingRequests; + QScriptEngine* _engine; +}; + + +class AssetMappingsScriptingInterface : public QObject { + Q_OBJECT +public: + AssetMappingsScriptingInterface(QJSEngine* engine); + + Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback); + Q_INVOKABLE void getMapping(QString path, QJSValue callback); + Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); + Q_INVOKABLE void getAllMappings(QJSValue callback); +protected: + QSet _pendingRequests; + QJSEngine* _engine; +}; + + #endif From 38edfe0557f96c3b1282c92acebc588687f43fdd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 16:53:18 -0800 Subject: [PATCH 094/209] Fix GetAllMappings reading --- libraries/networking/src/AssetClient.cpp | 144 +++++++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 42bfadee32..40838e3732 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -31,6 +31,150 @@ 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->read(SHA256_HASH_LENGTH).toHex(); + _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); + }); +}; + AssetClient::AssetClient() { setCustomDeleter([](Dependency* dependency){ From 4da4fd889ae884dca0b83b4c565f6b6306cfec4c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 11:04:49 -0800 Subject: [PATCH 095/209] Add AssetMappingModel --- interface/resources/qml/AssetServer.qml | 3 +- libraries/networking/src/AssetClient.cpp | 99 +++++++++++++++++++++++- libraries/networking/src/AssetClient.h | 24 +++++- 3 files changed, 122 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 34f6502b40..3e2dba164d 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -33,7 +33,7 @@ Window { HifiConstants { id: hifi } property var scripts: ScriptDiscoveryService; - property var scriptsModel: scripts.scriptsModelFilter + property var scriptsModel: Assets.getAssetMappingModel() property var currentDirectory; Settings { @@ -45,6 +45,7 @@ Window { function reload() { print("reload"); + scriptsModel.refresh(); } function addToWorld() { print("addToWorld"); diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 40838e3732..7eb49ff418 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -792,8 +792,11 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb assetRequest->start(); } +static int standardItemModelMetaTypeId = qRegisterMetaType("AssetMappingModel*"); + AssetMappingsScriptingInterface::AssetMappingsScriptingInterface(QJSEngine* engine) : - _engine(engine) + _engine(engine), + _assetMappingModel(this) { } @@ -867,3 +870,97 @@ void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { request->start(); } + +AssetMappingModel::AssetMappingModel(QObject* parent) { +} + +void AssetMappingModel::refresh() { + qDebug() << "Refreshing asset mapping model"; + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetAllMappingsRequest(); + + connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) mutable { + qDebug() << "Got response"; + auto mappings = request->getMappings(); +// clear(); + for (auto& mapping : mappings) { + auto& path = mapping.first; + auto parts = path.split("/"); + auto length = parts.length(); + + QString prefix = parts[0]; + + QStandardItem* lastItem = nullptr; + + auto it = _pathToItemMap.find(prefix); + if (it == _pathToItemMap.end()) { + lastItem = new QStandardItem(parts[0]); + _pathToItemMap[prefix] = lastItem; + appendRow(lastItem); + } else { + lastItem = it.value(); + } + + if (length > 1) { + for (int i = 1; i < length; ++i) { + prefix += "/" + parts[i]; + + auto it = _pathToItemMap.find(prefix); + if (it == _pathToItemMap.end()) { + qDebug() << "prefix not found: " << prefix; + auto item = new QStandardItem(parts[i]); + lastItem->setChild(lastItem->rowCount(), 0, item); + lastItem = item; + _pathToItemMap[prefix] = lastItem; + } else { + lastItem = it.value(); + } + } + } + + Q_ASSERT(prefix == path); + } + }); + + request->start(); +} + + +// QModelIndex AssetMappingModel::index(int row, int column, const QModelIndex& parent) const { +// if (row < 0 || column < 0) { +// return QModelIndex(); +// } + +// if (parent.isValid()) { +// auto item = static_cast(parent.internalPointer()); +// return createIndex(row, column, ) +// } +// return createIndex(row, column, getFolderNodes( +// static_cast(getTreeNodeFromIndex(parent))).at(row)); +// } + +// QModelIndex AssetMappingModel::parent(const QModelIndex& child) const { +// AssetMappingItem* parent = (static_cast(child.internalPointer()))->getParent(); +// if (!parent) { +// return QModelIndex(); +// } +// AssetMappingItem* grandParent = parent->getParent(); +// int row = getFolderNodes(grandParent).indexOf(parent); +// return createIndex(row, 0, parent); +// } + +// QVariant AssetMappingModel::data(const QModelIndex& index, int role) const { +// TreeNodeBase* node = getTreeNodeFromIndex(index); +// if (!node) { +// return QVariant(); +// } +// return QVariant(); +// } + +// int AssetMappingModel::rowCount(const QModelIndex& parent) const { +// return 1; +// } + +// int AssetMappingModel::columnCount(const QModelIndex& parent) const { +// return 1; +// } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index cec1bd3872..f48be7f962 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -12,6 +12,7 @@ #ifndef hifi_AssetClient_h #define hifi_AssetClient_h +#include #include #include @@ -125,11 +126,31 @@ protected: }; + class AssetMappingModel : public QStandardItemModel { + Q_OBJECT + public: + AssetMappingModel(QObject* parent = nullptr); + + Q_INVOKABLE void refresh(); + private: + QHash _pathToItemMap; + }; + + //class AssetMappingItem : public QStandardItem { + //Q_OBJECT + //public: + //AssetMappingItem(); + //}; + + class AssetMappingsScriptingInterface : public QObject { Q_OBJECT + Q_PROPERTY(AssetMappingModel* mappingModel READ getAssetMappingModel CONSTANT) public: AssetMappingsScriptingInterface(QJSEngine* engine); + Q_INVOKABLE AssetMappingModel* getAssetMappingModel() { return &_assetMappingModel; }; + Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback); Q_INVOKABLE void getMapping(QString path, QJSValue callback); Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); @@ -137,7 +158,6 @@ public: protected: QSet _pendingRequests; QJSEngine* _engine; + AssetMappingModel _assetMappingModel; }; - - #endif From 64bd41c37fd11c77c25cc6d8fc06184def0a3060 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 11:52:24 -0800 Subject: [PATCH 096/209] Add AssetMappingItem and extra data to items --- libraries/networking/src/AssetClient.cpp | 24 +++++++++++++++++------- libraries/networking/src/AssetClient.h | 22 ++++++++++++++-------- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 7eb49ff418..710c1bf4bc 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -871,6 +871,13 @@ void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { request->start(); } +AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder) + : name(name), + fullPath(fullPath), + isFolder(isFolder) { + +} + AssetMappingModel::AssetMappingModel(QObject* parent) { } @@ -880,9 +887,7 @@ void AssetMappingModel::refresh() { auto request = assetClient->createGetAllMappingsRequest(); connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) mutable { - qDebug() << "Got response"; auto mappings = request->getMappings(); -// clear(); for (auto& mapping : mappings) { auto& path = mapping.first; auto parts = path.split("/"); @@ -895,6 +900,8 @@ void AssetMappingModel::refresh() { auto it = _pathToItemMap.find(prefix); if (it == _pathToItemMap.end()) { lastItem = new QStandardItem(parts[0]); + lastItem->setData(parts[0], Qt::UserRole + 1); + lastItem->setData(prefix, Qt::UserRole + 2); _pathToItemMap[prefix] = lastItem; appendRow(lastItem); } else { @@ -909,6 +916,8 @@ void AssetMappingModel::refresh() { if (it == _pathToItemMap.end()) { qDebug() << "prefix not found: " << prefix; auto item = new QStandardItem(parts[i]); + item->setData(parts[i], Qt::UserRole + 1); + item->setData(prefix, Qt::UserRole + 2); lastItem->setChild(lastItem->rowCount(), 0, item); lastItem = item; _pathToItemMap[prefix] = lastItem; @@ -925,7 +934,6 @@ void AssetMappingModel::refresh() { request->start(); } - // QModelIndex AssetMappingModel::index(int row, int column, const QModelIndex& parent) const { // if (row < 0 || column < 0) { // return QModelIndex(); @@ -950,13 +958,15 @@ void AssetMappingModel::refresh() { // } // QVariant AssetMappingModel::data(const QModelIndex& index, int role) const { -// TreeNodeBase* node = getTreeNodeFromIndex(index); -// if (!node) { -// return QVariant(); +// if (index.isValid()) { +// AssetMappingItem* item = (static_cast(index.internalPointer())); +// if (item) { +// return item->name; +// } // } // return QVariant(); // } - +// // int AssetMappingModel::rowCount(const QModelIndex& parent) const { // return 1; // } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index f48be7f962..08fcb099c4 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -126,23 +126,29 @@ protected: }; + class AssetMappingItem : public QStandardItem { + public: + AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder); + + QString name; + QString fullPath; + bool isFolder; + }; + + class AssetMappingModel : public QStandardItemModel { Q_OBJECT public: AssetMappingModel(QObject* parent = nullptr); + QVariant AssetMappingModel::data(const QModelIndex& index, int role) const; + Q_INVOKABLE void refresh(); + private: - QHash _pathToItemMap; + QHash _pathToItemMap; }; - //class AssetMappingItem : public QStandardItem { - //Q_OBJECT - //public: - //AssetMappingItem(); - //}; - - class AssetMappingsScriptingInterface : public QObject { Q_OBJECT Q_PROPERTY(AssetMappingModel* mappingModel READ getAssetMappingModel CONSTANT) From 6bd7afc7b3232f7e9150d5d1ee02133296c30bd9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 9 Mar 2016 14:19:28 -0800 Subject: [PATCH 097/209] Confirm overrides --- interface/resources/qml/AssetServer.qml | 81 ++++++++++++++++++++----- 1 file changed, 65 insertions(+), 16 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index ea2a082c8a..fdb9b81d87 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -44,10 +44,58 @@ Window { property alias directory: root.currentDirectory } + function doDeleteFile(path) { + console.log("Deleting " + path); + + } + function doUploadFile(path, mapping, addToWorld) { + console.log("Uploading " + path + " to " + mapping + " (addToWorld: " + addToWorld + ")"); + + + } + function doRenameFile(oldPath, newPath) { + console.log("Renaming " + oldPath + " to " + newPath); + + } + + function fileExists(destinationPath) { + return true; // TODO get correct value + } + + function askForOverride(path, callback) { + var object = desktop.messageBox({ + icon: OriginalDialogs.StandardIcon.Question, + buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No, + defaultButton: OriginalDialogs.StandardButton.No, + text: "Override?", + informativeText: "The following file already exists:\n" + path + + "\nDo you want to override it?" + }); + object.selected.connect(function(button) { + if (button === OriginalDialogs.StandardButton.Yes) { + callback(); + } + }); + } + + function canAddToWorld() { + var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i]; + var path = scriptsModel.data(treeView.currentIndex, 0x100); + + return supportedExtensions.reduce(function(total, current) { + return total | new RegExp(current).test(path); + }, false); + } + function reload() { print("reload"); } function addToWorld() { + var path = scriptsModel.data(treeView.currentIndex, 0x100); + if (!path) { + return; + } + print("addToWorld"); } function renameFile() { @@ -62,12 +110,13 @@ Window { placeholderText: "Enter path here" }); object.selected.connect(function(destinationPath) { - console.log("Renaming " + path + " to " + destinationPath); - - - - - + if (fileExists(destinationPath)) { + askForOverride(path, function() { + doRenameFile(path, destinationPath); + }); + } else { + doRenameFile(path, destinationPath); + } }); } function deleteFile() { @@ -87,10 +136,7 @@ Window { }); object.selected.connect(function(button) { if (button === OriginalDialogs.StandardButton.Yes) { - console.log("Deleting " + path); - - - + doDeleteFile(path); } }); } @@ -120,12 +166,13 @@ Window { placeholderText: "Enter path here" }); object.selected.connect(function(destinationPath) { - console.log("Uploading " + fileUrl + " to " + destinationPath + " (addToWorld: " + addToWorld + ")"); - - - - - + if (fileExists(destinationPath)) { + askForOverride(fileUrl, function() { + doUploadFile(fileUrl, destinationPath, addToWorld); + }); + } else { + doUploadFile(fileUrl, destinationPath, addToWorld); + } }); } @@ -161,6 +208,8 @@ Window { height: 26 width: 120 + enabled: canAddToWorld() + onClicked: root.addToWorld() } From 96ba57a94609fb558978ae79543cc0b9036ea55e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 14:24:14 -0800 Subject: [PATCH 098/209] remove client side caching of ATP mappings --- libraries/networking/src/AssetClient.cpp | 4 --- libraries/networking/src/AssetClient.h | 2 -- libraries/networking/src/MappingRequest.cpp | 28 --------------------- 3 files changed, 34 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 7c967e681a..19b0be3917 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -91,8 +91,6 @@ void AssetClient::clearCache() { return; } - _mappingCache.clear(); - if (auto cache = NetworkAccessManager::getInstance().cache()) { qDebug() << "AssetClient::clearCache(): Clearing disk cache."; cache->clear(); @@ -578,6 +576,4 @@ void AssetClient::handleNodeKilled(SharedNodePointer node) { messageMapIt->second.clear(); } } - - _mappingCache.clear(); } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 87b8646be1..299039ae8e 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -95,8 +95,6 @@ private: std::unordered_map> _pendingInfoRequests; std::unordered_map> _pendingUploads; - QHash _mappingCache; - friend class AssetRequest; friend class AssetUpload; friend class GetMappingRequest; diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp index 187694e134..0ab7d8fb36 100644 --- a/libraries/networking/src/MappingRequest.cpp +++ b/libraries/networking/src/MappingRequest.cpp @@ -32,14 +32,6 @@ 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; @@ -59,7 +51,6 @@ void GetMappingRequest::doStart() { if (!_error) { _hash = message->read(SHA256_HASH_LENGTH).toHex(); - assetClient->_mappingCache[_path] = _hash; } emit finished(this); }); @@ -88,12 +79,10 @@ void GetAllMappingsRequest::doStart() { 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); @@ -122,9 +111,6 @@ void SetMappingRequest::doStart() { } } - if (!error) { - assetClient->_mappingCache[_path] = _hash; - } emit finished(this); }); }; @@ -151,12 +137,6 @@ void DeleteMappingsRequest::doStart() { } } - if (!error) { - // enumerate the paths and remove them from the cache - for (auto& path : _paths) { - assetClient->_mappingCache.remove(path); - } - } emit finished(this); }); }; @@ -189,14 +169,6 @@ void RenameMappingRequest::doStart() { } } - 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); }); } From e2b976d9f15903b41af6b839d540767dfe61402c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 14:24:35 -0800 Subject: [PATCH 099/209] remove debug, fix asset find bug for incorrect folder --- assignment-client/src/assets/AssetServer.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 13257967ac..2218c5b5e3 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -220,12 +220,10 @@ void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNode auto it = _fileMappings.find(assetPath); if (it != _fileMappings.end()) { auto assetHash = it->toString(); - qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; replyPacket.writePrimitive(AssetServerError::NoError); replyPacket.write(QByteArray::fromHex(assetHash.toUtf8())); } else { - qDebug() << "Mapping not found for: " << assetPath; replyPacket.writePrimitive(AssetServerError::AssetNotFound); } } @@ -314,7 +312,7 @@ void AssetServer::handleAssetGetInfo(QSharedPointer message, Sh replyPacket->write(assetHash); QString fileName = QString(hexHash); - QFileInfo fileInfo { _resourcesDirectory.filePath(fileName) }; + QFileInfo fileInfo { _filesDirectory.filePath(fileName) }; if (fileInfo.exists() && fileInfo.isReadable()) { qDebug() << "Opening file: " << fileInfo.filePath(); From f5497aa1e7d0ed7d281cc4bb11008b0ca41f2450 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 13:55:33 -0800 Subject: [PATCH 100/209] Add new AssetMappingsScriptingInterface and add mappings model --- interface/resources/qml/AssetServer.qml | 5 + interface/src/Application.cpp | 8 +- libraries/networking/src/AssetClient.cpp | 393 ------------------ libraries/networking/src/AssetClient.h | 58 --- libraries/networking/src/MappingRequest.cpp | 12 +- .../src/AssetMappingsScriptingInterface.cpp | 218 ++++++++++ .../src/AssetMappingsScriptingInterface.h | 64 +++ .../src/AssetScriptingInterface.cpp | 87 ---- .../src/AssetScriptingInterface.h | 5 - 9 files changed, 298 insertions(+), 552 deletions(-) create mode 100644 libraries/script-engine/src/AssetMappingsScriptingInterface.cpp create mode 100644 libraries/script-engine/src/AssetMappingsScriptingInterface.h diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 3e2dba164d..d773d6f86a 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -72,6 +72,7 @@ Window { } function deleteFile() { var path = scriptsModel.data(treeView.currentIndex, 0x100); + print(path); if (!path) { return; } @@ -89,6 +90,10 @@ Window { if (button === OriginalDialogs.StandardButton.Yes) { console.log("Deleting " + path); + Assets.deleteMappings([path], function(err) { + print("Finished deleting path: ", path, err); + reload(); + }); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3551d58b53..abeff8ade6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -66,6 +66,7 @@ #include #include #include +#include #include #include #include @@ -413,6 +414,7 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(true, qApp, qApp); DependencyManager::set(); @@ -1267,7 +1269,7 @@ void Application::initializeUi() { rootContext->setContextProperty("Quat", new Quat()); rootContext->setContextProperty("Vec3", new Vec3()); rootContext->setContextProperty("Uuid", new ScriptUUID()); - rootContext->setContextProperty("Assets", new AssetMappingsScriptingInterface(engine)); + rootContext->setContextProperty("Assets", DependencyManager::get().data()); rootContext->setContextProperty("AvatarList", DependencyManager::get().data()); @@ -4288,8 +4290,8 @@ bool Application::askToSetAvatarUrl(const QString& url) { case FSTReader::HEAD_AND_BODY_MODEL: ok = QMessageBox::Ok == OffscreenUi::question("Set Avatar", - "Would you like to use '" + modelName + "' for your avatar?", - QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok); + "Would you like to use '" + modelName + "' for your avatar?", + QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok); break; default: diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 710c1bf4bc..7c967e681a 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -31,150 +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->read(SHA256_HASH_LENGTH).toHex(); - _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); - }); -}; - AssetClient::AssetClient() { setCustomDeleter([](Dependency* dependency){ @@ -725,252 +581,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(); -} - -static int standardItemModelMetaTypeId = qRegisterMetaType("AssetMappingModel*"); - -AssetMappingsScriptingInterface::AssetMappingsScriptingInterface(QJSEngine* engine) : - _engine(engine), - _assetMappingModel(this) -{ -} - -void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createSetMappingRequest(path, hash); - - connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; - - callback.call(args); - - request->deleteLater(); - - }); - - request->start(); -} - -void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createGetMappingRequest(path); - - connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()), request->getHash() }; - - callback.call(args); - - request->deleteLater(); - - }); - - request->start(); -} - -void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createDeleteMappingsRequest(paths); - - connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; - - callback.call(args); - - request->deleteLater(); - - }); - - request->start(); -} - -void AssetMappingsScriptingInterface::getAllMappings(QJSValue 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); - } - - QJSValueList args { uint8_t(request->getError()), map }; - - callback.call(args); - - request->deleteLater(); - - }); - - request->start(); -} - -AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder) - : name(name), - fullPath(fullPath), - isFolder(isFolder) { - -} - -AssetMappingModel::AssetMappingModel(QObject* parent) { -} - -void AssetMappingModel::refresh() { - qDebug() << "Refreshing asset mapping model"; - auto assetClient = DependencyManager::get(); - auto request = assetClient->createGetAllMappingsRequest(); - - connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) mutable { - auto mappings = request->getMappings(); - for (auto& mapping : mappings) { - auto& path = mapping.first; - auto parts = path.split("/"); - auto length = parts.length(); - - QString prefix = parts[0]; - - QStandardItem* lastItem = nullptr; - - auto it = _pathToItemMap.find(prefix); - if (it == _pathToItemMap.end()) { - lastItem = new QStandardItem(parts[0]); - lastItem->setData(parts[0], Qt::UserRole + 1); - lastItem->setData(prefix, Qt::UserRole + 2); - _pathToItemMap[prefix] = lastItem; - appendRow(lastItem); - } else { - lastItem = it.value(); - } - - if (length > 1) { - for (int i = 1; i < length; ++i) { - prefix += "/" + parts[i]; - - auto it = _pathToItemMap.find(prefix); - if (it == _pathToItemMap.end()) { - qDebug() << "prefix not found: " << prefix; - auto item = new QStandardItem(parts[i]); - item->setData(parts[i], Qt::UserRole + 1); - item->setData(prefix, Qt::UserRole + 2); - lastItem->setChild(lastItem->rowCount(), 0, item); - lastItem = item; - _pathToItemMap[prefix] = lastItem; - } else { - lastItem = it.value(); - } - } - } - - Q_ASSERT(prefix == path); - } - }); - - request->start(); -} - -// QModelIndex AssetMappingModel::index(int row, int column, const QModelIndex& parent) const { -// if (row < 0 || column < 0) { -// return QModelIndex(); -// } - -// if (parent.isValid()) { -// auto item = static_cast(parent.internalPointer()); -// return createIndex(row, column, ) -// } -// return createIndex(row, column, getFolderNodes( -// static_cast(getTreeNodeFromIndex(parent))).at(row)); -// } - -// QModelIndex AssetMappingModel::parent(const QModelIndex& child) const { -// AssetMappingItem* parent = (static_cast(child.internalPointer()))->getParent(); -// if (!parent) { -// return QModelIndex(); -// } -// AssetMappingItem* grandParent = parent->getParent(); -// int row = getFolderNodes(grandParent).indexOf(parent); -// return createIndex(row, 0, parent); -// } - -// QVariant AssetMappingModel::data(const QModelIndex& index, int role) const { -// if (index.isValid()) { -// AssetMappingItem* item = (static_cast(index.internalPointer())); -// if (item) { -// return item->name; -// } -// } -// return QVariant(); -// } -// -// int AssetMappingModel::rowCount(const QModelIndex& parent) const { -// return 1; -// } - -// int AssetMappingModel::columnCount(const QModelIndex& parent) const { -// return 1; -// } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 08fcb099c4..9e34774816 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -108,62 +108,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); -protected: - QSet _pendingRequests; - QScriptEngine* _engine; -}; - - - class AssetMappingItem : public QStandardItem { - public: - AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder); - - QString name; - QString fullPath; - bool isFolder; - }; - - - class AssetMappingModel : public QStandardItemModel { - Q_OBJECT - public: - AssetMappingModel(QObject* parent = nullptr); - - QVariant AssetMappingModel::data(const QModelIndex& index, int role) const; - - Q_INVOKABLE void refresh(); - - private: - QHash _pathToItemMap; - }; - -class AssetMappingsScriptingInterface : public QObject { - Q_OBJECT - Q_PROPERTY(AssetMappingModel* mappingModel READ getAssetMappingModel CONSTANT) -public: - AssetMappingsScriptingInterface(QJSEngine* engine); - - Q_INVOKABLE AssetMappingModel* getAssetMappingModel() { return &_assetMappingModel; }; - - Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback); - Q_INVOKABLE void getMapping(QString path, QJSValue callback); - Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); - Q_INVOKABLE void getAllMappings(QJSValue callback); -protected: - QSet _pendingRequests; - QJSEngine* _engine; - AssetMappingModel _assetMappingModel; -}; #endif diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp index 187694e134..73ea1483b0 100644 --- a/libraries/networking/src/MappingRequest.cpp +++ b/libraries/networking/src/MappingRequest.cpp @@ -50,7 +50,7 @@ void GetMappingRequest::doStart() { break; case AssetServerError::AssetNotFound: _error = NotFound; - break; + break default: _error = UnknownError; break; @@ -85,13 +85,13 @@ void GetAllMappingsRequest::doStart() { } - if (!error) { + 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(); + auto hash = message->read(SHA256_HASH_LENGTH).toHex(); _mappings[path] = hash; assetClient->_mappingCache[path] = hash; } @@ -122,7 +122,7 @@ void SetMappingRequest::doStart() { } } - if (!error) { + if (!_error) { assetClient->_mappingCache[_path] = _hash; } emit finished(this); @@ -151,7 +151,7 @@ void DeleteMappingsRequest::doStart() { } } - if (!error) { + if (!_error) { // enumerate the paths and remove them from the cache for (auto& path : _paths) { assetClient->_mappingCache.remove(path); @@ -189,7 +189,7 @@ void RenameMappingRequest::doStart() { } } - if (!error) { + if (!_error) { // take the hash mapped for the old path from the cache auto hash = assetClient->_mappingCache.take(_oldPath); if (!hash.isEmpty()) { diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp new file mode 100644 index 0000000000..c8370170db --- /dev/null +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -0,0 +1,218 @@ +// +// AssetMappingsScriptingInterface.cpp +// libraries/script-engine/src +// +// Created by Ryan Huffman on 2016-03-09. +// 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 "AssetMappingsScriptingInterface.h" + +#include + +#include +#include +#include +#include + +AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() { +} + +void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createSetMappingRequest(path, hash); + + connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetMappingRequest(path); + + connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()), request->getHash() }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createDeleteMappingsRequest(paths); + + connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetMappingsScriptingInterface::getAllMappings(QJSValue 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); + } + + QJSValueList args { uint8_t(request->getError()), map }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString newPath, QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createRenameMappingRequest(oldPath, newPath); + + connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + + +AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder) + : name(name), + fullPath(fullPath), + isFolder(isFolder) { + +} + +static int assetMappingModelMetatypeId = qRegisterMetaType("AssetMappingModel*"); + +AssetMappingModel::AssetMappingModel(QObject* parent) { +} + +void AssetMappingModel::refresh() { + qDebug() << "Refreshing asset mapping model"; + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetAllMappingsRequest(); + + connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) mutable { + auto mappings = request->getMappings(); + for (auto& mapping : mappings) { + auto& path = mapping.first; + auto parts = path.split("/"); + auto length = parts.length(); + + QString fullPath = parts[0]; + + QStandardItem* lastItem = nullptr; + + auto it = _pathToItemMap.find(fullPath); + if (it == _pathToItemMap.end()) { + lastItem = new QStandardItem(parts[0]); + lastItem->setData(parts[0], Qt::UserRole + 1); + lastItem->setData(fullPath, Qt::UserRole + 2); + _pathToItemMap[fullPath] = lastItem; + appendRow(lastItem); + } + else { + lastItem = it.value(); + } + + if (length > 1) { + for (int i = 1; i < length; ++i) { + fullPath += "/" + parts[i]; + + auto it = _pathToItemMap.find(fullPath); + if (it == _pathToItemMap.end()) { + qDebug() << "prefix not found: " << fullPath; + auto item = new QStandardItem(parts[i]); + bool isFolder = i < length - 1; + item->setData(isFolder ? fullPath + "/" : fullPath, Qt::UserRole); + lastItem->setChild(lastItem->rowCount(), 0, item); + lastItem = item; + _pathToItemMap[fullPath] = lastItem; + } + else { + lastItem = it.value(); + } + } + } + + Q_ASSERT(fullPath == path); + } + }); + + request->start(); +} + +// QModelIndex AssetMappingModel::index(int row, int column, const QModelIndex& parent) const { +// if (row < 0 || column < 0) { +// return QModelIndex(); +// } + +// if (parent.isValid()) { +// auto item = static_cast(parent.internalPointer()); +// return createIndex(row, column, ) +// } +// return createIndex(row, column, getFolderNodes( +// static_cast(getTreeNodeFromIndex(parent))).at(row)); +// } + +// QModelIndex AssetMappingModel::parent(const QModelIndex& child) const { +// AssetMappingItem* parent = (static_cast(child.internalPointer()))->getParent(); +// if (!parent) { +// return QModelIndex(); +// } +// AssetMappingItem* grandParent = parent->getParent(); +// int row = getFolderNodes(grandParent).indexOf(parent); +// return createIndex(row, 0, parent); +// } + +// QVariant AssetMappingModel::data(const QModelIndex& index, int role) const { +// if (index.isValid()) { +// AssetMappingItem* item = (static_cast(index.internalPointer())); +// if (item) { +// return item->name; +// } +// } +// return QVariant(); +// } +// +// int AssetMappingModel::rowCount(const QModelIndex& parent) const { +// return 1; +// } + +// int AssetMappingModel::columnCount(const QModelIndex& parent) const { +// return 1; +// } diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.h b/libraries/script-engine/src/AssetMappingsScriptingInterface.h new file mode 100644 index 0000000000..66a31414bb --- /dev/null +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.h @@ -0,0 +1,64 @@ +// +// AssetScriptingInterface.h +// libraries/script-engine/src +// +// Created by Ryan Huffman on 2016-03-09. +// 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_AssetMappingsScriptingInterface_h +#define hifi_AssetMappingsScriptingInterface_h + +#include +#include + +#include + + class AssetMappingItem : public QStandardItem { + public: + AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder); + + QString name; + QString fullPath; + bool isFolder; + }; + + + class AssetMappingModel : public QStandardItemModel { + Q_OBJECT + public: + AssetMappingModel(QObject* parent = nullptr); + +// QVariant AssetMappingModel::data(const QModelIndex& index, int role) const; + + Q_INVOKABLE void refresh(); + + private: + QHash _pathToItemMap; + }; + + +class AssetMappingsScriptingInterface : public QObject, public Dependency { + Q_OBJECT +public: + AssetMappingsScriptingInterface(); + + Q_INVOKABLE AssetMappingModel* getAssetMappingModel() { return &_assetMappingModel; } + + Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback); + Q_INVOKABLE void getMapping(QString path, QJSValue callback); + Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); + Q_INVOKABLE void getAllMappings(QJSValue callback); + Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QJSValue callback); +protected: + QSet _pendingRequests; + AssetMappingModel _assetMappingModel; +}; + + +#endif // hifi_AssetMappingsScriptingInterface_h diff --git a/libraries/script-engine/src/AssetScriptingInterface.cpp b/libraries/script-engine/src/AssetScriptingInterface.cpp index db29008976..fb315434fd 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetScriptingInterface.cpp @@ -84,90 +84,3 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb 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 index 287300cac8..63b16fd51d 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.h +++ b/libraries/script-engine/src/AssetScriptingInterface.h @@ -26,11 +26,6 @@ public: 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; From d299ce2677ab6f0bdc205554c2c43726c8579648 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 14:56:56 -0800 Subject: [PATCH 101/209] Fix missing semicolon --- libraries/networking/src/MappingRequest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp index 73ea1483b0..9afa3e7432 100644 --- a/libraries/networking/src/MappingRequest.cpp +++ b/libraries/networking/src/MappingRequest.cpp @@ -50,7 +50,7 @@ void GetMappingRequest::doStart() { break; case AssetServerError::AssetNotFound: _error = NotFound; - break + break; default: _error = UnknownError; break; From f23057b1c04093f3b765709e1a8593eadf90ac8a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 16:29:17 -0800 Subject: [PATCH 102/209] Add renaming to Asset qml --- interface/resources/qml/AssetServer.qml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index d773d6f86a..d76374c10c 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -33,7 +33,7 @@ Window { HifiConstants { id: hifi } property var scripts: ScriptDiscoveryService; - property var scriptsModel: Assets.getAssetMappingModel() + property var scriptsModel: Assets.mappingModel; property var currentDirectory; Settings { @@ -52,6 +52,7 @@ Window { } function renameFile() { var path = scriptsModel.data(treeView.currentIndex, 0x100); + print(path); if (!path) { return; } @@ -63,16 +64,15 @@ Window { }); object.selected.connect(function(destinationPath) { console.log("Renaming " + path + " to " + destinationPath); - - - - - + Assets.renameMapping(path, destinationPath, function(err) { + print("Finished rename: ", err); + reload(); + }); }); } function deleteFile() { var path = scriptsModel.data(treeView.currentIndex, 0x100); - print(path); + print(treeView.currentIndex, path); if (!path) { return; } @@ -94,8 +94,6 @@ Window { print("Finished deleting path: ", path, err); reload(); }); - - } }); } From ebc6c8ce44e2f4deeef96fd537dcf62f4acf7e32 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 16:29:51 -0800 Subject: [PATCH 103/209] Add proper model updating to asset mapping model --- .../src/AssetMappingsScriptingInterface.cpp | 91 +++++++++++++------ .../src/AssetMappingsScriptingInterface.h | 5 +- 2 files changed, 67 insertions(+), 29 deletions(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index c8370170db..c5b165d7f6 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -20,6 +20,9 @@ AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() { } +AssetMappingsScriptingInterface::~AssetMappingsScriptingInterface() { + qDebug() << "Destroying mapping interface"; +} void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) { auto assetClient = DependencyManager::get(); @@ -118,7 +121,11 @@ AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, static int assetMappingModelMetatypeId = qRegisterMetaType("AssetMappingModel*"); -AssetMappingModel::AssetMappingModel(QObject* parent) { +AssetMappingModel::AssetMappingModel() { +} + +AssetMappingModel::~AssetMappingModel() { + qDebug() << " DEST"; } void AssetMappingModel::refresh() { @@ -128,49 +135,77 @@ void AssetMappingModel::refresh() { connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) mutable { auto mappings = request->getMappings(); + auto existingPaths = _pathToItemMap.keys(); for (auto& mapping : mappings) { auto& path = mapping.first; auto parts = path.split("/"); auto length = parts.length(); - QString fullPath = parts[0]; + existingPaths.removeOne(mapping.first); + + QString fullPath = "";// parts[0]; QStandardItem* lastItem = nullptr; - auto it = _pathToItemMap.find(fullPath); - if (it == _pathToItemMap.end()) { - lastItem = new QStandardItem(parts[0]); - lastItem->setData(parts[0], Qt::UserRole + 1); - lastItem->setData(fullPath, Qt::UserRole + 2); - _pathToItemMap[fullPath] = lastItem; - appendRow(lastItem); - } - else { - lastItem = it.value(); - } + for (int i = 0; i < length; ++i) { + fullPath += (i == 0 ? "" : "/") + parts[i]; - if (length > 1) { - for (int i = 1; i < length; ++i) { - fullPath += "/" + parts[i]; - - auto it = _pathToItemMap.find(fullPath); - if (it == _pathToItemMap.end()) { - qDebug() << "prefix not found: " << fullPath; - auto item = new QStandardItem(parts[i]); - bool isFolder = i < length - 1; - item->setData(isFolder ? fullPath + "/" : fullPath, Qt::UserRole); + auto it = _pathToItemMap.find(fullPath); + if (it == _pathToItemMap.end()) { + qDebug() << "prefix not found: " << fullPath; + auto item = new QStandardItem(parts[i]); + bool isFolder = i < length - 1; + item->setData(isFolder ? fullPath + "/" : fullPath, Qt::UserRole); + item->setData(isFolder, Qt::UserRole + 1); + if (lastItem) { lastItem->setChild(lastItem->rowCount(), 0, item); - lastItem = item; - _pathToItemMap[fullPath] = lastItem; - } - else { - lastItem = it.value(); + } else { + appendRow(item); } + + lastItem = item; + _pathToItemMap[fullPath] = lastItem; + } + else { + lastItem = it.value(); } } Q_ASSERT(fullPath == path); } + for (auto& path : existingPaths) { + Q_ASSERT(_pathToItemMap.contains(path)); + auto item = _pathToItemMap[path]; + if (item->data(Qt::UserRole + 1).toBool()) { + continue; + } + + qDebug() << "removing existing: " << path; + + while (item) { + // During each iteration, delete item + QStandardItem* nextItem = nullptr; + + auto parent = item->parent(); + if (parent) { + parent->removeRow(item->row()); + if (parent->rowCount() > 0) { + // The parent still contains children, set the nextItem to null so we stop processing + nextItem = nullptr; + } else { + nextItem = parent; + } + } else { + removeRow(item->row()); + } + + _pathToItemMap.remove(path); + //delete item; + + item = nextItem; + } + //removeitem->index(); + } }); request->start(); diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.h b/libraries/script-engine/src/AssetMappingsScriptingInterface.h index 66a31414bb..3afdab35cf 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.h +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.h @@ -32,7 +32,8 @@ class AssetMappingModel : public QStandardItemModel { Q_OBJECT public: - AssetMappingModel(QObject* parent = nullptr); + AssetMappingModel(); + ~AssetMappingModel(); // QVariant AssetMappingModel::data(const QModelIndex& index, int role) const; @@ -45,8 +46,10 @@ class AssetMappingsScriptingInterface : public QObject, public Dependency { Q_OBJECT + Q_PROPERTY(AssetMappingModel* mappingModel READ getAssetMappingModel CONSTANT) public: AssetMappingsScriptingInterface(); + ~AssetMappingsScriptingInterface(); Q_INVOKABLE AssetMappingModel* getAssetMappingModel() { return &_assetMappingModel; } From 232bfc9061ebc691abf9d19d1aa62575ca856ddb Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 16:44:31 -0800 Subject: [PATCH 104/209] Cleanup AssetServer qml --- interface/resources/qml/AssetServer.qml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 8134d78b26..54f7a10b25 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -47,7 +47,7 @@ Window { function doDeleteFile(path) { console.log("Deleting " + path); - Assets.deleteMappings([path], function(err) { + Assets.deleteMappings(path, function(err) { print("Finished deleting path: ", path, err); reload(); }); @@ -61,8 +61,7 @@ Window { function doRenameFile(oldPath, newPath) { console.log("Renaming " + oldPath + " to " + newPath); - console.log("Renaming " + path + " to " + destinationPath); - Assets.renameMapping(path, destinationPath, function(err) { + Assets.renameMapping(oldPath, destinationPath, function(err) { print("Finished rename: ", err); reload(); }); @@ -111,7 +110,6 @@ Window { } function renameFile() { var path = scriptsModel.data(treeView.currentIndex, 0x100); - print(path); if (!path) { return; } @@ -133,7 +131,6 @@ Window { } function deleteFile() { var path = scriptsModel.data(treeView.currentIndex, 0x100); - print(treeView.currentIndex, path); if (!path) { return; } From 3467e06199be0af83f642ebeb57c3292e7283339 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 16:44:41 -0800 Subject: [PATCH 105/209] Fix bugs in mapping model update --- .../src/AssetMappingsScriptingInterface.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index c5b165d7f6..8dc40b0df1 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -173,15 +173,24 @@ void AssetMappingModel::refresh() { Q_ASSERT(fullPath == path); } + + // Remove folders from list + auto it = existingPaths.begin(); + while (it != existingPaths.end()) { + auto item = _pathToItemMap[*it]; + if (item->data(Qt::UserRole + 1).toBool()) { + it = existingPaths.erase(it); + } else { + ++it; + } + } + for (auto& path : existingPaths) { Q_ASSERT(_pathToItemMap.contains(path)); - auto item = _pathToItemMap[path]; - if (item->data(Qt::UserRole + 1).toBool()) { - continue; - } - qDebug() << "removing existing: " << path; + auto item = _pathToItemMap[path]; + while (item) { // During each iteration, delete item QStandardItem* nextItem = nullptr; From fa66c0a5211cf377da783a39e342ad7653968dce Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 16:44:51 -0800 Subject: [PATCH 106/209] Remove old model code --- .../src/AssetMappingsScriptingInterface.cpp | 41 ------------------- 1 file changed, 41 deletions(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index 8dc40b0df1..7fab655e26 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -219,44 +219,3 @@ void AssetMappingModel::refresh() { request->start(); } - -// QModelIndex AssetMappingModel::index(int row, int column, const QModelIndex& parent) const { -// if (row < 0 || column < 0) { -// return QModelIndex(); -// } - -// if (parent.isValid()) { -// auto item = static_cast(parent.internalPointer()); -// return createIndex(row, column, ) -// } -// return createIndex(row, column, getFolderNodes( -// static_cast(getTreeNodeFromIndex(parent))).at(row)); -// } - -// QModelIndex AssetMappingModel::parent(const QModelIndex& child) const { -// AssetMappingItem* parent = (static_cast(child.internalPointer()))->getParent(); -// if (!parent) { -// return QModelIndex(); -// } -// AssetMappingItem* grandParent = parent->getParent(); -// int row = getFolderNodes(grandParent).indexOf(parent); -// return createIndex(row, 0, parent); -// } - -// QVariant AssetMappingModel::data(const QModelIndex& index, int role) const { -// if (index.isValid()) { -// AssetMappingItem* item = (static_cast(index.internalPointer())); -// if (item) { -// return item->name; -// } -// } -// return QVariant(); -// } -// -// int AssetMappingModel::rowCount(const QModelIndex& parent) const { -// return 1; -// } - -// int AssetMappingModel::columnCount(const QModelIndex& parent) const { -// return 1; -// } From dd52dd69d9fdb62919655834a6171ae65e4c1211 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 16:50:37 -0800 Subject: [PATCH 107/209] Fix rename mapping --- interface/resources/qml/AssetServer.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 54f7a10b25..f9cc566d39 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -61,7 +61,7 @@ Window { function doRenameFile(oldPath, newPath) { console.log("Renaming " + oldPath + " to " + newPath); - Assets.renameMapping(oldPath, destinationPath, function(err) { + Assets.renameMapping(oldPath, newPath, function(err) { print("Finished rename: ", err); reload(); }); @@ -121,7 +121,7 @@ Window { }); object.selected.connect(function(destinationPath) { if (fileExists(destinationPath)) { - askForOverride(path, function() { + askForOverride(destinationPath, function() { doRenameFile(path, destinationPath); }); } else { From 738ae54e8dafbbc85b939a315ed44375d3baf345 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 16:56:28 -0800 Subject: [PATCH 108/209] Remove comment --- libraries/script-engine/src/AssetMappingsScriptingInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index 7fab655e26..4dfc99b13f 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -143,7 +143,7 @@ void AssetMappingModel::refresh() { existingPaths.removeOne(mapping.first); - QString fullPath = "";// parts[0]; + QString fullPath = ""; QStandardItem* lastItem = nullptr; From 85fe1349ebb82ac43ee2db463aa26a864519d876 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 16:58:53 -0800 Subject: [PATCH 109/209] fix filename in header comment for AssetMappingsScriptingInterface --- libraries/script-engine/src/AssetMappingsScriptingInterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.h b/libraries/script-engine/src/AssetMappingsScriptingInterface.h index 0bf98f47cc..797f099fb5 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.h +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.h @@ -1,5 +1,5 @@ // -// AssetScriptingInterface.h +// AssetMappingsScriptingInterface.h // libraries/script-engine/src // // Created by Ryan Huffman on 2016-03-09. From ea5349f7a00687b496d026ec276f2fe0c911caca Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 16:59:31 -0800 Subject: [PATCH 110/209] remove ctor and dtor for AssetMappingsScriptingInterface --- .../script-engine/src/AssetMappingsScriptingInterface.cpp | 6 ------ .../script-engine/src/AssetMappingsScriptingInterface.h | 3 --- 2 files changed, 9 deletions(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index 4dfc99b13f..85ac84c244 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -18,12 +18,6 @@ #include #include -AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() { -} -AssetMappingsScriptingInterface::~AssetMappingsScriptingInterface() { - qDebug() << "Destroying mapping interface"; -} - void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createSetMappingRequest(path, hash); diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.h b/libraries/script-engine/src/AssetMappingsScriptingInterface.h index 797f099fb5..27d9ceff9f 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.h +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.h @@ -48,9 +48,6 @@ class AssetMappingsScriptingInterface : public QObject, public Dependency { Q_OBJECT Q_PROPERTY(AssetMappingModel* mappingModel READ getAssetMappingModel CONSTANT) public: - AssetMappingsScriptingInterface(); - ~AssetMappingsScriptingInterface(); - Q_INVOKABLE AssetMappingModel* getAssetMappingModel() { return &_assetMappingModel; } Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback); From 7b08ae37479a628e25b7857f377fe5a2955e9518 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 17:30:02 -0800 Subject: [PATCH 111/209] drop invalid mappings on AssetServer load --- assignment-client/src/assets/AssetServer.cpp | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index da1a7d3163..f37c6d706e 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -453,6 +453,30 @@ void AssetServer::loadMappingsFromFile() { if (error.error == QJsonParseError::NoError) { _fileMappings = jsonDocument.object().toVariantHash(); + // remove any mappings that don't match the expected format + auto it = _fileMappings.begin(); + while (it != _fileMappings.end()) { + bool shouldDrop = false; + + if (it.key()[0] != '/') { + qWarning() << "Will not keep mapping for" << it.key() << "since it does not have a leading forward slash."; + shouldDrop = true; + } + + QRegExp hashFileRegex { "^[A-Fa-f0-9]{" + QString::number(SHA256_HASH_HEX_LENGTH) + "}$" }; + + if (!hashFileRegex.exactMatch(it.value().toString())) { + qWarning() << "Will not keep mapping for" << it.key() << "since it does not have a valid hash."; + shouldDrop = true; + } + + if (shouldDrop) { + it = _fileMappings.erase(it); + } else { + ++it; + } + } + qInfo() << "Loaded" << _fileMappings.count() << "mappings from map file at" << mapFilePath; return; } From 6f044e1cd31994566d85af097ad2dea81db3a4ba Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 17:36:04 -0800 Subject: [PATCH 112/209] handling for leading slashes while loading mappings --- .../script-engine/src/AssetMappingsScriptingInterface.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index 85ac84c244..3f2dd84721 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -137,12 +137,13 @@ void AssetMappingModel::refresh() { existingPaths.removeOne(mapping.first); - QString fullPath = ""; + QString fullPath = "/"; QStandardItem* lastItem = nullptr; - for (int i = 0; i < length; ++i) { - fullPath += (i == 0 ? "" : "/") + parts[i]; + // start index at 1 to avoid empty string from leading slash + for (int i = 1; i < length; ++i) { + fullPath += (i == 1 ? "" : "/") + parts[i]; auto it = _pathToItemMap.find(fullPath); if (it == _pathToItemMap.end()) { From 672f8ec1f7505bc223ae618126f49bb93cbcdbec Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 17:43:31 -0800 Subject: [PATCH 113/209] add checking for leading slash in mapping operations --- assignment-client/src/assets/AssetServer.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index f37c6d706e..e094b0d749 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -244,6 +244,7 @@ void AssetServer::handleGetAllMappingOperation(ReceivedMessage& message, SharedN void AssetServer::handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket) { if (senderNode->getCanRez()) { QString assetPath = message.readString(); + auto assetHash = message.read(SHA256_HASH_LENGTH).toHex(); if (setMapping(assetPath, assetHash)) { @@ -511,6 +512,12 @@ bool AssetServer::writeMappingsToFile() { } bool AssetServer::setMapping(const AssetPath& path, const AssetHash& hash) { + + if (path[0] != '/') { + qWarning() << "Cannot set a mapping that does not have a leading forward slash:" << path; + return false; + } + // remember what the old mapping was in case persistence fails auto oldMapping = _fileMappings.value(path).toString(); @@ -593,6 +600,13 @@ bool AssetServer::deleteMappings(const AssetPathList& paths) { } bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPath) { + if (oldPath[0] != '/' || newPath[0] != '/') { + qWarning() << "Cannot perform rename with invalid paths - both should have leading forward slashes:" + << oldPath << "=>" << newPath; + + return false; + } + // figure out if this rename is for a file or folder if (pathIsFolder(oldPath)) { if (!pathIsFolder(newPath)) { From ae3c0f6646d3623db698651ff15b9d3cf21a7619 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 18:01:10 -0800 Subject: [PATCH 114/209] add hash and path checking --- assignment-client/src/assets/AssetServer.cpp | 18 +++++++++++------- .../networking/src/AssetResourceRequest.cpp | 18 +++++++++--------- .../networking/src/AssetResourceRequest.h | 2 +- libraries/networking/src/AssetUtils.cpp | 10 ++++++++++ libraries/networking/src/AssetUtils.h | 6 ++++++ 5 files changed, 37 insertions(+), 17 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index e094b0d749..428920a44c 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -117,7 +117,7 @@ void AssetServer::completeSetup() { // Check the asset directory to output some information about what we have auto files = _filesDirectory.entryList(QDir::Files); - QRegExp hashFileRegex { "^[a-f0-9]{" + QString::number(SHA256_HASH_HEX_LENGTH) + "}$" }; + QRegExp hashFileRegex { ASSET_HASH_REGEX_STRING }; auto hashedFiles = files.filter(hashFileRegex); qInfo() << "There are" << hashedFiles.size() << "asset files in the asset directory."; @@ -459,14 +459,13 @@ void AssetServer::loadMappingsFromFile() { while (it != _fileMappings.end()) { bool shouldDrop = false; - if (it.key()[0] != '/') { - qWarning() << "Will not keep mapping for" << it.key() << "since it does not have a leading forward slash."; + if (!isValidPath(it.key())) { + qWarning() << "Will not keep mapping for" << it.key() << "since it is not a valid path."; shouldDrop = true; } - QRegExp hashFileRegex { "^[A-Fa-f0-9]{" + QString::number(SHA256_HASH_HEX_LENGTH) + "}$" }; - if (!hashFileRegex.exactMatch(it.value().toString())) { + if (!isValidHash(it.value().toString())) { qWarning() << "Will not keep mapping for" << it.key() << "since it does not have a valid hash."; shouldDrop = true; } @@ -513,8 +512,13 @@ bool AssetServer::writeMappingsToFile() { bool AssetServer::setMapping(const AssetPath& path, const AssetHash& hash) { - if (path[0] != '/') { - qWarning() << "Cannot set a mapping that does not have a leading forward slash:" << path; + if (!isValidPath(path)) { + qWarning() << "Cannot set a mapping for invalid path:" << path << "=>" << hash; + return false; + } + + if (!isValidHash(hash)) { + qWarning() << "Cannot set a mapping for invalid hash" << path << "=>" << hash; return false; } diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index a588bfb0d8..3cc7bdd4c7 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -25,11 +25,11 @@ AssetResourceRequest::~AssetResourceRequest() { } } -bool AssetResourceRequest::urlIsAssetPath() const { +bool AssetResourceRequest::urlIsAssetHash() const { static const QString ATP_HASH_REGEX_STRING = "^atp:([A-Fa-f0-9]{64})(\\.[\\w]+)?$"; QRegExp hashRegex { ATP_HASH_REGEX_STRING }; - return !hashRegex.exactMatch(_url.toString()); + return hashRegex.exactMatch(_url.toString()); } void AssetResourceRequest::doSend() { @@ -39,18 +39,18 @@ void AssetResourceRequest::doSend() { // We'll either have a hash or an ATP path to a file (that maps to a hash) - if (urlIsAssetPath()) { - // This is an ATP path, we'll need to figure out what the mapping is. - // This may incur a roundtrip to the asset-server, or it may return immediately from the cache in AssetClient. - - auto path = _url.path(); - requestMappingForPath(path); - } else { + if (urlIsAssetHash()) { // We've detected that this is a hash - simply use AssetClient to request that asset auto parts = _url.path().split(".", QString::SkipEmptyParts); auto hash = parts.length() > 0 ? parts[0] : ""; requestHash(hash); + } else { + // This is an ATP path, we'll need to figure out what the mapping is. + // This may incur a roundtrip to the asset-server, or it may return immediately from the cache in AssetClient. + + auto path = _url.path(); + requestMappingForPath(path); } } diff --git a/libraries/networking/src/AssetResourceRequest.h b/libraries/networking/src/AssetResourceRequest.h index 2fb8cfd3df..f517c57030 100644 --- a/libraries/networking/src/AssetResourceRequest.h +++ b/libraries/networking/src/AssetResourceRequest.h @@ -30,7 +30,7 @@ private slots: void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); private: - bool urlIsAssetPath() const; + bool urlIsAssetHash() const; void requestMappingForPath(const AssetPath& path); void requestHash(const AssetHash& hash); diff --git a/libraries/networking/src/AssetUtils.cpp b/libraries/networking/src/AssetUtils.cpp index cf1bdbe8f2..e25f357fcc 100644 --- a/libraries/networking/src/AssetUtils.cpp +++ b/libraries/networking/src/AssetUtils.cpp @@ -63,3 +63,13 @@ bool saveToCache(const QUrl& url, const QByteArray& file) { } return false; } + +bool isValidPath(const AssetPath& path) { + QRegExp pathRegex { ASSET_PATH_REGEX_STRING }; + return pathRegex.exactMatch(path); +} + +bool isValidHash(const AssetHash& hash) { + QRegExp hashRegex { ASSET_HASH_REGEX_STRING }; + return hashRegex.exactMatch(hash); +} diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 2495326b67..52ed7336c2 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -31,6 +31,9 @@ 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 +const QString ASSET_PATH_REGEX_STRING = "^\\/(?:[^\\/]|\\/(?!\\/))*$"; +const QString ASSET_HASH_REGEX_STRING = QString("^[a-fA-F0-9]{%1}$").arg(SHA256_HASH_HEX_LENGTH); + enum AssetServerError : uint8_t { NoError = 0, AssetNotFound, @@ -55,4 +58,7 @@ QByteArray hashData(const QByteArray& data); QByteArray loadFromCache(const QUrl& url); bool saveToCache(const QUrl& url, const QByteArray& file); +bool isValidPath(const AssetPath& path); +bool isValidHash(const QString& hashString); + #endif From 3e5e2eef177bd2f91edeff35de39e6b965ae130d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 10 Mar 2016 08:18:17 -0800 Subject: [PATCH 115/209] Add mapping sorting, copying, and isKnownMapping --- interface/resources/qml/AssetServer.qml | 49 ++++++++++++++----- .../scripting/WindowScriptingInterface.cpp | 6 +++ .../src/scripting/WindowScriptingInterface.h | 1 + .../src/AssetMappingsScriptingInterface.cpp | 9 ++++ .../src/AssetMappingsScriptingInterface.h | 10 ++++ 5 files changed, 62 insertions(+), 13 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index f9cc566d39..3ff5bb98f1 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -33,7 +33,7 @@ Window { HifiConstants { id: hifi } property var scripts: ScriptDiscoveryService; - property var scriptsModel: Assets.mappingModel; + property var assetMappingsModel: Assets.proxyModel; property var currentDirectory; property alias currentFileUrl: fileUrlTextField.text; @@ -67,8 +67,8 @@ Window { }); } - function fileExists(destinationPath) { - return true; // TODO get correct value + function fileExists(path) { + return Assets.isKnownMapping(path); } function askForOverride(path, callback) { @@ -89,7 +89,7 @@ Window { function canAddToWorld() { var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i]; - var path = scriptsModel.data(treeView.currentIndex, 0x100); + var path = assetMappingsModel.data(treeView.currentIndex, 0x100); return supportedExtensions.reduce(function(total, current) { return total | new RegExp(current).test(path); @@ -98,18 +98,25 @@ Window { function reload() { print("reload"); - scriptsModel.refresh(); + Assets.mappingModel.refresh(); } function addToWorld() { - var path = scriptsModel.data(treeView.currentIndex, 0x100); + var path = assetMappingsModel.data(treeView.currentIndex, 0x100); if (!path) { return; } - - print("addToWorld"); } + + function copyURLToClipboard() { + var path = assetMappingsModel.data(treeView.currentIndex, 0x103); + if (!path) { + return; + } + Window.copyToClipboard(path); + } + function renameFile() { - var path = scriptsModel.data(treeView.currentIndex, 0x100); + var path = assetMappingsModel.data(treeView.currentIndex, 0x100); if (!path) { return; } @@ -120,6 +127,9 @@ Window { placeholderText: "Enter path here" }); object.selected.connect(function(destinationPath) { + if (path == destinationPath) { + return; + } if (fileExists(destinationPath)) { askForOverride(destinationPath, function() { doRenameFile(path, destinationPath); @@ -130,17 +140,20 @@ Window { }); } function deleteFile() { - var path = scriptsModel.data(treeView.currentIndex, 0x100); + var path = assetMappingsModel.data(treeView.currentIndex, 0x100); if (!path) { return; } + var isFolder = assetMappingsModel.data(treeView.currentIndex, 0x101); + var typeString = isFolder ? 'folder' : 'file'; + var object = desktop.messageBox({ icon: OriginalDialogs.StandardIcon.Question, buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No, defaultButton: OriginalDialogs.StandardButton.No, text: "Deleting", - informativeText: "You are about to delete the following file:\n" + + informativeText: "You are about to delete the following " + typeString + ":\n" + path + "\nDo you want to continue?" }); @@ -166,7 +179,7 @@ Window { var fileUrl = fileUrlTextField.text var addToWorld = addToWorldCheckBox.checked - var path = scriptsModel.data(treeView.currentIndex, 0x100); + var path = assetMappingsModel.data(treeView.currentIndex, 0x100); var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : ""; var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); @@ -211,6 +224,16 @@ Window { onClicked: root.reload() } + HifiControls.GlyphButton { + glyph: hifi.glyphs.reload + color: hifi.buttons.white + colorScheme: root.colorScheme + height: 26 + width: 26 + + onClicked: root.copyURLToClipboard() + } + HifiControls.Button { text: "ADD TO WORLD" color: hifi.buttons.white @@ -249,7 +272,7 @@ Window { HifiControls.Tree { id: treeView height: 400 - treeModel: scriptsModel + treeModel: assetMappingsModel colorScheme: root.colorScheme anchors.left: parent.left anchors.right: parent.right diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 4c9c0df1cb..0443c65453 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #include #include @@ -139,3 +140,8 @@ int WindowScriptingInterface::getX() { int WindowScriptingInterface::getY() { return qApp->getWindow()->y(); } + +void WindowScriptingInterface::copyToClipboard(const QString& text) { + qDebug() << "Copying"; + QApplication::clipboard()->setText(text); +} diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 609915bdc7..0f51a484c4 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -40,6 +40,7 @@ public slots: QScriptValue prompt(const QString& message = "", const QString& defaultText = ""); QScriptValue browse(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); QScriptValue save(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); + void copyToClipboard(const QString& text); signals: void domainChanged(const QString& domainHostname); diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index 3f2dd84721..c7c5929121 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -18,6 +18,13 @@ #include #include +AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() { + _proxyModel.setSourceModel(&_assetMappingModel); + _proxyModel.setSortRole(Qt::DisplayRole); + _proxyModel.setDynamicSortFilter(true); + _proxyModel.sort(0); +} + void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createSetMappingRequest(path, hash); @@ -152,6 +159,8 @@ void AssetMappingModel::refresh() { bool isFolder = i < length - 1; item->setData(isFolder ? fullPath + "/" : fullPath, Qt::UserRole); item->setData(isFolder, Qt::UserRole + 1); + item->setData(parts[i], Qt::UserRole + 2); + item->setData("atp:" + fullPath, Qt::UserRole + 3); if (lastItem) { lastItem->setChild(lastItem->rowCount(), 0, item); } else { diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.h b/libraries/script-engine/src/AssetMappingsScriptingInterface.h index 27d9ceff9f..2d62f2d6e5 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.h +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.h @@ -18,6 +18,7 @@ #include #include +#include class AssetMappingItem : public QStandardItem { public: @@ -39,6 +40,8 @@ Q_INVOKABLE void refresh(); + bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); }; + private: QHash _pathToItemMap; }; @@ -47,8 +50,14 @@ class AssetMappingsScriptingInterface : public QObject, public Dependency { Q_OBJECT Q_PROPERTY(AssetMappingModel* mappingModel READ getAssetMappingModel CONSTANT) + Q_PROPERTY(QAbstractProxyModel* proxyModel READ getProxyModel CONSTANT) public: + AssetMappingsScriptingInterface(); + Q_INVOKABLE AssetMappingModel* getAssetMappingModel() { return &_assetMappingModel; } + Q_INVOKABLE QAbstractProxyModel* getProxyModel() { return &_proxyModel; } + + Q_INVOKABLE bool isKnownMapping(QString path) const { return _assetMappingModel.isKnownMapping(path); }; Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback); Q_INVOKABLE void getMapping(QString path, QJSValue callback); @@ -59,6 +68,7 @@ public: protected: QSet _pendingRequests; AssetMappingModel _assetMappingModel; + QSortFilterProxyModel _proxyModel; }; From f1919031dece5f17d0759c7dbc51a26423541599 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 08:57:37 -0800 Subject: [PATCH 116/209] error message boxes for mapping errors --- interface/resources/qml/AssetServer.qml | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 3ff5bb98f1..43e5297477 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -48,7 +48,13 @@ Window { console.log("Deleting " + path); Assets.deleteMappings(path, function(err) { - print("Finished deleting path: ", path, err); + if (err) { + console.log("Error deleting path: ", path, err); + errorMessage("There was an error deleting:\n" + path + "\n\nPlease try again."); + } else { + console.log("Finished deleting path: ", path); + } + reload(); }); @@ -62,7 +68,13 @@ Window { console.log("Renaming " + oldPath + " to " + newPath); Assets.renameMapping(oldPath, newPath, function(err) { - print("Finished rename: ", err); + if (err) { + console.log("Error renaming: ", oldPath, "=>", newPath, " - error ", err); + errorMessage("There was an error renaming:\n" + oldPath + " to " + newPath + "\n\nPlease try again."); + } else { + console.log("Finished rename: ", oldPath, "=>", newPath); + } + reload(); }); } @@ -199,6 +211,15 @@ Window { }); } + function errorMessage(message) { + desktop.messageBox({ + icon: OriginalDialogs.StandardIcon.Error, + buttons: OriginalDialogs.StandardButton.Ok, + text: "Error", + informativeText: message + }); + } + Column { width: pane.contentWidth From 899595183e249b72ae7891ae6d7191fea6fa481a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 09:02:45 -0800 Subject: [PATCH 117/209] add reload of mappings on component complete --- interface/resources/qml/AssetServer.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 43e5297477..16dc5846ab 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -44,6 +44,8 @@ Window { property alias directory: root.currentDirectory } + Component.onCompleted: reload() + function doDeleteFile(path) { console.log("Deleting " + path); From b42bec78dc329060564e98d33fdd2738ef70a1ac Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 10 Mar 2016 10:25:20 -0800 Subject: [PATCH 118/209] Add Entities.addModelEntity --- libraries/entities/src/EntityScriptingInterface.cpp | 8 ++++++++ libraries/entities/src/EntityScriptingInterface.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 26f73eb65a..334295af16 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -178,6 +178,14 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties return id; } +QUuid EntityScriptingInterface::addModelEntity(const QString& modelUrl, const glm::vec3& position) { + EntityItemProperties properties; + properties.setType(EntityTypes::Model); + properties.setModelURL(modelUrl); + properties.setPosition(position); + return addEntity(properties); +} + EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity) { EntityPropertyFlags noSpecificProperties; return getEntityProperties(identity, noSpecificProperties); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 79d8f0a0b0..fda2aa7e59 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -84,6 +84,8 @@ public slots: /// adds a model with the specific properties Q_INVOKABLE QUuid addEntity(const EntityItemProperties& properties); + Q_INVOKABLE QUuid addModelEntity(const QString& modelUrl, const glm::vec3& position); + /// gets the current model properties for a specific model /// this function will not find return results in script engine contexts which don't have access to models Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid entityID); From 0df05d273d5accd6c5e9845f7ede86f14a89754b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 10 Mar 2016 10:25:51 -0800 Subject: [PATCH 119/209] Implement addToWorld in asset window --- interface/resources/qml/AssetServer.qml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 3ff5bb98f1..0ce9cbee40 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -101,10 +101,12 @@ Window { Assets.mappingModel.refresh(); } function addToWorld() { - var path = assetMappingsModel.data(treeView.currentIndex, 0x100); - if (!path) { + var url = assetMappingsModel.data(treeView.currentIndex, 0x102); + if (!url) { return; } + + Entities.addModelEntity(url, MyAvatar.position); } function copyURLToClipboard() { From 99718e9c4e5586bf8ac9f7a70b6db41bc463754b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 10:21:26 -0800 Subject: [PATCH 120/209] short circuit the mapping operations for invalid path/hash --- assignment-client/src/assets/AssetServer.cpp | 2 +- interface/resources/qml/AssetServer.qml | 28 +- libraries/networking/src/AssetClient.cpp | 30 +- libraries/networking/src/MappingRequest.cpp | 48 ++- libraries/networking/src/MappingRequest.h | 2 + .../src/AssetMappingsScriptingInterface.cpp | 278 ++++++++++-------- .../src/AssetMappingsScriptingInterface.h | 4 + .../src/AssetScriptingInterface.cpp | 4 +- 8 files changed, 250 insertions(+), 146 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 428920a44c..08cfa1252f 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -604,7 +604,7 @@ bool AssetServer::deleteMappings(const AssetPathList& paths) { } bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPath) { - if (oldPath[0] != '/' || newPath[0] != '/') { + if (!isValidPath(oldPath) || !isValidPath(newPath)) { qWarning() << "Cannot perform rename with invalid paths - both should have leading forward slashes:" << oldPath << "=>" << newPath; diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 0ffa0dca7a..dc4c925130 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -33,7 +33,8 @@ Window { HifiConstants { id: hifi } property var scripts: ScriptDiscoveryService; - property var assetMappingsModel: Assets.proxyModel; + property var assetProxyModel: Assets.proxyModel; + property var assetMappingsModel: Assets.mappingModel; property var currentDirectory; property alias currentFileUrl: fileUrlTextField.text; @@ -44,7 +45,10 @@ Window { property alias directory: root.currentDirectory } - Component.onCompleted: reload() + Component.onCompleted: { + assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError) + reload() + } function doDeleteFile(path) { console.log("Deleting " + path); @@ -103,7 +107,7 @@ Window { function canAddToWorld() { var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i]; - var path = assetMappingsModel.data(treeView.currentIndex, 0x100); + var path = assetProxyModel.data(treeView.currentIndex, 0x100); return supportedExtensions.reduce(function(total, current) { return total | new RegExp(current).test(path); @@ -114,6 +118,12 @@ Window { print("reload"); Assets.mappingModel.refresh(); } + + function handleGetMappingsError() { + errorMessage("There was a problem retreiving the list of assets from your Asset Server.\n" + + "Please make sure you are connected to the Asset Server and try again. "); + } + function addToWorld() { var url = assetMappingsModel.data(treeView.currentIndex, 0x102); if (!url) { @@ -124,7 +134,7 @@ Window { } function copyURLToClipboard() { - var path = assetMappingsModel.data(treeView.currentIndex, 0x103); + var path = assetProxyModel.data(treeView.currentIndex, 0x103); if (!path) { return; } @@ -132,7 +142,7 @@ Window { } function renameFile() { - var path = assetMappingsModel.data(treeView.currentIndex, 0x100); + var path = assetProxyModel.data(treeView.currentIndex, 0x100); if (!path) { return; } @@ -156,12 +166,12 @@ Window { }); } function deleteFile() { - var path = assetMappingsModel.data(treeView.currentIndex, 0x100); + var path = assetProxyModel.data(treeView.currentIndex, 0x100); if (!path) { return; } - var isFolder = assetMappingsModel.data(treeView.currentIndex, 0x101); + var isFolder = assetProxyModel.data(treeView.currentIndex, 0x101); var typeString = isFolder ? 'folder' : 'file'; var object = desktop.messageBox({ @@ -195,7 +205,7 @@ Window { var fileUrl = fileUrlTextField.text var addToWorld = addToWorldCheckBox.checked - var path = assetMappingsModel.data(treeView.currentIndex, 0x100); + var path = assetProxyModel.data(treeView.currentIndex, 0x100); var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : ""; var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); @@ -297,7 +307,7 @@ Window { HifiControls.Tree { id: treeView height: 400 - treeModel: assetMappingsModel + treeModel: assetProxyModel colorScheme: root.colorScheme anchors.left: parent.left anchors.right: parent.right diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 19b0be3917..79828cc235 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -138,6 +138,7 @@ bool haveAssetServer() { return true; } + GetMappingRequest* AssetClient::createGetMappingRequest(const AssetPath& path) { return new GetMappingRequest(path); } @@ -159,8 +160,8 @@ RenameMappingRequest* AssetClient::createRenameMappingRequest(const AssetPath& o } AssetRequest* AssetClient::createRequest(const AssetHash& hash) { - if (hash.length() != SHA256_HASH_HEX_LENGTH) { - qCWarning(asset_client) << "Invalid hash size"; + if (isValidHash(hash)) { + qCWarning(asset_client) << "Invalid hash"; return nullptr; } @@ -364,9 +365,10 @@ bool AssetClient::getAssetMapping(const AssetPath& path, MappingOperationCallbac _pendingMappingRequests[assetServer][messageID] = callback; return true; + } else { + callback(false, AssetServerError::NoError, QSharedPointer()); + return false; } - - return false; } bool AssetClient::getAllAssetMappings(MappingOperationCallback callback) { @@ -386,9 +388,10 @@ bool AssetClient::getAllAssetMappings(MappingOperationCallback callback) { _pendingMappingRequests[assetServer][messageID] = callback; return true; + } else { + callback(false, AssetServerError::NoError, QSharedPointer()); + return false; } - - return false; } bool AssetClient::deleteAssetMappings(const AssetPathList& paths, MappingOperationCallback callback) { @@ -414,9 +417,10 @@ bool AssetClient::deleteAssetMappings(const AssetPathList& paths, MappingOperati _pendingMappingRequests[assetServer][messageID] = callback; return true; + } else { + callback(false, AssetServerError::NoError, QSharedPointer()); + return false; } - - return false; } bool AssetClient::setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback) { @@ -439,9 +443,10 @@ bool AssetClient::setAssetMapping(const QString& path, const AssetHash& hash, Ma _pendingMappingRequests[assetServer][messageID] = callback; return true; + } else { + callback(false, AssetServerError::NoError, QSharedPointer()); + return false; } - - return false; } bool AssetClient::renameAssetMapping(const AssetPath& oldPath, const AssetPath& newPath, MappingOperationCallback callback) { @@ -465,9 +470,10 @@ bool AssetClient::renameAssetMapping(const AssetPath& oldPath, const AssetPath& return true; + } else { + callback(false, AssetServerError::NoError, QSharedPointer()); + return false; } - - return false; } bool AssetClient::uploadAsset(const QByteArray& data, UploadResultCallback callback) { diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp index afa20e551c..6f76d1103f 100644 --- a/libraries/networking/src/MappingRequest.cpp +++ b/libraries/networking/src/MappingRequest.cpp @@ -30,6 +30,13 @@ GetMappingRequest::GetMappingRequest(const AssetPath& path) : _path(path) { void GetMappingRequest::doStart() { + // short circuit the request if the path is invalid + if (!isValidPath(_path)) { + _error = MappingRequest::InvalidPath; + emit finished(this); + return; + } + auto assetClient = DependencyManager::get(); assetClient->getAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { @@ -89,11 +96,26 @@ void GetAllMappingsRequest::doStart() { }); }; -SetMappingRequest::SetMappingRequest(const AssetPath& path, const AssetHash& hash) : _path(path), _hash(hash) { +SetMappingRequest::SetMappingRequest(const AssetPath& path, const AssetHash& hash) : + _path(path), + _hash(hash) +{ + }; void SetMappingRequest::doStart() { + + // short circuit the request if the hash or path are invalid + auto validPath = isValidPath(_path); + auto validHash = isValidHash(_hash); + if (!validPath || !validHash) { + _error = validPath ? MappingRequest::InvalidPath : MappingRequest::InvalidHash; + emit finished(this); + return; + } + auto assetClient = DependencyManager::get(); + assetClient->setAssetMapping(_path, _hash, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { if (!responseReceived) { _error = NetworkError; @@ -119,7 +141,18 @@ DeleteMappingsRequest::DeleteMappingsRequest(const AssetPathList& paths) : _path }; void DeleteMappingsRequest::doStart() { + + // short circuit the request if any of the paths are invalid + for (auto& path : _paths) { + if (!isValidPath(path)) { + _error = MappingRequest::InvalidPath; + emit finished(this); + return; + } + } + auto assetClient = DependencyManager::get(); + assetClient->deleteAssetMappings(_paths, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { if (!responseReceived) { _error = NetworkError; @@ -142,14 +175,23 @@ void DeleteMappingsRequest::doStart() { }; RenameMappingRequest::RenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath) : -_oldPath(oldPath), -_newPath(newPath) + _oldPath(oldPath), + _newPath(newPath) { } void RenameMappingRequest::doStart() { + + // short circuit the request if either of the paths are invalid + if (!isValidPath(_oldPath) || !isValidPath(_newPath)) { + _error = InvalidPath; + emit finished(this); + return; + } + auto assetClient = DependencyManager::get(); + assetClient->renameAssetMapping(_oldPath, _newPath, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { diff --git a/libraries/networking/src/MappingRequest.h b/libraries/networking/src/MappingRequest.h index b9bd867712..c6a27e0274 100644 --- a/libraries/networking/src/MappingRequest.h +++ b/libraries/networking/src/MappingRequest.h @@ -26,6 +26,8 @@ public: NotFound, NetworkError, PermissionDenied, + InvalidPath, + InvalidHash, UnknownError }; diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index c7c5929121..fc21161f93 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -29,87 +29,117 @@ void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJS auto assetClient = DependencyManager::get(); auto request = assetClient->createSetMappingRequest(path, hash); - connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; + if (request) { + connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); + } else { + // not connected to an Asset Server, return network error + QJSValueList args { uint8_t(MappingRequest::NetworkError) }; callback.call(args); - - request->deleteLater(); - - }); - - request->start(); + } } void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createGetMappingRequest(path); - connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()), request->getHash() }; + if (request) { + connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()), request->getHash() }; + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); + } else { + // not connected to an Asset Server, return network error + QJSValueList args { uint8_t(MappingRequest::NetworkError) }; callback.call(args); - - request->deleteLater(); - - }); - - request->start(); + } } void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createDeleteMappingsRequest(paths); - connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; + if (request) { + connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); + } else { + // not connected to an Asset Server, return network error + QJSValueList args { uint8_t(MappingRequest::NetworkError) }; callback.call(args); - - request->deleteLater(); - - }); - - request->start(); + } } void AssetMappingsScriptingInterface::getAllMappings(QJSValue 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(); + if (request) { + 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); - } + for (auto& kv : mappings ) { + map.setProperty(kv.first, kv.second); + } - QJSValueList args { uint8_t(request->getError()), map }; + QJSValueList args { uint8_t(request->getError()), map }; + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); + } else { + // not connected to an Asset Server, return network error + QJSValueList args { uint8_t(MappingRequest::NetworkError) }; callback.call(args); - - request->deleteLater(); - - }); - - request->start(); + } } void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString newPath, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createRenameMappingRequest(oldPath, newPath); - connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; + if (request) { + connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; + + callback.call(args); + + request->deleteLater(); + + }); + request->start(); + } else { + // not connected to an Asset Server, return network error + QJSValueList args { uint8_t(MappingRequest::NetworkError) }; callback.call(args); - - request->deleteLater(); - - }); - - request->start(); + } } @@ -134,92 +164,102 @@ void AssetMappingModel::refresh() { auto assetClient = DependencyManager::get(); auto request = assetClient->createGetAllMappingsRequest(); - connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) mutable { - auto mappings = request->getMappings(); - auto existingPaths = _pathToItemMap.keys(); - for (auto& mapping : mappings) { - auto& path = mapping.first; - auto parts = path.split("/"); - auto length = parts.length(); + if (request) { + connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) mutable { + if (request->getError() == MappingRequest::NoError) { + auto mappings = request->getMappings(); + auto existingPaths = _pathToItemMap.keys(); + for (auto& mapping : mappings) { + auto& path = mapping.first; + auto parts = path.split("/"); + auto length = parts.length(); - existingPaths.removeOne(mapping.first); + existingPaths.removeOne(mapping.first); - QString fullPath = "/"; + QString fullPath = "/"; - QStandardItem* lastItem = nullptr; + QStandardItem* lastItem = nullptr; - // start index at 1 to avoid empty string from leading slash - for (int i = 1; i < length; ++i) { - fullPath += (i == 1 ? "" : "/") + parts[i]; + // start index at 1 to avoid empty string from leading slash + for (int i = 1; i < length; ++i) { + fullPath += (i == 1 ? "" : "/") + parts[i]; - auto it = _pathToItemMap.find(fullPath); - if (it == _pathToItemMap.end()) { - qDebug() << "prefix not found: " << fullPath; - auto item = new QStandardItem(parts[i]); - bool isFolder = i < length - 1; - item->setData(isFolder ? fullPath + "/" : fullPath, Qt::UserRole); - item->setData(isFolder, Qt::UserRole + 1); - item->setData(parts[i], Qt::UserRole + 2); - item->setData("atp:" + fullPath, Qt::UserRole + 3); - if (lastItem) { - lastItem->setChild(lastItem->rowCount(), 0, item); - } else { - appendRow(item); + auto it = _pathToItemMap.find(fullPath); + if (it == _pathToItemMap.end()) { + qDebug() << "prefix not found: " << fullPath; + auto item = new QStandardItem(parts[i]); + bool isFolder = i < length - 1; + item->setData(isFolder ? fullPath + "/" : fullPath, Qt::UserRole); + item->setData(isFolder, Qt::UserRole + 1); + item->setData(parts[i], Qt::UserRole + 2); + item->setData("atp:" + fullPath, Qt::UserRole + 3); + if (lastItem) { + lastItem->setChild(lastItem->rowCount(), 0, item); + } else { + appendRow(item); + } + + lastItem = item; + _pathToItemMap[fullPath] = lastItem; + } + else { + lastItem = it.value(); + } } - lastItem = item; - _pathToItemMap[fullPath] = lastItem; + Q_ASSERT(fullPath == path); } - else { - lastItem = it.value(); + + // Remove folders from list + auto it = existingPaths.begin(); + while (it != existingPaths.end()) { + auto item = _pathToItemMap[*it]; + if (item->data(Qt::UserRole + 1).toBool()) { + it = existingPaths.erase(it); + } else { + ++it; + } } - } - Q_ASSERT(fullPath == path); - } + for (auto& path : existingPaths) { + Q_ASSERT(_pathToItemMap.contains(path)); + qDebug() << "removing existing: " << path; - // Remove folders from list - auto it = existingPaths.begin(); - while (it != existingPaths.end()) { - auto item = _pathToItemMap[*it]; - if (item->data(Qt::UserRole + 1).toBool()) { - it = existingPaths.erase(it); + auto item = _pathToItemMap[path]; + + while (item) { + // During each iteration, delete item + QStandardItem* nextItem = nullptr; + + auto parent = item->parent(); + if (parent) { + parent->removeRow(item->row()); + if (parent->rowCount() > 0) { + // The parent still contains children, set the nextItem to null so we stop processing + nextItem = nullptr; + } else { + nextItem = parent; + } + } else { + removeRow(item->row()); + } + + _pathToItemMap.remove(path); + //delete item; + + item = nextItem; + } + //removeitem->index(); + } } else { - ++it; + emit errorGettingMappings(uint8_t(request->getError())); } - } + }); - for (auto& path : existingPaths) { - Q_ASSERT(_pathToItemMap.contains(path)); - qDebug() << "removing existing: " << path; - - auto item = _pathToItemMap[path]; - - while (item) { - // During each iteration, delete item - QStandardItem* nextItem = nullptr; - - auto parent = item->parent(); - if (parent) { - parent->removeRow(item->row()); - if (parent->rowCount() > 0) { - // The parent still contains children, set the nextItem to null so we stop processing - nextItem = nullptr; - } else { - nextItem = parent; - } - } else { - removeRow(item->row()); - } - - _pathToItemMap.remove(path); - //delete item; - - item = nextItem; - } - //removeitem->index(); - } - }); - - request->start(); + request->start(); + } else { + qDebug() << "NO CONNECTED ASSET SERVER"; + // not connected to an Asset Server, emit network error + emit errorGettingMappings(uint8_t(MappingRequest::NetworkError)); + } } diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.h b/libraries/script-engine/src/AssetMappingsScriptingInterface.h index 2d62f2d6e5..67c0856730 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.h +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.h @@ -42,6 +42,9 @@ bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); }; + signals: + void errorGettingMappings(uint8_t error); + private: QHash _pathToItemMap; }; @@ -65,6 +68,7 @@ public: Q_INVOKABLE void deleteMapping(QString path, QJSValue callback) { deleteMappings(QStringList(path), callback); } Q_INVOKABLE void getAllMappings(QJSValue callback); Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QJSValue callback); + protected: QSet _pendingRequests; AssetMappingModel _assetMappingModel; diff --git a/libraries/script-engine/src/AssetScriptingInterface.cpp b/libraries/script-engine/src/AssetScriptingInterface.cpp index fb315434fd..e6a482ad27 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetScriptingInterface.cpp @@ -34,7 +34,7 @@ void AssetScriptingInterface::uploadData(QString data, QScriptValue callback) { QObject::connect(upload, &AssetUpload::finished, this, [this, callback](AssetUpload* upload, const QString& hash) mutable { if (callback.isFunction()) { - QString url = "atp://" + hash; + QString url = "atp:" + hash; QScriptValueList args { url }; callback.call(_engine->currentContext()->thisObject(), args); } @@ -43,7 +43,7 @@ void AssetScriptingInterface::uploadData(QString data, QScriptValue callback) { } void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callback) { - const QString ATP_SCHEME { "atp://" }; + const QString ATP_SCHEME { "atp:" }; if (!urlString.startsWith(ATP_SCHEME)) { return; From fccad7dca447d4b585c339c7d2993d663a336f3b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 10:24:11 -0800 Subject: [PATCH 121/209] remove nullptr request checks in AssetMappingsScriptingInterface --- .../src/AssetMappingsScriptingInterface.cpp | 98 +++++++------------ 1 file changed, 37 insertions(+), 61 deletions(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index fc21161f93..bccb57153a 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -51,95 +51,71 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback auto assetClient = DependencyManager::get(); auto request = assetClient->createGetMappingRequest(path); - if (request) { - connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()), request->getHash() }; + connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()), request->getHash() }; - callback.call(args); - - request->deleteLater(); - - }); - - request->start(); - } else { - // not connected to an Asset Server, return network error - QJSValueList args { uint8_t(MappingRequest::NetworkError) }; callback.call(args); - } + + request->deleteLater(); + + }); + + request->start(); } void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createDeleteMappingsRequest(paths); - if (request) { - connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; + connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; - callback.call(args); - - request->deleteLater(); - - }); - - request->start(); - } else { - // not connected to an Asset Server, return network error - QJSValueList args { uint8_t(MappingRequest::NetworkError) }; callback.call(args); - } + + request->deleteLater(); + + }); + + request->start(); } void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createGetAllMappingsRequest(); - if (request) { - connect(request, &GetAllMappingsRequest::finished, this, [this, callback](GetAllMappingsRequest* request) mutable { - auto mappings = request->getMappings(); - auto map = callback.engine()->newObject(); + 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); - } + for (auto& kv : mappings ) { + map.setProperty(kv.first, kv.second); + } - QJSValueList args { uint8_t(request->getError()), map }; + QJSValueList args { uint8_t(request->getError()), map }; - callback.call(args); - - request->deleteLater(); - - }); - - request->start(); - } else { - // not connected to an Asset Server, return network error - QJSValueList args { uint8_t(MappingRequest::NetworkError) }; callback.call(args); - } + + request->deleteLater(); + + }); + + request->start(); } void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString newPath, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createRenameMappingRequest(oldPath, newPath); - if (request) { - connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; + connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; - callback.call(args); - - request->deleteLater(); - - }); - - request->start(); - } else { - // not connected to an Asset Server, return network error - QJSValueList args { uint8_t(MappingRequest::NetworkError) }; callback.call(args); - } + + request->deleteLater(); + + }); + + request->start(); } From 9d19bf85b1c4a38fb128b2e3f4f0ea5ef0f243cb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 10:40:20 -0800 Subject: [PATCH 122/209] add consistent error handling for asset request and upload --- interface/src/assets/ATPAssetMigrator.cpp | 30 +++---- interface/src/ui/AssetUploadDialogFactory.cpp | 20 ++--- libraries/networking/src/AssetClient.cpp | 86 ++++++++++--------- .../networking/src/AssetResourceRequest.cpp | 8 -- libraries/networking/src/AssetUpload.cpp | 2 +- .../src/AssetScriptingInterface.cpp | 8 -- 6 files changed, 63 insertions(+), 91 deletions(-) diff --git a/interface/src/assets/ATPAssetMigrator.cpp b/interface/src/assets/ATPAssetMigrator.cpp index 51b2ac558a..e9327924a9 100644 --- a/interface/src/assets/ATPAssetMigrator.cpp +++ b/interface/src/assets/ATPAssetMigrator.cpp @@ -143,25 +143,17 @@ void ATPAssetMigrator::migrateResource(ResourceRequest* request) { QFileInfo assetInfo { request->getUrl().fileName() }; auto upload = assetClient->createUpload(request->getData()); - - if (upload) { - // add this URL to our hash of AssetUpload to original URL - _originalURLs.insert(upload, request->getUrl()); - - qCDebug(asset_migrator) << "Starting upload of asset from" << request->getUrl(); - - // connect to the finished signal so we know when the AssetUpload is done - QObject::connect(upload, &AssetUpload::finished, this, &ATPAssetMigrator::assetUploadFinished); - - // start the upload now - upload->start(); - } else { - // show a QMessageBox to say that there is no local asset server - QString messageBoxText = QString("Could not upload \n\n%1\n\nbecause you are currently not connected" \ - " to a local asset-server.").arg(assetInfo.fileName()); - - QMessageBox::information(_dialogParent, "Failed to Upload", messageBoxText); - } + + // add this URL to our hash of AssetUpload to original URL + _originalURLs.insert(upload, request->getUrl()); + + qCDebug(asset_migrator) << "Starting upload of asset from" << request->getUrl(); + + // connect to the finished signal so we know when the AssetUpload is done + QObject::connect(upload, &AssetUpload::finished, this, &ATPAssetMigrator::assetUploadFinished); + + // start the upload now + upload->start(); } void ATPAssetMigrator::assetUploadFinished(AssetUpload *upload, const QString& hash) { diff --git a/interface/src/ui/AssetUploadDialogFactory.cpp b/interface/src/ui/AssetUploadDialogFactory.cpp index 46f07cb7df..7b2da4c83b 100644 --- a/interface/src/ui/AssetUploadDialogFactory.cpp +++ b/interface/src/ui/AssetUploadDialogFactory.cpp @@ -44,20 +44,12 @@ void AssetUploadDialogFactory::showDialog() { auto assetClient = DependencyManager::get(); auto upload = assetClient->createUpload(filename); - - if (upload) { - // connect to the finished signal so we know when the AssetUpload is done - QObject::connect(upload, &AssetUpload::finished, this, &AssetUploadDialogFactory::handleUploadFinished); - - // start the upload now - upload->start(); - } else { - // show a QMessageBox to say that there is no local asset server - QString messageBoxText = QString("Could not upload \n\n%1\n\nbecause you are currently not connected" \ - " to a local asset-server.").arg(QFileInfo(filename).fileName()); - - QMessageBox::information(_dialogParent, "Failed to Upload", messageBoxText); - } + + // connect to the finished signal so we know when the AssetUpload is done + QObject::connect(upload, &AssetUpload::finished, this, &AssetUploadDialogFactory::handleUploadFinished); + + // start the upload now + upload->start(); } } else { // we don't have permission to upload to asset server in this domain - show the permission denied error diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 79828cc235..8cb1f31090 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -144,62 +144,60 @@ GetMappingRequest* AssetClient::createGetMappingRequest(const AssetPath& path) { } GetAllMappingsRequest* AssetClient::createGetAllMappingsRequest() { - return new GetAllMappingsRequest(); + auto request = new GetAllMappingsRequest(); + + request->moveToThread(thread()); + + return request; } DeleteMappingsRequest* AssetClient::createDeleteMappingsRequest(const AssetPathList& paths) { - return new DeleteMappingsRequest(paths); + auto request = new DeleteMappingsRequest(paths); + + request->moveToThread(thread()); + + return request; } SetMappingRequest* AssetClient::createSetMappingRequest(const AssetPath& path, const AssetHash& hash) { - return new SetMappingRequest(path, hash); + auto request = new SetMappingRequest(path, hash); + + request->moveToThread(thread()); + + return request; } RenameMappingRequest* AssetClient::createRenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath) { - return new RenameMappingRequest(oldPath, newPath); + auto request = new RenameMappingRequest(oldPath, newPath); + + request->moveToThread(thread()); + + return request; } AssetRequest* AssetClient::createRequest(const AssetHash& hash) { - if (isValidHash(hash)) { - qCWarning(asset_client) << "Invalid hash"; - return nullptr; - } + auto request = new AssetRequest(hash); - if (haveAssetServer()) { - auto request = new AssetRequest(hash); - - // Move to the AssetClient thread in case we are not currently on that thread (which will usually be the case) - request->moveToThread(thread()); - - return request; - } else { - return nullptr; - } + // Move to the AssetClient thread in case we are not currently on that thread (which will usually be the case) + request->moveToThread(thread()); + + return request; } AssetUpload* AssetClient::createUpload(const QString& filename) { - - if (haveAssetServer()) { - auto upload = new AssetUpload(filename); - - upload->moveToThread(thread()); - - return upload; - } else { - return nullptr; - } + auto upload = new AssetUpload(filename); + + upload->moveToThread(thread()); + + return upload; } AssetUpload* AssetClient::createUpload(const QByteArray& data) { - if (haveAssetServer()) { - auto upload = new AssetUpload(data); - - upload->moveToThread(thread()); - - return upload; - } else { - return nullptr; - } + auto upload = new AssetUpload(data); + + upload->moveToThread(thread()); + + return upload; } bool AssetClient::getAsset(const QString& hash, DataOffset start, DataOffset end, @@ -233,9 +231,12 @@ bool AssetClient::getAsset(const QString& hash, DataOffset start, DataOffset end _pendingRequests[assetServer][messageID] = { callback, progressCallback }; return true; + } else { + callback(false, AssetServerError::NoError, QByteArray()); + return false; } - return false; + } bool AssetClient::getAssetInfo(const QString& hash, GetInfoCallback callback) { @@ -256,9 +257,10 @@ bool AssetClient::getAssetInfo(const QString& hash, GetInfoCallback callback) { _pendingInfoRequests[assetServer][messageID] = callback; return true; + } else { + callback(false, AssetServerError::NoError, { "", 0 }); + return false; } - - return false; } void AssetClient::handleAssetGetInfoReply(QSharedPointer message, SharedNodePointer senderNode) { @@ -495,8 +497,10 @@ bool AssetClient::uploadAsset(const QByteArray& data, UploadResultCallback callb _pendingUploads[assetServer][messageID] = callback; return true; + } else { + callback(false, AssetServerError::NoError, QString()); + return false; } - return false; } void AssetClient::handleAssetUploadReply(QSharedPointer message, SharedNodePointer senderNode) { diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 3cc7bdd4c7..a896f94c8c 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -122,14 +122,6 @@ void AssetResourceRequest::requestHash(const AssetHash& hash) { auto assetClient = DependencyManager::get(); _assetRequest = assetClient->createRequest(hash); - if (!_assetRequest) { - _result = ServerUnavailable; - _state = Finished; - - emit finished(); - return; - } - connect(_assetRequest, &AssetRequest::progress, this, &AssetResourceRequest::progress); connect(_assetRequest, &AssetRequest::finished, this, [this](AssetRequest* req) { Q_ASSERT(_state == InProgress); diff --git a/libraries/networking/src/AssetUpload.cpp b/libraries/networking/src/AssetUpload.cpp index 754d632cce..2840f6777c 100644 --- a/libraries/networking/src/AssetUpload.cpp +++ b/libraries/networking/src/AssetUpload.cpp @@ -41,7 +41,7 @@ QString AssetUpload::getErrorString() const { case AssetUpload::FileOpenError: return "The file could not be opened. Please check your permissions and try again."; case AssetUpload::NetworkError: - return "The file could not be opened. Please check your network connectivity."; + return "There was a problem reaching your Asset Server. Please check your network connectivity."; default: // not handled, do not show a message box return QString(); diff --git a/libraries/script-engine/src/AssetScriptingInterface.cpp b/libraries/script-engine/src/AssetScriptingInterface.cpp index e6a482ad27..aaa4f97fb3 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetScriptingInterface.cpp @@ -27,10 +27,6 @@ AssetScriptingInterface::AssetScriptingInterface(QScriptEngine* 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()) { @@ -61,10 +57,6 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb auto assetClient = DependencyManager::get(); auto assetRequest = assetClient->createRequest(hash); - if (!assetRequest) { - return; - } - _pendingRequests << assetRequest; connect(assetRequest, &AssetRequest::finished, this, [this, callback](AssetRequest* request) mutable { From 2bbeac6597f225f9d93bdaed9f1e103a67b87ea5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 10:42:45 -0800 Subject: [PATCH 123/209] short circuit asset request for invalid hash --- libraries/networking/src/AssetRequest.cpp | 9 +++++++++ libraries/networking/src/AssetRequest.h | 1 + libraries/networking/src/AssetResourceRequest.cpp | 12 +++--------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index f2e347e0f7..95812d5a52 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -35,6 +35,15 @@ void AssetRequest::start() { qCWarning(asset_client) << "AssetRequest already started."; return; } + + // in case we haven't parsed a valid hash, return an error now + if (isValidHash(_hash)) { + _result = InvalidHash; + _state = Finished; + + emit finished(this); + return; + } // Try to load from cache _data = loadFromCache(getUrl()); diff --git a/libraries/networking/src/AssetRequest.h b/libraries/networking/src/AssetRequest.h index ac4485a683..b98ac4ec4b 100644 --- a/libraries/networking/src/AssetRequest.h +++ b/libraries/networking/src/AssetRequest.h @@ -34,6 +34,7 @@ public: NoError, NotFound, InvalidByteRange, + InvalidHash, HashVerificationFailed, NetworkError, UnknownError diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index a896f94c8c..587eca6b0b 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -109,15 +109,6 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) { void AssetResourceRequest::requestHash(const AssetHash& hash) { - // in case we haven't parsed a valid hash, return an error now - if (hash.length() != SHA256_HASH_HEX_LENGTH) { - _result = InvalidURL; - _state = Finished; - - emit finished(); - return; - } - // Make request to atp auto assetClient = DependencyManager::get(); _assetRequest = assetClient->createRequest(hash); @@ -133,6 +124,9 @@ void AssetResourceRequest::requestHash(const AssetHash& hash) { _data = req->getData(); _result = Success; break; + case AssetRequest::InvalidHash: + _result = InvalidURL; + break; case AssetRequest::Error::NotFound: _result = NotFound; break; From 9c53f40fbe30e6ad72194d613dc49216d2ed8ee3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 10:45:43 -0800 Subject: [PATCH 124/209] remove nullptr check in AssetMappingsScriptingInterface --- libraries/networking/src/AssetRequest.cpp | 2 +- .../src/AssetMappingsScriptingInterface.cpp | 174 +++++++++--------- 2 files changed, 85 insertions(+), 91 deletions(-) diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 95812d5a52..93b1e4e698 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -38,7 +38,7 @@ void AssetRequest::start() { // in case we haven't parsed a valid hash, return an error now if (isValidHash(_hash)) { - _result = InvalidHash; + _error = InvalidHash; _state = Finished; emit finished(this); diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index bccb57153a..95ceb3ce90 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -140,102 +140,96 @@ void AssetMappingModel::refresh() { auto assetClient = DependencyManager::get(); auto request = assetClient->createGetAllMappingsRequest(); - if (request) { - connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) mutable { - if (request->getError() == MappingRequest::NoError) { - auto mappings = request->getMappings(); - auto existingPaths = _pathToItemMap.keys(); - for (auto& mapping : mappings) { - auto& path = mapping.first; - auto parts = path.split("/"); - auto length = parts.length(); + connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) mutable { + if (request->getError() == MappingRequest::NoError) { + auto mappings = request->getMappings(); + auto existingPaths = _pathToItemMap.keys(); + for (auto& mapping : mappings) { + auto& path = mapping.first; + auto parts = path.split("/"); + auto length = parts.length(); - existingPaths.removeOne(mapping.first); + existingPaths.removeOne(mapping.first); - QString fullPath = "/"; + QString fullPath = "/"; - QStandardItem* lastItem = nullptr; + QStandardItem* lastItem = nullptr; - // start index at 1 to avoid empty string from leading slash - for (int i = 1; i < length; ++i) { - fullPath += (i == 1 ? "" : "/") + parts[i]; + // start index at 1 to avoid empty string from leading slash + for (int i = 1; i < length; ++i) { + fullPath += (i == 1 ? "" : "/") + parts[i]; - auto it = _pathToItemMap.find(fullPath); - if (it == _pathToItemMap.end()) { - qDebug() << "prefix not found: " << fullPath; - auto item = new QStandardItem(parts[i]); - bool isFolder = i < length - 1; - item->setData(isFolder ? fullPath + "/" : fullPath, Qt::UserRole); - item->setData(isFolder, Qt::UserRole + 1); - item->setData(parts[i], Qt::UserRole + 2); - item->setData("atp:" + fullPath, Qt::UserRole + 3); - if (lastItem) { - lastItem->setChild(lastItem->rowCount(), 0, item); - } else { - appendRow(item); - } - - lastItem = item; - _pathToItemMap[fullPath] = lastItem; - } - else { - lastItem = it.value(); - } - } - - Q_ASSERT(fullPath == path); - } - - // Remove folders from list - auto it = existingPaths.begin(); - while (it != existingPaths.end()) { - auto item = _pathToItemMap[*it]; - if (item->data(Qt::UserRole + 1).toBool()) { - it = existingPaths.erase(it); - } else { - ++it; - } - } - - for (auto& path : existingPaths) { - Q_ASSERT(_pathToItemMap.contains(path)); - qDebug() << "removing existing: " << path; - - auto item = _pathToItemMap[path]; - - while (item) { - // During each iteration, delete item - QStandardItem* nextItem = nullptr; - - auto parent = item->parent(); - if (parent) { - parent->removeRow(item->row()); - if (parent->rowCount() > 0) { - // The parent still contains children, set the nextItem to null so we stop processing - nextItem = nullptr; - } else { - nextItem = parent; - } + auto it = _pathToItemMap.find(fullPath); + if (it == _pathToItemMap.end()) { + qDebug() << "prefix not found: " << fullPath; + auto item = new QStandardItem(parts[i]); + bool isFolder = i < length - 1; + item->setData(isFolder ? fullPath + "/" : fullPath, Qt::UserRole); + item->setData(isFolder, Qt::UserRole + 1); + item->setData(parts[i], Qt::UserRole + 2); + item->setData("atp:" + fullPath, Qt::UserRole + 3); + if (lastItem) { + lastItem->setChild(lastItem->rowCount(), 0, item); } else { - removeRow(item->row()); + appendRow(item); } - - _pathToItemMap.remove(path); - //delete item; - - item = nextItem; - } - //removeitem->index(); - } - } else { - emit errorGettingMappings(uint8_t(request->getError())); - } - }); - request->start(); - } else { - qDebug() << "NO CONNECTED ASSET SERVER"; - // not connected to an Asset Server, emit network error - emit errorGettingMappings(uint8_t(MappingRequest::NetworkError)); - } + lastItem = item; + _pathToItemMap[fullPath] = lastItem; + } + else { + lastItem = it.value(); + } + } + + Q_ASSERT(fullPath == path); + } + + // Remove folders from list + auto it = existingPaths.begin(); + while (it != existingPaths.end()) { + auto item = _pathToItemMap[*it]; + if (item->data(Qt::UserRole + 1).toBool()) { + it = existingPaths.erase(it); + } else { + ++it; + } + } + + for (auto& path : existingPaths) { + Q_ASSERT(_pathToItemMap.contains(path)); + qDebug() << "removing existing: " << path; + + auto item = _pathToItemMap[path]; + + while (item) { + // During each iteration, delete item + QStandardItem* nextItem = nullptr; + + auto parent = item->parent(); + if (parent) { + parent->removeRow(item->row()); + if (parent->rowCount() > 0) { + // The parent still contains children, set the nextItem to null so we stop processing + nextItem = nullptr; + } else { + nextItem = parent; + } + } else { + removeRow(item->row()); + } + + _pathToItemMap.remove(path); + //delete item; + + item = nextItem; + } + //removeitem->index(); + } + } else { + emit errorGettingMappings(uint8_t(request->getError())); + } + }); + + request->start(); } From 50a05df72162fa82087096edb2215a68551801af Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 11:58:55 -0800 Subject: [PATCH 125/209] fix asset loading with error changes --- assignment-client/src/assets/AssetServer.cpp | 2 +- libraries/networking/src/AssetRequest.cpp | 4 +-- .../networking/src/AssetResourceRequest.cpp | 36 ++++++++----------- 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 08cfa1252f..962e0fc583 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -482,7 +482,7 @@ void AssetServer::loadMappingsFromFile() { } } - qCritical() << "Failed to read mapping file at" << mapFilePath << "- assignment with not continue."; + qCritical() << "Failed to read mapping file at" << mapFilePath << "- assignment will not continue."; setFinished(true); } else { qInfo() << "No existing mappings loaded from file since no file was found at" << mapFilePath; diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 93b1e4e698..e40b8d2cbe 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -37,7 +37,7 @@ void AssetRequest::start() { } // in case we haven't parsed a valid hash, return an error now - if (isValidHash(_hash)) { + if (!isValidHash(_hash)) { _error = InvalidHash; _state = Finished; @@ -62,7 +62,7 @@ void AssetRequest::start() { auto assetClient = DependencyManager::get(); assetClient->getAssetInfo(_hash, [this](bool responseReceived, AssetServerError serverError, AssetInfo info) { _info = info; - + if (!responseReceived) { _error = NetworkError; } else if (serverError != AssetServerError::NoError) { diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 587eca6b0b..c9063d7eae 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -58,15 +58,6 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) { auto assetClient = DependencyManager::get(); _assetMappingRequest = assetClient->createGetMappingRequest(path); - // if we get a nullptr for createGetMappingRequest assume that there is no currently available asset-server - if (!_assetMappingRequest) { - _result = ServerUnavailable; - _state = Finished; - - emit finished(); - return; - } - // make sure we'll hear about the result of the get mapping request connect(_assetMappingRequest, &GetMappingRequest::finished, this, [this, path](GetMappingRequest* request){ Q_ASSERT(_state == InProgress); @@ -80,24 +71,27 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) { requestHash(request->getHash()); break; - case MappingRequest::NotFound: - // no result for the mapping request, set error to not found - _result = NotFound; + default: { + switch (request->getError()) { + case MappingRequest::NotFound: + // no result for the mapping request, set error to not found + _result = NotFound; + break; + case MappingRequest::NetworkError: + // didn't hear back from the server, mark it unavailable + _result = ServerUnavailable; + break; + default: + _result = Error; + break; + } // since we've failed we know we are finished _state = Finished; emit finished(); break; - default: - // these are unexpected errors for a GetMappingRequest object - _result = Error; - - // since we've failed we know we are finished - _state = Finished; - emit finished(); - - break; + } } _assetMappingRequest->deleteLater(); From e3cae5b026aa5292fb5cde4e77f2cc235786768b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 12:26:00 -0800 Subject: [PATCH 126/209] change setMapping for new disconnected error case --- .../src/AssetMappingsScriptingInterface.cpp | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index 95ceb3ce90..ee8deb4056 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -29,22 +29,16 @@ void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJS auto assetClient = DependencyManager::get(); auto request = assetClient->createSetMappingRequest(path, hash); - if (request) { - connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; + connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; - callback.call(args); - - request->deleteLater(); - - }); - - request->start(); - } else { - // not connected to an Asset Server, return network error - QJSValueList args { uint8_t(MappingRequest::NetworkError) }; callback.call(args); - } + + request->deleteLater(); + + }); + + request->start(); } void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback) { From 273acc6a7e3a7f8097b62a46b7ceaa389d681e16 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 10 Mar 2016 13:55:36 -0800 Subject: [PATCH 127/209] Add context menu to asset manager --- interface/resources/qml/AssetServer.qml | 71 ++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 0ce9cbee40..8db7d7b3dd 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -109,16 +109,22 @@ Window { Entities.addModelEntity(url, MyAvatar.position); } - function copyURLToClipboard() { - var path = assetMappingsModel.data(treeView.currentIndex, 0x103); + function copyURLToClipboard(index) { + if (!index) { + index = treeView.currentIndex; + } + var path = assetMappingsModel.data(index, 0x103); if (!path) { return; } Window.copyToClipboard(path); } - function renameFile() { - var path = assetMappingsModel.data(treeView.currentIndex, 0x100); + function renameFile(index) { + if (!index) { + index = treeView.currentIndex; + } + var path = assetMappingsModel.data(index, 0x100); if (!path) { return; } @@ -141,8 +147,11 @@ Window { } }); } - function deleteFile() { - var path = assetMappingsModel.data(treeView.currentIndex, 0x100); + function deleteFile(index) { + if (!index) { + index = treeView.currentIndex; + } + var path = assetMappingsModel.data(index, 0x100); if (!path) { return; } @@ -271,6 +280,34 @@ Window { } } + Menu { + id: contextMenu + title: "Edit" + property var url: "" + property var currentIndex: null + + MenuItem { + text: "Copy URL" + onTriggered: { + copyURLToClipboard(contextMenu.currentIndex); + } + } + + MenuItem { + text: "Rename" + onTriggered: { + renameFile(contextMenu.currentIndex); + } + } + + MenuItem { + text: "Delete" + onTriggered: { + deleteFile(contextMenu.currentIndex); + } + } + } + HifiControls.Tree { id: treeView height: 400 @@ -278,6 +315,28 @@ Window { colorScheme: root.colorScheme anchors.left: parent.left anchors.right: parent.right + onClicked: { + print('here'); + } + rowDelegate: Rectangle { + height: hifi.dimensions.tableRowHeight + color: styleData.selected + ? hifi.colors.primaryHighlight + : treeView.isLightColorScheme + ? (styleData.alternate ? hifi.colors.tableRowLightEven : hifi.colors.tableRowLightOdd) + : (styleData.alternate ? hifi.colors.tableRowDarkEven : hifi.colors.tableRowDarkOdd) + + } + MouseArea { + propagateComposedEvents: true + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: { + var index = treeView.indexAt(mouse.x, mouse.y); + contextMenu.currentIndex = index; + contextMenu.popup(); + } + } } } From 71bc937533e7320a53d1487e6f021265598ad0f2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 10 Mar 2016 13:56:54 -0800 Subject: [PATCH 128/209] Remove copy URL button --- interface/resources/qml/AssetServer.qml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 8db7d7b3dd..df3612050b 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -235,16 +235,6 @@ Window { onClicked: root.reload() } - HifiControls.GlyphButton { - glyph: hifi.glyphs.reload - color: hifi.buttons.white - colorScheme: root.colorScheme - height: 26 - width: 26 - - onClicked: root.copyURLToClipboard() - } - HifiControls.Button { text: "ADD TO WORLD" color: hifi.buttons.white From ef8c66c1be201a959a54e5ff96e1d4fe5825f418 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 10 Mar 2016 14:18:09 -0800 Subject: [PATCH 129/209] Remove commented out code --- interface/resources/qml/AssetServer.qml | 3 --- 1 file changed, 3 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index df3612050b..d5a6a8b440 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -305,9 +305,6 @@ Window { colorScheme: root.colorScheme anchors.left: parent.left anchors.right: parent.right - onClicked: { - print('here'); - } rowDelegate: Rectangle { height: hifi.dimensions.tableRowHeight color: styleData.selected From c93ba2752b9f693fb408db525cb24567026de526 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 10 Mar 2016 14:44:53 -0800 Subject: [PATCH 130/209] Remove rowDelegate styling for asset window --- interface/resources/qml/AssetServer.qml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 5f2eb6272a..c69af702fb 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -338,15 +338,6 @@ Window { colorScheme: root.colorScheme anchors.left: parent.left anchors.right: parent.right - rowDelegate: Rectangle { - height: hifi.dimensions.tableRowHeight - color: styleData.selected - ? hifi.colors.primaryHighlight - : treeView.isLightColorScheme - ? (styleData.alternate ? hifi.colors.tableRowLightEven : hifi.colors.tableRowLightOdd) - : (styleData.alternate ? hifi.colors.tableRowDarkEven : hifi.colors.tableRowDarkOdd) - - } MouseArea { propagateComposedEvents: true anchors.fill: parent From 8cc0ae3148881697c8e37a9764129533b271b1a5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 13:16:02 -0800 Subject: [PATCH 131/209] menu and naming changes for asset server directory --- interface/resources/qml/AssetServer.qml | 2 +- interface/src/Menu.cpp | 11 ++++++----- interface/src/Menu.h | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index c69af702fb..2f79eae931 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -21,7 +21,7 @@ import "dialogs" Window { id: root objectName: "AssetServer" - title: "Asset Server" + title: "My Asset Server" resizable: true destroyOnInvisible: true x: 40; y: 40 diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 58617bcb7c..abb1b4e143 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -95,10 +95,6 @@ Menu::Menu() { addActionToQMenuAndActionHash(editMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J, qApp, SLOT(toggleRunningScriptsWidget())); - // Edit > Asset Server - addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, 0, - qApp, SLOT(toggleAssetServerWidget())); - // Edit > Open and Run Script from File... [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, qApp, SLOT(loadDialog()), @@ -131,10 +127,15 @@ Menu::Menu() { SLOT(toggleConsole()), QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + editMenu->addSeparator(); + + // Edit > My Asset Server + addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, 0, qApp, SLOT(toggleAssetServerWidget())); + // Edit > Reload All Content [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()), QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - + // Edit > Package Model... [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::PackageModel, 0, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 9ed7a605dc..93394828ec 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -34,7 +34,7 @@ namespace MenuOption { const QString AnimDebugDrawDefaultPose = "Debug Draw Default Pose"; const QString AnimDebugDrawPosition= "Debug Draw Position"; const QString AssetMigration = "ATP Asset Migration"; - const QString AssetServer = "Asset Server"; + const QString AssetServer = "My Asset Server"; const QString Attachments = "Attachments..."; const QString AudioNetworkStats = "Audio Network Stats"; const QString AudioNoiseReduction = "Audio Noise Reduction"; From 1678c9be20436bcd372f6b76388b214d7c208e30 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 13:24:11 -0800 Subject: [PATCH 132/209] add a keyboard shortcut for the asset directory --- interface/src/Menu.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index abb1b4e143..0724e75ea1 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -130,7 +130,8 @@ Menu::Menu() { editMenu->addSeparator(); // Edit > My Asset Server - addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, 0, qApp, SLOT(toggleAssetServerWidget())); + addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, Qt::CTRL | Qt::SHIFT | Qt::Key_A, + qApp, SLOT(toggleAssetServerWidget())); // Edit > Reload All Content [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()), From c65b5b63f0e50f31f353411cec9a544eec5317a3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 14:20:16 -0800 Subject: [PATCH 133/209] better error handling for asset browser --- interface/resources/qml/AssetServer.qml | 30 +++++++------- .../src/AssetMappingsScriptingInterface.cpp | 39 +++++++++++++------ .../src/AssetMappingsScriptingInterface.h | 9 ++--- 3 files changed, 48 insertions(+), 30 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 2f79eae931..e74699f367 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -56,12 +56,13 @@ Window { Assets.deleteMappings(path, function(err) { if (err) { console.log("Error deleting path: ", path, err); - errorMessage("There was an error deleting:\n" + path + "\n\nPlease try again."); + + box = errorMessageBox("There was an error deleting:\n" + path + "\n" + Assets.getErrorString(err)); + box.selected.connect(reload); } else { console.log("Finished deleting path: ", path); + reload(); } - - reload(); }); } @@ -76,7 +77,8 @@ Window { Assets.renameMapping(oldPath, newPath, function(err) { if (err) { console.log("Error renaming: ", oldPath, "=>", newPath, " - error ", err); - errorMessage("There was an error renaming:\n" + oldPath + " to " + newPath + "\n\nPlease try again."); + box = errorMessageBox("There was an error renaming:\n" + oldPath + " to " + newPath + "\n" + Assets.getErrorString(err)); + box.selected.connect(reload); } else { console.log("Finished rename: ", oldPath, "=>", newPath); } @@ -119,9 +121,11 @@ Window { Assets.mappingModel.refresh(); } - function handleGetMappingsError() { - errorMessage("There was a problem retreiving the list of assets from your Asset Server.\n" - + "Please make sure you are connected to the Asset Server and try again. "); + function handleGetMappingsError(errorCode) { + errorMessageBox( + "There was a problem retreiving the list of assets from your Asset Server.\n" + + Assets.getErrorString(errorCode) + ); } function addToWorld() { @@ -234,12 +238,12 @@ Window { }); } - function errorMessage(message) { - desktop.messageBox({ - icon: OriginalDialogs.StandardIcon.Error, - buttons: OriginalDialogs.StandardButton.Ok, - text: "Error", - informativeText: message + function errorMessageBox(message) { + return desktop.messageBox({ + icon: hifi.icons.warning, + defaultButton: OriginalDialogs.StandardButton.Ok, + title: "Error", + text: message }); } diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index ee8deb4056..e40e47b944 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -25,6 +25,27 @@ AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() { _proxyModel.sort(0); } +QString AssetMappingsScriptingInterface::getErrorString(int errorCode) const { + switch (errorCode) { + case MappingRequest::NoError: + return "No error"; + case MappingRequest::NotFound: + return "Asset not found"; + case MappingRequest::NetworkError: + return "Unable to communicate with Asset Server"; + case MappingRequest::PermissionDenied: + return "Permission denied"; + case MappingRequest::InvalidPath: + return "Path is invalid"; + case MappingRequest::InvalidHash: + return "Hash is invalid"; + case MappingRequest::UnknownError: + return "Asset Server internal error"; + default: + return QString(); + } +} + void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createSetMappingRequest(path, hash); @@ -113,22 +134,16 @@ void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString new } -AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder) - : name(name), +AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder) : + name(name), fullPath(fullPath), - isFolder(isFolder) { + isFolder(isFolder) +{ } static int assetMappingModelMetatypeId = qRegisterMetaType("AssetMappingModel*"); -AssetMappingModel::AssetMappingModel() { -} - -AssetMappingModel::~AssetMappingModel() { - qDebug() << " DEST"; -} - void AssetMappingModel::refresh() { qDebug() << "Refreshing asset mapping model"; auto assetClient = DependencyManager::get(); @@ -221,7 +236,9 @@ void AssetMappingModel::refresh() { //removeitem->index(); } } else { - emit errorGettingMappings(uint8_t(request->getError())); + qDebug() << "THE ERROR IS" << request->getError(); + qDebug() << "Casted error is" << static_cast(request->getError()); + emit errorGettingMappings(static_cast(request->getError())); } }); diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.h b/libraries/script-engine/src/AssetMappingsScriptingInterface.h index 67c0856730..3458da949a 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.h +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.h @@ -33,17 +33,12 @@ class AssetMappingModel : public QStandardItemModel { Q_OBJECT public: - AssetMappingModel(); - ~AssetMappingModel(); - -// QVariant AssetMappingModel::data(const QModelIndex& index, int role) const; - Q_INVOKABLE void refresh(); bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); }; signals: - void errorGettingMappings(uint8_t error); + void errorGettingMappings(int error); private: QHash _pathToItemMap; @@ -62,6 +57,8 @@ public: Q_INVOKABLE bool isKnownMapping(QString path) const { return _assetMappingModel.isKnownMapping(path); }; + Q_INVOKABLE QString getErrorString(int errorCode) const; + Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback); Q_INVOKABLE void getMapping(QString path, QJSValue callback); Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); From e93bc8317f039eb907512c9705cb67072303625a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 14:22:50 -0800 Subject: [PATCH 134/209] remove an extra space --- assignment-client/src/assets/AssetServer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 962e0fc583..38f4c66f4b 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -464,7 +464,6 @@ void AssetServer::loadMappingsFromFile() { shouldDrop = true; } - if (!isValidHash(it.value().toString())) { qWarning() << "Will not keep mapping for" << it.key() << "since it does not have a valid hash."; shouldDrop = true; From d077ade350087b64f67a1c0df07102bf8b15a9c5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 14:26:45 -0800 Subject: [PATCH 135/209] fix path regex to handle leading double slash --- libraries/networking/src/AssetUtils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 52ed7336c2..ac3d819ae2 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -31,7 +31,7 @@ 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 -const QString ASSET_PATH_REGEX_STRING = "^\\/(?:[^\\/]|\\/(?!\\/))*$"; +const QString ASSET_PATH_REGEX_STRING = "^\\/(?!\\/)(?:[^\\/]|\\/(?!\\/))*$"; const QString ASSET_HASH_REGEX_STRING = QString("^[a-fA-F0-9]{%1}$").arg(SHA256_HASH_HEX_LENGTH); enum AssetServerError : uint8_t { From 5167cf69b277ec8a425fa3ab1ca1e885a504b8d7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 14:41:35 -0800 Subject: [PATCH 136/209] fix for add to world and delete dialog --- interface/resources/qml/AssetServer.qml | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index e74699f367..97646de79f 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -129,7 +129,7 @@ Window { } function addToWorld() { - var url = assetMappingsModel.data(treeView.currentIndex, 0x102); + var url = assetProxyModel.data(treeView.currentIndex, 0x103); if (!url) { return; } @@ -137,15 +137,16 @@ Window { Entities.addModelEntity(url, MyAvatar.position); } - function copyURLToClipboard(index) { + function copyURLToClipboard() { if (!index) { index = treeView.currentIndex; } - var path = assetProxyModel.data(index, 0x103); - if (!path) { + + var url = assetProxyModel.data(treeView.currentIndex, 0x103); + if (!url) { return; } - Window.copyToClipboard(path); + Window.copyToClipboard(url); } function renameFile(index) { @@ -188,13 +189,11 @@ Window { var typeString = isFolder ? 'folder' : 'file'; var object = desktop.messageBox({ - icon: OriginalDialogs.StandardIcon.Question, - buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No, - defaultButton: OriginalDialogs.StandardButton.No, - text: "Deleting", - informativeText: "You are about to delete the following " + typeString + ":\n" + - path + - "\nDo you want to continue?" + icon: hifi.icons.question, + buttons: OriginalDialogs.StandardButton.Yes + OriginalDialogs.StandardButton.No, + defaultButton: OriginalDialogs.StandardButton.Yes, + title: "Delete", + text: "You are about to delete the following " + typeString + ":\n" + path + "\nDo you want to continue?" }); object.selected.connect(function(button) { if (button === OriginalDialogs.StandardButton.Yes) { From e227f68353675b2b9f7a6bb27c02d8e0aef9b6b8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 14:42:24 -0800 Subject: [PATCH 137/209] tweak wording for overwrite dialog --- interface/resources/qml/AssetServer.qml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 97646de79f..ade6563622 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -93,12 +93,11 @@ Window { function askForOverride(path, callback) { var object = desktop.messageBox({ - icon: OriginalDialogs.StandardIcon.Question, + icon: hifi.icons.question, buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No, - defaultButton: OriginalDialogs.StandardButton.No, - text: "Override?", - informativeText: "The following file already exists:\n" + path + - "\nDo you want to override it?" + defaultButton: OriginalDialogs.StandardButton.Yes, + title: "Overwrite File", + text: path + "\n" + "This file already exists. Do you want to overwrite it?" }); object.selected.connect(function(button) { if (button === OriginalDialogs.StandardButton.Yes) { From 7f0917ea00f66d5f1d9727df65ebba7ca7973a51 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 14:47:24 -0800 Subject: [PATCH 138/209] add to world in front of MyAvatar --- interface/resources/qml/AssetServer.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index ade6563622..32e0a3b8ee 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -132,8 +132,8 @@ Window { if (!url) { return; } - - Entities.addModelEntity(url, MyAvatar.position); + var addPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(MyAvatar.orientation))); + Entities.addModelEntity(url, addPosition); } function copyURLToClipboard() { From b3d8b67893ed3696ed4ea88ef7e84ef962248644 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 14:50:21 -0800 Subject: [PATCH 139/209] remove committed debug lines --- libraries/script-engine/src/AssetMappingsScriptingInterface.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index e40e47b944..a843094df3 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -236,8 +236,6 @@ void AssetMappingModel::refresh() { //removeitem->index(); } } else { - qDebug() << "THE ERROR IS" << request->getError(); - qDebug() << "Casted error is" << static_cast(request->getError()); emit errorGettingMappings(static_cast(request->getError())); } }); From dc79d3262a979f268753fbb861377880e22bc1ba Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 9 Mar 2016 15:50:33 -0800 Subject: [PATCH 140/209] Update glyphs font --- .../qml/styles-uit/HifiConstants.qml | 131 +++++++++++++----- 1 file changed, 100 insertions(+), 31 deletions(-) diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 32cf61117b..09cba6d462 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -35,7 +35,7 @@ Item { glyph = hifi.glyphs.alert; break; case hifi.icons.critical: - glyph = hifi.glyphs.critical; + glyph = hifi.glyphs.error; break; case hifi.icons.placemark: glyph = hifi.glyphs.placemark; @@ -159,36 +159,6 @@ Item { readonly property real disclosureButton: dimensions.largeScreen ? 20 : 15 } - Item { - id: glyphs - readonly property string alert: "+" - readonly property string backward: "E" - readonly property string caratDn: "5" - readonly property string caratR: "3" - readonly property string caratUp: "6" - readonly property string close: "w" - readonly property string closeInverted: "x" - readonly property string closeSmall: "C" - readonly property string critical: "=" - readonly property string disclosureButtonCollapse: "M" - readonly property string disclosureButtonExpand: "L" - readonly property string disclosureCollapse: "Z" - readonly property string disclosureExpand: "B" - readonly property string forward: "D" - readonly property string info: "[" - readonly property string noIcon: "" - readonly property string pin: "y" - readonly property string pinInverted: "z" - readonly property string placemark: "U" - readonly property string question: "]" - readonly property string reloadSmall: "a" - readonly property string resizeHandle: "A" - readonly property string upload: "j" - readonly property string reload: "a" - readonly property string back: "1" - - } - Item { id: icons // Values per OffscreenUi::Icon @@ -221,4 +191,103 @@ Item { id: effects readonly property int fadeInDuration: 300 } + Item { + id: glyphs + readonly property string noIcon: "" + readonly property string hmd: "b" + readonly property string screen: "c" + readonly property string keyboard: "d" + readonly property string handControllers: "e" + readonly property string headphonesMic: "f" + readonly property string gamepad: "g" + readonly property string headphones: "h" + readonly property string mic: "i" + readonly property string upload: "j" + readonly property string script: "k" + readonly property string text: "l" + readonly property string cube: "m" + readonly property string sphere: "n" + readonly property string zone: "o" + readonly property string light: "p" + readonly property string web: "q" + readonly property string web2: "r" + readonly property string edit: "s" + readonly property string market: "t" + readonly property string directory: "u" + readonly property string menu: "v" + readonly property string close: "w" + readonly property string closeInverted: "x" + readonly property string pin: "y" + readonly property string pinInverted: "z" + readonly property string resizeHandle: "A" + readonly property string disclosureExpand: "B" + readonly property string reloadSmall: "a" + readonly property string closeSmall: "C" + readonly property string forward: "D" + readonly property string backward: "E" + readonly property string reload: "F" + readonly property string unmuted: "G" + readonly property string muted: "H" + readonly property string minimize: "I" + readonly property string maximize: "J" + readonly property string maximizeInverted: "K" + readonly property string disclosureButtonExpand: "L" + readonly property string disclosureButtonCollapse: "M" + readonly property string scriptStop: "N" + readonly property string scriptReload: "O" + readonly property string scriptRun: "P" + readonly property string scriptNew: "Q" + readonly property string hifiForum: "2" + readonly property string hifiLogoSmall: "S" + readonly property string avatar1: "T" + readonly property string placemark: "U" + readonly property string box: "V" + readonly property string community: "0" + readonly property string grabHandle: "X" + readonly property string search: "Y" + readonly property string disclosureCollapse: "Z" + readonly property string scriptUpload: "R" + readonly property string code: "W" + readonly property string avatar: "<" + readonly property string arrowsH: ":" + readonly property string arrowsV: ";" + readonly property string arrows: "`" + readonly property string compress: "!" + readonly property string expand: "\"" + readonly property string placemark1: "#" + readonly property string circle: "$" + readonly property string handPointer: "9" + readonly property string plusSquareO: "%" + readonly property string sliders: "&" + readonly property string square: "'" + readonly property string alignCenter: "8" + readonly property string alignJustify: ")" + readonly property string alignLeft: "*" + readonly property string alignRight: "^" + readonly property string bars: "7" + readonly property string circleSlash: "," + readonly property string sync: "()" + readonly property string key: "-" + readonly property string link: "." + readonly property string location: "/" + readonly property string caratR: "3" + readonly property string caratL: "4" + readonly property string caratDn: "5" + readonly property string caratUp: "6" + readonly property string folderLg: ">" + readonly property string folderSm: "?" + readonly property string levelUp: "1" + readonly property string info: "[" + readonly property string question: "]" + readonly property string alert: "+" + readonly property string home: "_" + readonly property string error: "=" + readonly property string settings: "@" + readonly property string trash: "{" + readonly property string objectGroup: "" + readonly property string cm: "}" + readonly property string msvg79: "~" + readonly property string deg: "\\" + readonly property string px: "|" + } } From 7d7a683b18ae9f623b8b379e2076f6ccfdcdaeb6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 10 Mar 2016 13:33:36 -0800 Subject: [PATCH 141/209] Add uploadFile method that prompts the user --- interface/resources/qml/AssetServer.qml | 18 ++-- .../resources/qml/dialogs/QueryDialog.qml | 4 +- interface/src/Application.cpp | 2 +- .../AssetMappingsScriptingInterface.cpp | 84 ++++++++++++++----- .../AssetMappingsScriptingInterface.h | 1 + libraries/networking/src/MappingRequest.h | 1 + 6 files changed, 74 insertions(+), 36 deletions(-) rename {libraries/script-engine/src => interface/src/scripting}/AssetMappingsScriptingInterface.cpp (76%) rename {libraries/script-engine/src => interface/src/scripting}/AssetMappingsScriptingInterface.h (96%) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 32e0a3b8ee..eacbd15ec5 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -159,7 +159,7 @@ Window { var object = desktop.inputDialog({ label: "Enter new path:", - prefilledText: path, + current: path, placeholderText: "Enter path here" }); object.selected.connect(function(destinationPath) { @@ -220,18 +220,12 @@ Window { var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : ""; var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); - var object = desktop.inputDialog({ - label: "Enter asset path:", - prefilledText: directory + filename, - placeholderText: "Enter path here" - }); - object.selected.connect(function(destinationPath) { - if (fileExists(destinationPath)) { - askForOverride(fileUrl, function() { - doUploadFile(fileUrl, destinationPath, addToWorld); - }); + Assets.uploadFile(fileUrl, directory + filename, function(err) { + if (err) { + console.log("Error uploading: ", fileUrl, " - error ", err); + errorMessage("There was an error uploading:\n" + fileUrl + "\n\nPlease try again."); } else { - doUploadFile(fileUrl, destinationPath, addToWorld); + console.log("Finished uploading: ", fileUrl); } }); } diff --git a/interface/resources/qml/dialogs/QueryDialog.qml b/interface/resources/qml/dialogs/QueryDialog.qml index 754851030c..48df9a41ce 100644 --- a/interface/resources/qml/dialogs/QueryDialog.qml +++ b/interface/resources/qml/dialogs/QueryDialog.qml @@ -34,12 +34,10 @@ ModalWindow { property var items; property string label property var result; - // FIXME not current honored - property var current; + property alias current: textResult.text // For text boxes property alias placeholderText: textResult.placeholderText - property alias prefilledText: textResult.text // For combo boxes property bool editable: true; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2660acfa00..e8b2384bbf 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -66,7 +66,6 @@ #include #include #include -#include #include #include #include @@ -142,6 +141,7 @@ #include "ModelPackager.h" #include "PluginContainerProxy.h" #include "scripting/AccountScriptingInterface.h" +#include "scripting/AssetMappingsScriptingInterface.h" #include "scripting/AudioDeviceScriptingInterface.h" #include "scripting/ClipboardScriptingInterface.h" #include "scripting/DesktopScriptingInterface.h" diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp similarity index 76% rename from libraries/script-engine/src/AssetMappingsScriptingInterface.cpp rename to interface/src/scripting/AssetMappingsScriptingInterface.cpp index a843094df3..b4f9458551 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -12,11 +12,13 @@ #include "AssetMappingsScriptingInterface.h" #include +#include #include #include #include #include +#include AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() { _proxyModel.setSourceModel(&_assetMappingModel); @@ -51,12 +53,12 @@ void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJS auto request = assetClient->createSetMappingRequest(path, hash); connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; - - callback.call(args); + if (callback.isCallable()) { + QJSValueList args { uint8_t(request->getError()) }; + callback.call(args); + } request->deleteLater(); - }); request->start(); @@ -67,28 +69,70 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback auto request = assetClient->createGetMappingRequest(path); connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()), request->getHash() }; - - callback.call(args); + if (callback.isCallable()) { + QJSValueList args { uint8_t(request->getError()) }; + callback.call(args); + } request->deleteLater(); - }); request->start(); } +void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue callback) { + QFile file(path); + if (!file.open(QFile::ReadOnly)) { + qCWarning(asset_client) << "Error uploading file to asset server:\n" + << "Could not open" << qPrintable(path); + OffscreenUi::warning("File Error", "Could not open file: " + path, QMessageBox::Ok); + return; + } + + auto offscreenUi = DependencyManager::get(); + auto result = offscreenUi->inputDialog(OffscreenUi::ICON_NONE, "Enter asset path:", "", mapping); + if (!result.isValid()) { + return; + } + + // Check for override + if (isKnownMapping(result.toString())) { + auto message = "The following file already exists:\n" + path + "\nDo you want to override it?"; + auto button = offscreenUi->messageBox(OffscreenUi::ICON_QUESTION, "", message, + QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + if (button == QMessageBox::No) { + return; + } + } + + auto upload = DependencyManager::get()->createUpload(file.readAll()); + QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { + if (upload->getError() != AssetUpload::NoError) { + if (callback.isCallable()) { + QJSValueList args { uint8_t(upload->getError()) }; + callback.call(args); + } + } else { + setMapping(mapping, hash, callback); + } + + upload->deleteLater(); + }); + + upload->start(); +} + void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createDeleteMappingsRequest(paths); connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; - - callback.call(args); + if (callback.isCallable()) { + QJSValueList args { uint8_t(request->getError()) }; + callback.call(args); + } request->deleteLater(); - }); request->start(); @@ -106,12 +150,12 @@ void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { map.setProperty(kv.first, kv.second); } - QJSValueList args { uint8_t(request->getError()), map }; - - callback.call(args); + if (callback.isCallable()) { + QJSValueList args { uint8_t(request->getError()) }; + callback.call(args); + } request->deleteLater(); - }); request->start(); @@ -122,12 +166,12 @@ void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString new auto request = assetClient->createRenameMappingRequest(oldPath, newPath); connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; - - callback.call(args); + if (callback.isCallable()) { + QJSValueList args { uint8_t(request->getError()) }; + callback.call(args); + } request->deleteLater(); - }); request->start(); diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h similarity index 96% rename from libraries/script-engine/src/AssetMappingsScriptingInterface.h rename to interface/src/scripting/AssetMappingsScriptingInterface.h index 3458da949a..f1198ef17d 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -61,6 +61,7 @@ public: Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback); Q_INVOKABLE void getMapping(QString path, QJSValue callback); + Q_INVOKABLE void uploadFile(QString path, QString mapping, QJSValue callback = QJSValue()); Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); Q_INVOKABLE void deleteMapping(QString path, QJSValue callback) { deleteMappings(QStringList(path), callback); } Q_INVOKABLE void getAllMappings(QJSValue callback); diff --git a/libraries/networking/src/MappingRequest.h b/libraries/networking/src/MappingRequest.h index c6a27e0274..504a0cb2fa 100644 --- a/libraries/networking/src/MappingRequest.h +++ b/libraries/networking/src/MappingRequest.h @@ -64,6 +64,7 @@ class SetMappingRequest : public MappingRequest { public: SetMappingRequest(const AssetPath& path, const AssetHash& hash); + AssetPath getPath() const { return _path; } AssetHash getHash() const { return _hash; } signals: From 548d826a4e58d6a95db92de16febec17a226706c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 10 Mar 2016 14:04:52 -0800 Subject: [PATCH 142/209] Couple bug fixes --- interface/resources/qml/AssetServer.qml | 4 +++- interface/src/Application.cpp | 3 +-- .../scripting/AssetMappingsScriptingInterface.cpp | 15 ++++----------- .../scripting/AssetMappingsScriptingInterface.h | 2 +- libraries/networking/src/MappingRequest.cpp | 2 +- 5 files changed, 10 insertions(+), 16 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index eacbd15ec5..1220f288f7 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -217,7 +217,7 @@ Window { var addToWorld = addToWorldCheckBox.checked var path = assetProxyModel.data(treeView.currentIndex, 0x100); - var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : ""; + var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/"; var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); Assets.uploadFile(fileUrl, directory + filename, function(err) { @@ -227,6 +227,8 @@ Window { } else { console.log("Finished uploading: ", fileUrl); } + + reload(); }); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e8b2384bbf..a8e64513ee 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -426,7 +426,6 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(); DependencyManager::set(); DependencyManager::set(true, qApp, qApp); DependencyManager::set(); @@ -1296,7 +1295,7 @@ void Application::initializeUi() { rootContext->setContextProperty("Quat", new Quat()); rootContext->setContextProperty("Vec3", new Vec3()); rootContext->setContextProperty("Uuid", new ScriptUUID()); - rootContext->setContextProperty("Assets", DependencyManager::get().data()); + rootContext->setContextProperty("Assets", new AssetMappingsScriptingInterface()); rootContext->setContextProperty("AvatarList", DependencyManager::get().data()); diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index b4f9458551..ea763210c9 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -81,22 +81,15 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback } void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue callback) { - QFile file(path); - if (!file.open(QFile::ReadOnly)) { - qCWarning(asset_client) << "Error uploading file to asset server:\n" - << "Could not open" << qPrintable(path); - OffscreenUi::warning("File Error", "Could not open file: " + path, QMessageBox::Ok); - return; - } - auto offscreenUi = DependencyManager::get(); auto result = offscreenUi->inputDialog(OffscreenUi::ICON_NONE, "Enter asset path:", "", mapping); if (!result.isValid()) { return; } + mapping = result.toString(); // Check for override - if (isKnownMapping(result.toString())) { + if (isKnownMapping(mapping)) { auto message = "The following file already exists:\n" + path + "\nDo you want to override it?"; auto button = offscreenUi->messageBox(OffscreenUi::ICON_QUESTION, "", message, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); @@ -105,7 +98,7 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, } } - auto upload = DependencyManager::get()->createUpload(file.readAll()); + auto upload = DependencyManager::get()->createUpload(path); QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { if (upload->getError() != AssetUpload::NoError) { if (callback.isCallable()) { @@ -242,7 +235,7 @@ void AssetMappingModel::refresh() { auto it = existingPaths.begin(); while (it != existingPaths.end()) { auto item = _pathToItemMap[*it]; - if (item->data(Qt::UserRole + 1).toBool()) { + if (item && item->data(Qt::UserRole + 1).toBool()) { it = existingPaths.erase(it); } else { ++it; diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index f1198ef17d..2ad7da7c94 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -45,7 +45,7 @@ }; -class AssetMappingsScriptingInterface : public QObject, public Dependency { +class AssetMappingsScriptingInterface : public QObject { Q_OBJECT Q_PROPERTY(AssetMappingModel* mappingModel READ getAssetMappingModel CONSTANT) Q_PROPERTY(QAbstractProxyModel* proxyModel READ getProxyModel CONSTANT) diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp index 6f76d1103f..2cc28c03be 100644 --- a/libraries/networking/src/MappingRequest.cpp +++ b/libraries/networking/src/MappingRequest.cpp @@ -109,7 +109,7 @@ void SetMappingRequest::doStart() { auto validPath = isValidPath(_path); auto validHash = isValidHash(_hash); if (!validPath || !validHash) { - _error = validPath ? MappingRequest::InvalidPath : MappingRequest::InvalidHash; + _error = !validPath ? MappingRequest::InvalidPath : MappingRequest::InvalidHash; emit finished(this); return; } From 63571a7c36d424dffa0157e67b3da2ea23d81787 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 10 Mar 2016 14:57:02 -0800 Subject: [PATCH 143/209] Make sure Upload is not clicked several times --- interface/resources/qml/AssetServer.qml | 7 +++++++ .../src/scripting/AssetMappingsScriptingInterface.cpp | 1 + 2 files changed, 8 insertions(+) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 1220f288f7..0490db2fa7 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -212,7 +212,13 @@ Window { }); } + property var uploadOpen: false; function uploadClicked() { + if(uploadOpen) { + return; + } + uploadOpen = true; + var fileUrl = fileUrlTextField.text var addToWorld = addToWorldCheckBox.checked @@ -230,6 +236,7 @@ Window { reload(); }); + uploadOpen = false; } function errorMessageBox(message) { diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index ea763210c9..9934b7937c 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -83,6 +83,7 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue callback) { auto offscreenUi = DependencyManager::get(); auto result = offscreenUi->inputDialog(OffscreenUi::ICON_NONE, "Enter asset path:", "", mapping); + if (!result.isValid()) { return; } From cf12a8d3963439e83437b0c4dda4401836cd5013 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 15:02:19 -0800 Subject: [PATCH 144/209] always center the text in the message dialog --- interface/resources/qml/dialogs/MessageDialog.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/resources/qml/dialogs/MessageDialog.qml b/interface/resources/qml/dialogs/MessageDialog.qml index fa702090d3..4a25c51012 100644 --- a/interface/resources/qml/dialogs/MessageDialog.qml +++ b/interface/resources/qml/dialogs/MessageDialog.qml @@ -96,6 +96,7 @@ ModalWindow { } lineHeight: 2 lineHeightMode: Text.ProportionalHeight + horizontalAlignment: Text.AlignHCenter } RalewaySemiBold { From a6ccfb1685e75f77f6dfa3f39699cf44c83c6517 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 10 Mar 2016 15:03:25 -0800 Subject: [PATCH 145/209] CR --- interface/resources/qml/AssetServer.qml | 2 +- .../src/scripting/AssetMappingsScriptingInterface.cpp | 4 ++-- .../src/scripting/AssetMappingsScriptingInterface.h | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 0490db2fa7..c4855b7704 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -214,7 +214,7 @@ Window { property var uploadOpen: false; function uploadClicked() { - if(uploadOpen) { + if (uploadOpen) { return; } uploadOpen = true; diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 9934b7937c..2839a0a9f6 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -91,8 +91,8 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, // Check for override if (isKnownMapping(mapping)) { - auto message = "The following file already exists:\n" + path + "\nDo you want to override it?"; - auto button = offscreenUi->messageBox(OffscreenUi::ICON_QUESTION, "", message, + auto message = path + "\n" + "This file already exists. Do you want to overwrite it?"; + auto button = offscreenUi->messageBox(OffscreenUi::ICON_QUESTION, "Overwrite File", message, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (button == QMessageBox::No) { return; diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index 2ad7da7c94..3a7711b340 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -59,13 +59,13 @@ public: Q_INVOKABLE QString getErrorString(int errorCode) const; - Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback); - Q_INVOKABLE void getMapping(QString path, QJSValue callback); + Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback = QJSValue()); + Q_INVOKABLE void getMapping(QString path, QJSValue callback = QJSValue()); Q_INVOKABLE void uploadFile(QString path, QString mapping, QJSValue callback = QJSValue()); Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); - Q_INVOKABLE void deleteMapping(QString path, QJSValue callback) { deleteMappings(QStringList(path), callback); } - Q_INVOKABLE void getAllMappings(QJSValue callback); - Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QJSValue callback); + Q_INVOKABLE void deleteMapping(QString path, QJSValue callback) { deleteMappings(QStringList(path), callback = QJSValue()); } + Q_INVOKABLE void getAllMappings(QJSValue callback = QJSValue()); + Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QJSValue callback = QJSValue()); protected: QSet _pendingRequests; From e29565a71701fba1521bf3775eef315e6f8d723d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 15:15:18 -0800 Subject: [PATCH 146/209] don't default to yes when prompted for overwrite --- interface/resources/qml/AssetServer.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index c4855b7704..bcb236e7a1 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -91,11 +91,11 @@ Window { return Assets.isKnownMapping(path); } - function askForOverride(path, callback) { + function askForOverwrite(path, callback) { var object = desktop.messageBox({ icon: hifi.icons.question, buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No, - defaultButton: OriginalDialogs.StandardButton.Yes, + defaultButton: OriginalDialogs.StandardButton.No, title: "Overwrite File", text: path + "\n" + "This file already exists. Do you want to overwrite it?" }); @@ -167,7 +167,7 @@ Window { return; } if (fileExists(destinationPath)) { - askForOverride(destinationPath, function() { + askForOverwrite(destinationPath, function() { doRenameFile(path, destinationPath); }); } else { @@ -229,7 +229,7 @@ Window { Assets.uploadFile(fileUrl, directory + filename, function(err) { if (err) { console.log("Error uploading: ", fileUrl, " - error ", err); - errorMessage("There was an error uploading:\n" + fileUrl + "\n\nPlease try again."); + errorMessage("There was an error uploading:\n" + fileUrl + "\n" + Assets.getErrorString(err)); } else { console.log("Finished uploading: ", fileUrl); } From 76152906bea3c76281d63cf6cbb774a5f9d635b2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 10 Mar 2016 15:37:38 -0800 Subject: [PATCH 147/209] Fix crash bug in asset manager --- .../src/AssetMappingsScriptingInterface.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index ee8deb4056..77cc435fb8 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -155,13 +155,13 @@ void AssetMappingModel::refresh() { auto it = _pathToItemMap.find(fullPath); if (it == _pathToItemMap.end()) { - qDebug() << "prefix not found: " << fullPath; auto item = new QStandardItem(parts[i]); bool isFolder = i < length - 1; item->setData(isFolder ? fullPath + "/" : fullPath, Qt::UserRole); item->setData(isFolder, Qt::UserRole + 1); item->setData(parts[i], Qt::UserRole + 2); item->setData("atp:" + fullPath, Qt::UserRole + 3); + item->setData(fullPath, Qt::UserRole + 4); if (lastItem) { lastItem->setChild(lastItem->rowCount(), 0, item); } else { @@ -182,6 +182,7 @@ void AssetMappingModel::refresh() { // Remove folders from list auto it = existingPaths.begin(); while (it != existingPaths.end()) { + Q_ASSERT(_pathToItemMap.contains(*it)); auto item = _pathToItemMap[*it]; if (item->data(Qt::UserRole + 1).toBool()) { it = existingPaths.erase(it); @@ -192,7 +193,6 @@ void AssetMappingModel::refresh() { for (auto& path : existingPaths) { Q_ASSERT(_pathToItemMap.contains(path)); - qDebug() << "removing existing: " << path; auto item = _pathToItemMap[path]; @@ -200,6 +200,7 @@ void AssetMappingModel::refresh() { // During each iteration, delete item QStandardItem* nextItem = nullptr; + auto fullPath = item->data(Qt::UserRole + 4).toString(); auto parent = item->parent(); if (parent) { parent->removeRow(item->row()); @@ -210,15 +211,15 @@ void AssetMappingModel::refresh() { nextItem = parent; } } else { - removeRow(item->row()); + auto removed = removeRow(item->row()); + Q_ASSERT(removed); } - _pathToItemMap.remove(path); - //delete item; + Q_ASSERT(_pathToItemMap.contains(fullPath)); + _pathToItemMap.remove(fullPath); item = nextItem; } - //removeitem->index(); } } else { emit errorGettingMappings(uint8_t(request->getError())); From 76ed16314a4f6b302def5b42d7f270ea37557e2c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 10 Mar 2016 15:38:20 -0800 Subject: [PATCH 148/209] Add prepended slash on rename if missing --- interface/resources/qml/AssetServer.qml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index c69af702fb..8819d1100c 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -73,6 +73,10 @@ Window { function doRenameFile(oldPath, newPath) { console.log("Renaming " + oldPath + " to " + newPath); + if (newPath[0] != "/") { + newPath = "/" + newPath; + } + Assets.renameMapping(oldPath, newPath, function(err) { if (err) { console.log("Error renaming: ", oldPath, "=>", newPath, " - error ", err); From ad0fb18d81dad2323d0a2b411132d581baf0ee0c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 10 Mar 2016 16:02:41 -0800 Subject: [PATCH 149/209] Add / to beginning of mapping on upload if missing --- interface/src/scripting/AssetMappingsScriptingInterface.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 11a14c7686..6ac60ccbdf 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -88,6 +88,9 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, return; } mapping = result.toString(); + if (mapping[0] != '/') { + mapping = "/" + mapping; + } // Check for override if (isKnownMapping(mapping)) { From 35f5ebb93829885694e78de20677256a85d38d60 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 10 Mar 2016 15:50:02 -0800 Subject: [PATCH 150/209] Don't allow folder overwrite --- interface/resources/qml/AssetServer.qml | 8 ++++++-- .../scripting/AssetMappingsScriptingInterface.cpp | 13 +++++++++++++ .../src/scripting/AssetMappingsScriptingInterface.h | 6 ++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index afb4b50773..768eaa28a2 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -72,12 +72,16 @@ Window { } function doRenameFile(oldPath, newPath) { - console.log("Renaming " + oldPath + " to " + newPath); - if (newPath[0] != "/") { newPath = "/" + newPath; } + if (Assets.isKnownFolder(newPath)) { + box = errorMessageBox("Cannot override existing directory."); + box.selected.connect(reload); + } + + console.log("Renaming " + oldPath + " to " + newPath); Assets.renameMapping(oldPath, newPath, function(err) { if (err) { console.log("Error renaming: ", oldPath, "=>", newPath, " - error ", err); diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 6ac60ccbdf..ae2ef3183a 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -174,6 +174,19 @@ void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString new request->start(); } +bool AssetMappingModel::isKnownFolder(QString path) const { + if (!path.endsWith("/")) { + return false; + } + + auto existingPaths = _pathToItemMap.keys(); + for (auto& entry : existingPaths) { + if (entry.startsWith(path)) { + return true; + } + } + return false; +} AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder) : name(name), diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index 3a7711b340..99ced25d29 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -35,7 +35,8 @@ public: Q_INVOKABLE void refresh(); - bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); }; + bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); } + bool isKnownFolder(QString path) const; signals: void errorGettingMappings(int error); @@ -55,7 +56,8 @@ public: Q_INVOKABLE AssetMappingModel* getAssetMappingModel() { return &_assetMappingModel; } Q_INVOKABLE QAbstractProxyModel* getProxyModel() { return &_proxyModel; } - Q_INVOKABLE bool isKnownMapping(QString path) const { return _assetMappingModel.isKnownMapping(path); }; + Q_INVOKABLE bool isKnownMapping(QString path) const { return _assetMappingModel.isKnownMapping(path); } + Q_INVOKABLE bool isKnownFolder(QString path) const { return _assetMappingModel.isKnownFolder(path); } Q_INVOKABLE QString getErrorString(int errorCode) const; From 16287b70407f87cf55d8b588cc435e5f43fe7a31 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 10 Mar 2016 16:42:26 -0800 Subject: [PATCH 151/209] Disable add to world for uncompatible files --- interface/resources/qml/AssetServer.qml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 768eaa28a2..4cb69bb3ef 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -114,9 +114,8 @@ Window { }); } - function canAddToWorld() { + function canAddToWorld(path) { var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i]; - var path = assetProxyModel.data(treeView.currentIndex, 0x100); return supportedExtensions.reduce(function(total, current) { return total | new RegExp(current).test(path); @@ -137,7 +136,7 @@ Window { function addToWorld() { var url = assetProxyModel.data(treeView.currentIndex, 0x103); - if (!url) { + if (!url || !canAddToWorld(url)) { return; } var addPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(MyAvatar.orientation))); @@ -288,7 +287,7 @@ Window { height: 26 width: 120 - enabled: canAddToWorld() + enabled: canAddToWorld(assetProxyModel.data(treeView.currentIndex, 0x100)) onClicked: root.addToWorld() } @@ -408,6 +407,9 @@ Window { anchors.rightMargin: uploadButton.width + hifi.dimensions.contentSpacing.x text: "Add to world on upload" + + enabled: canAddToWorld(fileUrlTextField.text) + checked: false } From 4a9d88d213c74b7f3b5465b852848a4b8536cd66 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 10 Mar 2016 16:46:35 -0800 Subject: [PATCH 152/209] CR --- interface/resources/qml/AssetServer.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 4cb69bb3ef..a178374fed 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -77,7 +77,7 @@ Window { } if (Assets.isKnownFolder(newPath)) { - box = errorMessageBox("Cannot override existing directory."); + box = errorMessageBox("Cannot overwrite existing directory."); box.selected.connect(reload); } @@ -408,7 +408,7 @@ Window { text: "Add to world on upload" - enabled: canAddToWorld(fileUrlTextField.text) + opacity: canAddToWorld(fileUrlTextField.text) ? 1 : 0 checked: false } From 96a112290ffedd9a5ae9d0ba49f70c70be41e269 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 15:49:18 -0800 Subject: [PATCH 153/209] use mapping for overwrite prompt --- interface/src/scripting/AssetMappingsScriptingInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index ae2ef3183a..9d873409e0 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -94,7 +94,7 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, // Check for override if (isKnownMapping(mapping)) { - auto message = path + "\n" + "This file already exists. Do you want to overwrite it?"; + auto message = mapping + "\n" + "This file already exists. Do you want to overwrite it?"; auto button = offscreenUi->messageBox(OffscreenUi::ICON_QUESTION, "Overwrite File", message, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (button == QMessageBox::No) { From ed4df72eed57f430c9707d630430b487f5a86904 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 15:50:09 -0800 Subject: [PATCH 154/209] cleanup logging for asset browser --- interface/resources/qml/AssetServer.qml | 46 +++++++++++++++---------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index a178374fed..9d4db830e2 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -55,23 +55,20 @@ Window { Assets.deleteMappings(path, function(err) { if (err) { - console.log("Error deleting path: ", path, err); + console.log("Asset browser - error deleting path: ", path, err); box = errorMessageBox("There was an error deleting:\n" + path + "\n" + Assets.getErrorString(err)); box.selected.connect(reload); } else { - console.log("Finished deleting path: ", path); + console.log("Asset browser - finished deleting path: ", path); reload(); } }); } - function doUploadFile(path, mapping, addToWorld) { - console.log("Uploading " + path + " to " + mapping + " (addToWorld: " + addToWorld + ")"); - - } function doRenameFile(oldPath, newPath) { + if (newPath[0] != "/") { newPath = "/" + newPath; } @@ -81,14 +78,15 @@ Window { box.selected.connect(reload); } - console.log("Renaming " + oldPath + " to " + newPath); + console.log("Asset browser - renaming " + oldPath + " to " + newPath); + Assets.renameMapping(oldPath, newPath, function(err) { if (err) { - console.log("Error renaming: ", oldPath, "=>", newPath, " - error ", err); + console.log("Asset browser - error renaming: ", oldPath, "=>", newPath, " - error ", err); box = errorMessageBox("There was an error renaming:\n" + oldPath + " to " + newPath + "\n" + Assets.getErrorString(err)); box.selected.connect(reload); } else { - console.log("Finished rename: ", oldPath, "=>", newPath); + console.log("Asset browser - finished rename: ", oldPath, "=>", newPath); } reload(); @@ -123,7 +121,6 @@ Window { } function reload() { - print("reload"); Assets.mappingModel.refresh(); } @@ -134,16 +131,22 @@ Window { ); } - function addToWorld() { - var url = assetProxyModel.data(treeView.currentIndex, 0x103); + function addToWorld(url) { + if (!url) { + url = assetProxyModel.data(treeView.currentIndex, 0x103); + } + if (!url || !canAddToWorld(url)) { return; } + + console.log("Asset browser - adding asset " + url + " to world."); + var addPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(MyAvatar.orientation))); Entities.addModelEntity(url, addPosition); } - function copyURLToClipboard() { + function copyURLToClipboard(index) { if (!index) { index = treeView.currentIndex; } @@ -227,7 +230,7 @@ Window { uploadOpen = true; var fileUrl = fileUrlTextField.text - var addToWorld = addToWorldCheckBox.checked + var shouldAddToWorld = addToWorldCheckBox.checked var path = assetProxyModel.data(treeView.currentIndex, 0x100); var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/"; @@ -235,13 +238,18 @@ Window { Assets.uploadFile(fileUrl, directory + filename, function(err) { if (err) { - console.log("Error uploading: ", fileUrl, " - error ", err); - errorMessage("There was an error uploading:\n" + fileUrl + "\n" + Assets.getErrorString(err)); + console.log("Asset Browser - error uploading: ", fileUrl, " - error ", err); + var box = errorMessage("There was an error uploading:\n" + fileUrl + "\n" + Assets.getErrorString(err)); + box.selected.connect(reload); } else { - console.log("Finished uploading: ", fileUrl); - } + console.log("Asset Browser - finished uploading: ", fileUrl); - reload(); + if (shouldAddToWorld) { + addToWorld("atp:" + directory + filename); + } + + reload(); + } }); uploadOpen = false; } From 979fda7c8b49a14d55aacca78ca2fa78d3950305 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 15:53:05 -0800 Subject: [PATCH 155/209] add trimming for upload mapping --- interface/src/scripting/AssetMappingsScriptingInterface.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 9d873409e0..603fd4dadd 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -88,6 +88,8 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, return; } mapping = result.toString(); + mapping = mapping.trimmed(); + if (mapping[0] != '/') { mapping = "/" + mapping; } From 52ee2499fc429ff832308edd969dd22af12aa7ca Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 15:56:45 -0800 Subject: [PATCH 156/209] add trim prior to rename in AssetServer --- interface/resources/qml/AssetServer.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 9d4db830e2..a4421ac371 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -173,6 +173,8 @@ Window { placeholderText: "Enter path here" }); object.selected.connect(function(destinationPath) { + destinationPath = destinationPath.trim(); + if (path == destinationPath) { return; } From e94e2ece2e0dd954b51fb2b426de747c9e5267cd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 16:00:29 -0800 Subject: [PATCH 157/209] add trimming to paths on asset server --- assignment-client/src/assets/AssetServer.cpp | 12 +++++++++--- assignment-client/src/assets/AssetServer.h | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 38f4c66f4b..8598a33715 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -509,7 +509,8 @@ bool AssetServer::writeMappingsToFile() { return false; } -bool AssetServer::setMapping(const AssetPath& path, const AssetHash& hash) { +bool AssetServer::setMapping(AssetPath path, AssetHash hash) { + path = path.trimmed(); if (!isValidPath(path)) { qWarning() << "Cannot set a mapping for invalid path:" << path << "=>" << hash; @@ -555,7 +556,9 @@ bool AssetServer::deleteMappings(const AssetPathList& paths) { auto oldMappings = _fileMappings; // enumerate the paths to delete and remove them all - for (auto& path : paths) { + for (auto path : paths) { + + path = path.trimmed(); // figure out if this path will delete a file or folder if (pathIsFolder(path)) { @@ -602,7 +605,10 @@ bool AssetServer::deleteMappings(const AssetPathList& paths) { } } -bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPath) { +bool AssetServer::renameMapping(AssetPath oldPath, AssetPath newPath) { + oldPath = oldPath.trimmed(); + newPath = newPath.trimmed(); + if (!isValidPath(oldPath) || !isValidPath(newPath)) { qWarning() << "Cannot perform rename with invalid paths - both should have leading forward slashes:" << oldPath << "=>" << newPath; diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 094ea58d41..2e4321e4cd 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -52,13 +52,13 @@ private: bool writeMappingsToFile(); /// Set the mapping for path to hash - bool setMapping(const AssetPath& path, const AssetHash& hash); + bool setMapping(AssetPath path, 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); + bool renameMapping(AssetPath oldPath, AssetPath newPath); void performMappingMigration(); From 6ae5ed6588f336c27c1818080e492e006a0aa965 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 16:04:10 -0800 Subject: [PATCH 158/209] add trimming to MappingRequest ctors --- libraries/networking/src/MappingRequest.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp index 2cc28c03be..7b675050a1 100644 --- a/libraries/networking/src/MappingRequest.cpp +++ b/libraries/networking/src/MappingRequest.cpp @@ -25,7 +25,7 @@ void MappingRequest::start() { doStart(); }; -GetMappingRequest::GetMappingRequest(const AssetPath& path) : _path(path) { +GetMappingRequest::GetMappingRequest(const AssetPath& path) : _path(path.trimmed()) { }; void GetMappingRequest::doStart() { @@ -97,7 +97,7 @@ void GetAllMappingsRequest::doStart() { }; SetMappingRequest::SetMappingRequest(const AssetPath& path, const AssetHash& hash) : - _path(path), + _path(path.trimmed()), _hash(hash) { @@ -138,6 +138,9 @@ void SetMappingRequest::doStart() { }; DeleteMappingsRequest::DeleteMappingsRequest(const AssetPathList& paths) : _paths(paths) { + for (auto& path : _paths) { + path = path.trimmed(); + } }; void DeleteMappingsRequest::doStart() { @@ -175,8 +178,8 @@ void DeleteMappingsRequest::doStart() { }; RenameMappingRequest::RenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath) : - _oldPath(oldPath), - _newPath(newPath) + _oldPath(oldPath.trimmed()), + _newPath(newPath.trimmed()) { } From 6f550292f4b9efd9dfe866627eb6bf2489b5f0d9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 16:06:04 -0800 Subject: [PATCH 159/209] pass delete paths by reference for trimming --- assignment-client/src/assets/AssetServer.cpp | 4 ++-- assignment-client/src/assets/AssetServer.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 8598a33715..ff7d869a0b 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -551,12 +551,12 @@ bool pathIsFolder(const AssetPath& path) { return path.endsWith('/'); } -bool AssetServer::deleteMappings(const AssetPathList& paths) { +bool AssetServer::deleteMappings(AssetPathList& paths) { // take a copy of the current mappings in case persistence of these deletes fails auto oldMappings = _fileMappings; // enumerate the paths to delete and remove them all - for (auto path : paths) { + for (auto& path : paths) { path = path.trimmed(); diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 2e4321e4cd..1a8ebed50b 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -55,7 +55,7 @@ private: bool setMapping(AssetPath path, AssetHash hash); /// Delete mapping `path`. Returns `true` if deletion of mappings succeeds, else `false`. - bool deleteMappings(const AssetPathList& paths); + bool deleteMappings(AssetPathList& paths); /// Rename mapping from `oldPath` to `newPath`. Returns true if successful bool renameMapping(AssetPath oldPath, AssetPath newPath); From 625032f748bea7402abe80f70a6b32be6265dc9a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 17:10:49 -0800 Subject: [PATCH 160/209] fix for add to world after upload name change --- interface/resources/qml/AssetServer.qml | 4 ++-- interface/src/scripting/AssetMappingsScriptingInterface.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index a4421ac371..a3fe6cacb8 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -238,7 +238,7 @@ Window { var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/"; var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); - Assets.uploadFile(fileUrl, directory + filename, function(err) { + Assets.uploadFile(fileUrl, directory + filename, function(err, path) { if (err) { console.log("Asset Browser - error uploading: ", fileUrl, " - error ", err); var box = errorMessage("There was an error uploading:\n" + fileUrl + "\n" + Assets.getErrorString(err)); @@ -247,7 +247,7 @@ Window { console.log("Asset Browser - finished uploading: ", fileUrl); if (shouldAddToWorld) { - addToWorld("atp:" + directory + filename); + addToWorld("atp:" + path); } reload(); diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 603fd4dadd..32b697459c 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -54,7 +54,7 @@ void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJS connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { if (callback.isCallable()) { - QJSValueList args { uint8_t(request->getError()) }; + QJSValueList args { uint8_t(request->getError()), request->getPath() }; callback.call(args); } @@ -150,7 +150,7 @@ void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { } if (callback.isCallable()) { - QJSValueList args { uint8_t(request->getError()) }; + QJSValueList args { uint8_t(request->getError()), map }; callback.call(args); } From 39e869fdfd0b4e26bef30c050489619c8a92cef6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 17:54:38 -0800 Subject: [PATCH 161/209] append a trailing slash for folder rename --- interface/resources/qml/AssetServer.qml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index a3fe6cacb8..e5e3d95a81 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -73,6 +73,11 @@ Window { newPath = "/" + newPath; } + if (oldPath[oldPath.length - 1] == '/' && newPath[newPath.length - 1] != '/') { + // this is a folder rename but the user neglected to add a trailing slash when providing a new path + newPath = newPath + "/"; + } + if (Assets.isKnownFolder(newPath)) { box = errorMessageBox("Cannot overwrite existing directory."); box.selected.connect(reload); From 8e2b06a8e5d59935fadb0ebd2b79a7fbbbb46e56 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 18:32:18 -0800 Subject: [PATCH 162/209] use an explicit selection model for treeview --- interface/resources/qml/AssetServer.qml | 18 ++++++++++-------- interface/resources/qml/controls-uit/Tree.qml | 4 ++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index e5e3d95a81..1a6247ced9 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -138,7 +138,7 @@ Window { function addToWorld(url) { if (!url) { - url = assetProxyModel.data(treeView.currentIndex, 0x103); + url = assetProxyModel.data(treeView.selection.currentIndex, 0x103); } if (!url || !canAddToWorld(url)) { @@ -153,10 +153,10 @@ Window { function copyURLToClipboard(index) { if (!index) { - index = treeView.currentIndex; + index = treeView.selection.currentIndex; } - var url = assetProxyModel.data(treeView.currentIndex, 0x103); + var url = assetProxyModel.data(treeView.selection.currentIndex, 0x103); if (!url) { return; } @@ -165,9 +165,11 @@ Window { function renameFile(index) { if (!index) { - index = treeView.currentIndex; + index = treeView.selection.currentIndex; } + console.log("THE CURRENT INDEX IS " + treeView.selection.currentIndex); var path = assetProxyModel.data(index, 0x100); + console.log("THE PATH IS " + path); if (!path) { return; } @@ -194,14 +196,14 @@ Window { } function deleteFile(index) { if (!index) { - index = treeView.currentIndex; + index = treeView.selection.currentIndex; } var path = assetProxyModel.data(index, 0x100); if (!path) { return; } - var isFolder = assetProxyModel.data(treeView.currentIndex, 0x101); + var isFolder = assetProxyModel.data(treeView.selection.currentIndex, 0x101); var typeString = isFolder ? 'folder' : 'file'; var object = desktop.messageBox({ @@ -239,7 +241,7 @@ Window { var fileUrl = fileUrlTextField.text var shouldAddToWorld = addToWorldCheckBox.checked - var path = assetProxyModel.data(treeView.currentIndex, 0x100); + var path = assetProxyModel.data(treeView.selection.currentIndex, 0x100); var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/"; var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); @@ -302,7 +304,7 @@ Window { height: 26 width: 120 - enabled: canAddToWorld(assetProxyModel.data(treeView.currentIndex, 0x100)) + enabled: canAddToWorld(assetProxyModel.data(treeView.selection.currentIndex, 0x100)) onClicked: root.addToWorld() } diff --git a/interface/resources/qml/controls-uit/Tree.qml b/interface/resources/qml/controls-uit/Tree.qml index 18741d6420..a2572a2f5c 100644 --- a/interface/resources/qml/controls-uit/Tree.qml +++ b/interface/resources/qml/controls-uit/Tree.qml @@ -8,6 +8,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +import QtQml.Models 2.2 import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 @@ -22,6 +23,9 @@ TreeView { readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light model: treeModel + selection: ItemSelectionModel { + model: treeModel + } TableViewColumn { role: "display"; From 7675c83f920ecb0505e7ece26255ff56261b9a19 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 18:34:28 -0800 Subject: [PATCH 163/209] clear selection on reload --- interface/resources/qml/AssetServer.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 1a6247ced9..db2f6dd83c 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -127,6 +127,7 @@ Window { function reload() { Assets.mappingModel.refresh(); + treeView.selection.clear(); } function handleGetMappingsError(errorCode) { From 7ccba8b40636425b5c0cc009476aed493eef872d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 18:36:12 -0800 Subject: [PATCH 164/209] remove debug for selected index crash --- interface/resources/qml/AssetServer.qml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index db2f6dd83c..c5ebb04819 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -168,9 +168,8 @@ Window { if (!index) { index = treeView.selection.currentIndex; } - console.log("THE CURRENT INDEX IS " + treeView.selection.currentIndex); + var path = assetProxyModel.data(index, 0x100); - console.log("THE PATH IS " + path); if (!path) { return; } From 631aad80f9b891739fe250767c74ba9d6b7979dc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 11 Mar 2016 09:53:08 -0800 Subject: [PATCH 165/209] Add Q_DECLARE_METATYPE(AssetMappingModel*) and fix indentation --- .../AssetMappingsScriptingInterface.h | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index 99ced25d29..35a1c1ae7e 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -20,31 +20,32 @@ #include #include - class AssetMappingItem : public QStandardItem { - public: - AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder); +class AssetMappingItem : public QStandardItem { +public: + AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder); - QString name; - QString fullPath; - bool isFolder; - }; + QString name; + QString fullPath; + bool isFolder; +}; - class AssetMappingModel : public QStandardItemModel { - Q_OBJECT - public: - Q_INVOKABLE void refresh(); +class AssetMappingModel : public QStandardItemModel { + Q_OBJECT +public: + Q_INVOKABLE void refresh(); - bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); } - bool isKnownFolder(QString path) const; + bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); } + bool isKnownFolder(QString path) const; - signals: - void errorGettingMappings(int error); +signals: + void errorGettingMappings(int error); - private: - QHash _pathToItemMap; - }; +private: + QHash _pathToItemMap; +}; +Q_DECLARE_METATYPE(AssetMappingModel*); class AssetMappingsScriptingInterface : public QObject { Q_OBJECT From 9522c2d17cfe2c116b5c75246d791596fc364052 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 11:04:34 -0800 Subject: [PATCH 166/209] add file open and write error handling --- .../src/assets/UploadAssetTask.cpp | 21 ++++++++++++++----- libraries/networking/src/AssetUpload.cpp | 5 +++++ libraries/networking/src/AssetUpload.h | 3 ++- libraries/networking/src/AssetUtils.h | 3 ++- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/assets/UploadAssetTask.cpp b/assignment-client/src/assets/UploadAssetTask.cpp index 0856a29e1f..e850f29991 100644 --- a/assignment-client/src/assets/UploadAssetTask.cpp +++ b/assignment-client/src/assets/UploadAssetTask.cpp @@ -61,13 +61,24 @@ void UploadAssetTask::run() { if (file.exists()) { qDebug() << "[WARNING] This file already exists: " << hexHash; - } else { - file.open(QIODevice::WriteOnly); - file.write(fileData); + + replyPacket->writePrimitive(AssetServerError::NoError); + replyPacket->write(hash); + } else if (file.open(QIODevice::WriteOnly) && file.write(fileData) == qint64(fileSize)) { file.close(); + + replyPacket->writePrimitive(AssetServerError::NoError); + replyPacket->write(hash); + } else { + // upload has failed - remove the file and return an error + auto removed = file.remove(); + + if (!removed) { + qWarning() << "Removal of failed upload file" << hash << "failed."; + } + + replyPacket->writePrimitive(AssetServerError::FileOperationFailed); } - replyPacket->writePrimitive(AssetServerError::NoError); - replyPacket->write(hash); } auto nodeList = DependencyManager::get(); diff --git a/libraries/networking/src/AssetUpload.cpp b/libraries/networking/src/AssetUpload.cpp index 2840f6777c..44b7e9b681 100644 --- a/libraries/networking/src/AssetUpload.cpp +++ b/libraries/networking/src/AssetUpload.cpp @@ -42,6 +42,8 @@ QString AssetUpload::getErrorString() const { return "The file could not be opened. Please check your permissions and try again."; case AssetUpload::NetworkError: return "There was a problem reaching your Asset Server. Please check your network connectivity."; + case AssetUpload::ServerFileError: + return "The Asset Server failed to store the asset. Please try again."; default: // not handled, do not show a message box return QString(); @@ -90,6 +92,9 @@ void AssetUpload::start() { case AssetServerError::PermissionDenied: _error = PermissionDenied; break; + case AssetServerError::FileOperationFailed: + _error = ServerFileError; + break; default: _error = FileOpenError; break; diff --git a/libraries/networking/src/AssetUpload.h b/libraries/networking/src/AssetUpload.h index 656c1a281e..82328ef2eb 100644 --- a/libraries/networking/src/AssetUpload.h +++ b/libraries/networking/src/AssetUpload.h @@ -32,7 +32,8 @@ public: Timeout, TooLarge, PermissionDenied, - FileOpenError + FileOpenError, + ServerFileError }; static const QString PERMISSION_DENIED_ERROR; diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index ac3d819ae2..3a663af420 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -40,7 +40,8 @@ enum AssetServerError : uint8_t { InvalidByteRange, AssetTooLarge, PermissionDenied, - MappingOperationFailed + MappingOperationFailed, + FileOperationFailed }; enum AssetMappingOperationType : uint8_t { From e51aedeb35a7e99b2ff6a28c8bf649cf177ff4bf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 11:36:52 -0800 Subject: [PATCH 167/209] fix error handling for diff request types --- .../src/assets/UploadAssetTask.cpp | 5 ++- interface/resources/qml/AssetServer.qml | 12 +++---- .../AssetMappingsScriptingInterface.cpp | 35 ++++--------------- .../AssetMappingsScriptingInterface.h | 4 +-- libraries/networking/src/MappingRequest.cpp | 21 +++++++++++ libraries/networking/src/MappingRequest.h | 1 + 6 files changed, 40 insertions(+), 38 deletions(-) diff --git a/assignment-client/src/assets/UploadAssetTask.cpp b/assignment-client/src/assets/UploadAssetTask.cpp index e850f29991..e82b99fe99 100644 --- a/assignment-client/src/assets/UploadAssetTask.cpp +++ b/assignment-client/src/assets/UploadAssetTask.cpp @@ -65,16 +65,19 @@ void UploadAssetTask::run() { replyPacket->writePrimitive(AssetServerError::NoError); replyPacket->write(hash); } else if (file.open(QIODevice::WriteOnly) && file.write(fileData) == qint64(fileSize)) { + qDebug() << "Wrote file" << hash << "to disk. Upload complete"; file.close(); replyPacket->writePrimitive(AssetServerError::NoError); replyPacket->write(hash); } else { + qWarning() << "Failed to upload or write to file" << hexHash << " - upload failed."; + // upload has failed - remove the file and return an error auto removed = file.remove(); if (!removed) { - qWarning() << "Removal of failed upload file" << hash << "failed."; + qWarning() << "Removal of failed upload file" << hexHash << "failed."; } replyPacket->writePrimitive(AssetServerError::FileOperationFailed); diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index c5ebb04819..1be5867413 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -57,7 +57,7 @@ Window { if (err) { console.log("Asset browser - error deleting path: ", path, err); - box = errorMessageBox("There was an error deleting:\n" + path + "\n" + Assets.getErrorString(err)); + box = errorMessageBox("There was an error deleting:\n" + path + "\n" + err); box.selected.connect(reload); } else { console.log("Asset browser - finished deleting path: ", path); @@ -88,7 +88,7 @@ Window { Assets.renameMapping(oldPath, newPath, function(err) { if (err) { console.log("Asset browser - error renaming: ", oldPath, "=>", newPath, " - error ", err); - box = errorMessageBox("There was an error renaming:\n" + oldPath + " to " + newPath + "\n" + Assets.getErrorString(err)); + box = errorMessageBox("There was an error renaming:\n" + oldPath + " to " + newPath + "\n" + err); box.selected.connect(reload); } else { console.log("Asset browser - finished rename: ", oldPath, "=>", newPath); @@ -130,10 +130,10 @@ Window { treeView.selection.clear(); } - function handleGetMappingsError(errorCode) { + function handleGetMappingsError(errorString) { errorMessageBox( "There was a problem retreiving the list of assets from your Asset Server.\n" - + Assets.getErrorString(errorCode) + + errorString ); } @@ -168,7 +168,7 @@ Window { if (!index) { index = treeView.selection.currentIndex; } - + var path = assetProxyModel.data(index, 0x100); if (!path) { return; @@ -248,7 +248,7 @@ Window { Assets.uploadFile(fileUrl, directory + filename, function(err, path) { if (err) { console.log("Asset Browser - error uploading: ", fileUrl, " - error ", err); - var box = errorMessage("There was an error uploading:\n" + fileUrl + "\n" + Assets.getErrorString(err)); + var box = errorMessageBox("There was an error uploading:\n" + fileUrl + "\n" + err); box.selected.connect(reload); } else { console.log("Asset Browser - finished uploading: ", fileUrl); diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 32b697459c..d4f5431d32 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -27,34 +27,13 @@ AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() { _proxyModel.sort(0); } -QString AssetMappingsScriptingInterface::getErrorString(int errorCode) const { - switch (errorCode) { - case MappingRequest::NoError: - return "No error"; - case MappingRequest::NotFound: - return "Asset not found"; - case MappingRequest::NetworkError: - return "Unable to communicate with Asset Server"; - case MappingRequest::PermissionDenied: - return "Permission denied"; - case MappingRequest::InvalidPath: - return "Path is invalid"; - case MappingRequest::InvalidHash: - return "Hash is invalid"; - case MappingRequest::UnknownError: - return "Asset Server internal error"; - default: - return QString(); - } -} - void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createSetMappingRequest(path, hash); connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { if (callback.isCallable()) { - QJSValueList args { uint8_t(request->getError()), request->getPath() }; + QJSValueList args { request->getErrorString(), request->getPath() }; callback.call(args); } @@ -70,7 +49,7 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { if (callback.isCallable()) { - QJSValueList args { uint8_t(request->getError()) }; + QJSValueList args { request->getErrorString() }; callback.call(args); } @@ -108,7 +87,7 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { if (upload->getError() != AssetUpload::NoError) { if (callback.isCallable()) { - QJSValueList args { uint8_t(upload->getError()) }; + QJSValueList args { upload->getErrorString() }; callback.call(args); } } else { @@ -127,7 +106,7 @@ void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { if (callback.isCallable()) { - QJSValueList args { uint8_t(request->getError()) }; + QJSValueList args { request->getErrorString() }; callback.call(args); } @@ -150,7 +129,7 @@ void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { } if (callback.isCallable()) { - QJSValueList args { uint8_t(request->getError()), map }; + QJSValueList args { request->getErrorString(), map }; callback.call(args); } @@ -166,7 +145,7 @@ void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString new connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { if (callback.isCallable()) { - QJSValueList args { uint8_t(request->getError()) }; + QJSValueList args { request->getErrorString() }; callback.call(args); } @@ -293,7 +272,7 @@ void AssetMappingModel::refresh() { } } } else { - emit errorGettingMappings(static_cast(request->getError())); + emit errorGettingMappings(request->getErrorString()); } }); diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index 99ced25d29..9a427a05ed 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -39,7 +39,7 @@ bool isKnownFolder(QString path) const; signals: - void errorGettingMappings(int error); + void errorGettingMappings(QString errorString); private: QHash _pathToItemMap; @@ -59,8 +59,6 @@ public: Q_INVOKABLE bool isKnownMapping(QString path) const { return _assetMappingModel.isKnownMapping(path); } Q_INVOKABLE bool isKnownFolder(QString path) const { return _assetMappingModel.isKnownFolder(path); } - Q_INVOKABLE QString getErrorString(int errorCode) const; - Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback = QJSValue()); Q_INVOKABLE void getMapping(QString path, QJSValue callback = QJSValue()); Q_INVOKABLE void uploadFile(QString path, QString mapping, QJSValue callback = QJSValue()); diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp index 7b675050a1..be24c6b9d2 100644 --- a/libraries/networking/src/MappingRequest.cpp +++ b/libraries/networking/src/MappingRequest.cpp @@ -25,6 +25,27 @@ void MappingRequest::start() { doStart(); }; +QString MappingRequest::getErrorString() const { + switch (_error) { + case MappingRequest::NoError: + return "No error"; + case MappingRequest::NotFound: + return "Asset not found"; + case MappingRequest::NetworkError: + return "Unable to communicate with Asset Server"; + case MappingRequest::PermissionDenied: + return "Permission denied"; + case MappingRequest::InvalidPath: + return "Path is invalid"; + case MappingRequest::InvalidHash: + return "Hash is invalid"; + case MappingRequest::UnknownError: + return "Asset Server internal error"; + default: + return QString(); + } +} + GetMappingRequest::GetMappingRequest(const AssetPath& path) : _path(path.trimmed()) { }; diff --git a/libraries/networking/src/MappingRequest.h b/libraries/networking/src/MappingRequest.h index 504a0cb2fa..206e383c33 100644 --- a/libraries/networking/src/MappingRequest.h +++ b/libraries/networking/src/MappingRequest.h @@ -33,6 +33,7 @@ public: Q_INVOKABLE void start(); Error getError() const { return _error; } + Q_INVOKABLE QString getErrorString() const; protected: Error _error { NoError }; From 85e203e2cbec798f0f74ca99ded0afb924be4f4b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 11:44:46 -0800 Subject: [PATCH 168/209] return an empty string for no error --- libraries/networking/src/AssetUpload.cpp | 5 +++-- libraries/networking/src/MappingRequest.cpp | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/AssetUpload.cpp b/libraries/networking/src/AssetUpload.cpp index 44b7e9b681..f99f5badb6 100644 --- a/libraries/networking/src/AssetUpload.cpp +++ b/libraries/networking/src/AssetUpload.cpp @@ -34,6 +34,8 @@ AssetUpload::AssetUpload(const QString& filename) : QString AssetUpload::getErrorString() const { // figure out the right error message for error switch (_error) { + case AssetUpload::NoError: + return QString(); case AssetUpload::PermissionDenied: return PERMISSION_DENIED_ERROR; case AssetUpload::TooLarge: @@ -45,8 +47,7 @@ QString AssetUpload::getErrorString() const { case AssetUpload::ServerFileError: return "The Asset Server failed to store the asset. Please try again."; default: - // not handled, do not show a message box - return QString(); + return QString("Unknown error with code %1").arg(_error); } } diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp index be24c6b9d2..409957db42 100644 --- a/libraries/networking/src/MappingRequest.cpp +++ b/libraries/networking/src/MappingRequest.cpp @@ -28,7 +28,7 @@ void MappingRequest::start() { QString MappingRequest::getErrorString() const { switch (_error) { case MappingRequest::NoError: - return "No error"; + return QString(); case MappingRequest::NotFound: return "Asset not found"; case MappingRequest::NetworkError: @@ -42,7 +42,7 @@ QString MappingRequest::getErrorString() const { case MappingRequest::UnknownError: return "Asset Server internal error"; default: - return QString(); + return QString("Unknown error with code %1").arg(_error); } } From 7efe26e8543e4dcdff05f4ff650f1323d737b0f6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 11 Mar 2016 11:53:14 -0800 Subject: [PATCH 169/209] Disable asset browser if user can't rez --- interface/src/Menu.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0724e75ea1..dcec037c1c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -130,8 +130,12 @@ Menu::Menu() { editMenu->addSeparator(); // Edit > My Asset Server - addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, Qt::CTRL | Qt::SHIFT | Qt::Key_A, - qApp, SLOT(toggleAssetServerWidget())); + auto assetServerAction = addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, + Qt::CTRL | Qt::SHIFT | Qt::Key_A, + qApp, SLOT(toggleAssetServerWidget())); + auto nodeList = DependencyManager::get(); + QObject::connect(nodeList.data(), &NodeList::canRezChanged, assetServerAction, &QAction::setEnabled); + assetServerAction->setEnabled(nodeList->getThisNodeCanRez()); // Edit > Reload All Content [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()), From 630f5303b2f8ac660d2ef4dd8f662d4f9bd8622f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 13:23:57 -0800 Subject: [PATCH 170/209] overwrite existing asset during upload if hash doesn't match --- .../src/assets/UploadAssetTask.cpp | 52 ++++++++++++------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/assignment-client/src/assets/UploadAssetTask.cpp b/assignment-client/src/assets/UploadAssetTask.cpp index e82b99fe99..5ca9b5bbf1 100644 --- a/assignment-client/src/assets/UploadAssetTask.cpp +++ b/assignment-client/src/assets/UploadAssetTask.cpp @@ -58,30 +58,46 @@ void UploadAssetTask::run() { << "is: (" << hexHash << ") "; QFile file { _resourcesDir.filePath(QString(hexHash)) }; + + bool existingCorrectFile = false; if (file.exists()) { - qDebug() << "[WARNING] This file already exists: " << hexHash; + // check if the local file has the correct contents, otherwise we overwrite + if (file.open(QIODevice::ReadOnly) && hashData(file.readAll()) == hash) { + qDebug() << "Not overwriting existing verified file: " << hexHash; - replyPacket->writePrimitive(AssetServerError::NoError); - replyPacket->write(hash); - } else if (file.open(QIODevice::WriteOnly) && file.write(fileData) == qint64(fileSize)) { - qDebug() << "Wrote file" << hash << "to disk. Upload complete"; - file.close(); + existingCorrectFile = true; - replyPacket->writePrimitive(AssetServerError::NoError); - replyPacket->write(hash); - } else { - qWarning() << "Failed to upload or write to file" << hexHash << " - upload failed."; - - // upload has failed - remove the file and return an error - auto removed = file.remove(); - - if (!removed) { - qWarning() << "Removal of failed upload file" << hexHash << "failed."; + replyPacket->writePrimitive(AssetServerError::NoError); + replyPacket->write(hash); + } else { + qDebug() << "Overwriting an existing file whose contents did not match the expected hash: " << hexHash; + file.close(); } - - replyPacket->writePrimitive(AssetServerError::FileOperationFailed); } + + if (!existingCorrectFile) { + if (file.open(QIODevice::WriteOnly) && file.write(fileData) == qint64(fileSize)) { + qDebug() << "Wrote file" << hexHash << "to disk. Upload complete"; + file.close(); + + replyPacket->writePrimitive(AssetServerError::NoError); + replyPacket->write(hash); + } else { + qWarning() << "Failed to upload or write to file" << hexHash << " - upload failed."; + + // upload has failed - remove the file and return an error + auto removed = file.remove(); + + if (!removed) { + qWarning() << "Removal of failed upload file" << hexHash << "failed."; + } + + replyPacket->writePrimitive(AssetServerError::FileOperationFailed); + } + } + + } auto nodeList = DependencyManager::get(); From d7b800283b926dd535396760157d42e6bb86df24 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 11 Mar 2016 13:57:05 -0800 Subject: [PATCH 171/209] Adjust bugsplat to use qPrintable --- interface/src/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 3a4807ad6a..5a53fdd4bf 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -39,7 +39,7 @@ int main(int argc, const char* argv[]) { static const DWORD BUG_SPLAT_FLAGS = MDSF_PREVENTHIJACKING | MDSF_USEGUARDMEMORY; static const char* BUG_SPLAT_DATABASE = "interface_alpha"; static const char* BUG_SPLAT_APPLICATION_NAME = "Interface"; - MiniDmpSender mpSender { BUG_SPLAT_DATABASE, BUG_SPLAT_APPLICATION_NAME, BuildInfo::VERSION.toLatin1().constData(), + MiniDmpSender mpSender { BUG_SPLAT_DATABASE, BUG_SPLAT_APPLICATION_NAME, qPrintable(BuildInfo::VERSION), nullptr, BUG_SPLAT_FLAGS }; #endif @@ -145,9 +145,9 @@ int main(int argc, const char* argv[]) { #ifdef HAS_BUGSPLAT AccountManager& accountManager = AccountManager::getInstance(); - mpSender.setDefaultUserName(accountManager.getAccountInfo().getUsername().toLatin1().constData()); + mpSender.setDefaultUserName(qPrintable(accountManager.getAccountInfo().getUsername())); QObject::connect(&accountManager, &AccountManager::usernameChanged, &app, [&mpSender](const QString& newUsername) { - mpSender.setDefaultUserName(newUsername.toLatin1().constData()); + mpSender.setDefaultUserName(qPrintable(newUsername)); }); #endif From ee1fb698a4656b7b22fb87b5a9d79a8f26a7428a Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 8 Mar 2016 12:50:21 -0800 Subject: [PATCH 172/209] Add texture transparency to material key --- libraries/model/src/model/Material.cpp | 7 +++--- libraries/model/src/model/Material.h | 12 ++++++++-- libraries/model/src/model/Material.slh | 24 +++++++++---------- .../render-utils/src/MeshPartPayload.cpp | 9 +++---- 4 files changed, 30 insertions(+), 22 deletions(-) diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index 10fa15edd5..306867c204 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -80,6 +80,10 @@ void Material::setMetallic(float metallic) { _schemaBuffer.edit()._metallic = metallic; } +void Material::setTransparentTexture(bool isTransparent) { + _key.setTransparentTexture(isTransparent); + _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); +} void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textureMap) { if (textureMap) { @@ -92,6 +96,3 @@ void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textur _textureMaps.erase(channel); } } - - - diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index b22f8a3f42..078fc6499a 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -32,6 +32,7 @@ public: METALLIC_VAL_BIT, GLOSSY_VAL_BIT, TRANSPARENT_VAL_BIT, + TRANSPARENT_TEX_VAL_BIT, EMISSIVE_MAP_BIT, ALBEDO_MAP_BIT, @@ -101,6 +102,9 @@ public: void setAlbedo(bool value) { _flags.set(ALBEDO_VAL_BIT, value); } bool isAlbedo() const { return _flags[ALBEDO_VAL_BIT]; } + void setTransparentTexture(bool value) { _flags.set(TRANSPARENT_TEX_VAL_BIT, value); } + bool isTransparentTexture() const { return _flags[TRANSPARENT_TEX_VAL_BIT]; } + void setAlbedoMap(bool value) { _flags.set(ALBEDO_MAP_BIT, value); } bool isAlbedoMap() const { return _flags[ALBEDO_MAP_BIT]; } @@ -164,6 +168,9 @@ public: Builder& withoutAlbedo() { _value.reset(MaterialKey::ALBEDO_VAL_BIT); _mask.set(MaterialKey::ALBEDO_VAL_BIT); return (*this); } Builder& withAlbedo() { _value.set(MaterialKey::ALBEDO_VAL_BIT); _mask.set(MaterialKey::ALBEDO_VAL_BIT); return (*this); } + Builder& withoutTransparentTexture() { _value.reset(MaterialKey::TRANSPARENT_TEX_VAL_BIT); _mask.set(MaterialKey::TRANSPARENT_TEX_VAL_BIT); return (*this); } + Builder& withTransparentTexture() { _value.set(MaterialKey::TRANSPARENT_TEX_VAL_BIT); _mask.set(MaterialKey::TRANSPARENT_TEX_VAL_BIT); return (*this); } + Builder& withoutAlbedoMap() { _value.reset(MaterialKey::ALBEDO_MAP_BIT); _mask.set(MaterialKey::ALBEDO_MAP_BIT); return (*this); } Builder& withAlbedoMap() { _value.set(MaterialKey::ALBEDO_MAP_BIT); _mask.set(MaterialKey::ALBEDO_MAP_BIT); return (*this); } @@ -248,6 +255,8 @@ public: void setRoughness(float roughness); float getRoughness() const { return _schemaBuffer.get()._roughness; } + void setTransparentTexture(bool isTransparent); + // Schema to access the attribute values of the material class Schema { public: @@ -260,8 +269,7 @@ public: glm::vec3 _fresnel{ 0.03f }; // Fresnel value for a default non metallic float _metallic{ 0.0f }; // Not Metallic - - glm::vec3 _spare0{ 0.0f }; + glm::vec3 _spare{ 0.0f }; uint32_t _key{ 0 }; // a copy of the materialKey diff --git a/libraries/model/src/model/Material.slh b/libraries/model/src/model/Material.slh index d75f3df5e0..da185ddf0b 100644 --- a/libraries/model/src/model/Material.slh +++ b/libraries/model/src/model/Material.slh @@ -15,7 +15,7 @@ struct Material { vec4 _emissiveOpacity; vec4 _albedoRoughness; vec4 _fresnelMetallic; - vec4 _spare; + vec4 _spareKey; }; uniform materialBuffer { @@ -37,25 +37,23 @@ float getMaterialMetallic(Material m) { return m._fresnelMetallic.a; } float getMaterialShininess(Material m) { return 1.0 - getMaterialRoughness(m); } -int getMaterialKey(Material m) { return floatBitsToInt(m._spare.w); } +int getMaterialKey(Material m) { return floatBitsToInt(m._spareKey.w); } const int EMISSIVE_VAL_BIT = 0x00000001; const int ALBEDO_VAL_BIT = 0x00000002; const int METALLIC_VAL_BIT = 0x00000004; const int GLOSSY_VAL_BIT = 0x00000008; const int TRANSPARENT_VAL_BIT = 0x00000010; +const int TRANSPARENT_TEX_VAL_BIT = 0x00000020; +const int EMISSIVE_MAP_BIT = 0x00000040; +const int ALBEDO_MAP_BIT = 0x00000080; +const int METALLIC_MAP_BIT = 0x00000100; +const int ROUGHNESS_MAP_BIT = 0x00000200; +const int TRANSPARENT_MAP_BIT = 0x00000400; +const int NORMAL_MAP_BIT = 0x00000800; +const int OCCLUSION_MAP_BIT = 0x00001000; -const int EMISSIVE_MAP_BIT = 0x00000020; -const int ALBEDO_MAP_BIT = 0x00000040; -const int METALLIC_MAP_BIT = 0x00000080; -const int ROUGHNESS_MAP_BIT = 0x00000100; -const int TRANSPARENT_MAP_BIT = 0x00000200; -const int NORMAL_MAP_BIT = 0x00000400; -const int OCCLUSION_MAP_BIT = 0x00000800; - -const int LIGHTMAP_MAP_BIT = 0x00001000; - - +const int LIGHTMAP_MAP_BIT = 0x00002000; <@endif@> diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 166b14333f..4ae5b4532a 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -81,7 +81,7 @@ ItemKey MeshPartPayload::getKey() const { if (_drawMaterial) { auto matKey = _drawMaterial->getKey(); - if (matKey.isTransparent() || matKey.isTransparentMap()) { + if (matKey.isTransparent() || matKey.isTransparentTexture() || matKey.isTransparentMap()) { builder.withTransparent(); } } @@ -100,7 +100,7 @@ ShapeKey MeshPartPayload::getShapeKey() const { } ShapeKey::Builder builder; - if (drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap()) { + if (drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentTexture() || drawMaterialKey.isTransparentMap()) { builder.withTranslucent(); } if (drawMaterialKey.isNormalMap()) { @@ -365,7 +365,7 @@ ItemKey ModelMeshPartPayload::getKey() const { if (_drawMaterial) { auto matKey = _drawMaterial->getKey(); - if (matKey.isTransparent() || matKey.isTransparentMap()) { + if (matKey.isTransparent() || matKey.isTransparentTexture() || matKey.isTransparentMap()) { builder.withTransparent(); } } @@ -412,7 +412,8 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { drawMaterialKey = _drawMaterial->getKey(); } - bool isTranslucent = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap(); + bool isTranslucent = + drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentTexture() || drawMaterialKey.isTransparentMap(); bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty(); bool hasSpecular = drawMaterialKey.isMetallicMap(); bool hasLightmap = drawMaterialKey.isLightmapMap(); From 22d41c833f8b8b7bde69994ebd521b48badc48dd Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 29 Feb 2016 19:26:18 -0800 Subject: [PATCH 173/209] Update loaded models with texture transparency --- .../model-networking/src/model-networking/ModelCache.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 21eed5f59f..29c517594a 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -145,7 +145,13 @@ bool NetworkGeometry::isLoadedWithTextures() const { (material->lightmapTexture && !material->lightmapTexture->isLoaded())) { return false; } + if (material->albedoTexture) { + // Reset the materialKey transparentTexture key only, as it is albedoTexture-dependent + const auto& usage = material->albedoTexture->getGPUTexture()->getUsage(); + material->_material->setTransparentTexture(usage.isAlpha() && !usage.isAlphaMask()); + } } + _isLoadedWithTextures = true; } return true; From 3b62e203f754717c49ea256c425642801d251759 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 11 Mar 2016 14:25:21 -0800 Subject: [PATCH 174/209] Cache NetworkGeometry::_hasTransparentTextures --- .../model-networking/src/model-networking/ModelCache.cpp | 6 +++++- .../model-networking/src/model-networking/ModelCache.h | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 29c517594a..af9fe97e93 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -135,6 +135,8 @@ bool NetworkGeometry::isLoadedWithTextures() const { } if (!_isLoadedWithTextures) { + _hasTransparentTextures = false; + for (auto&& material : _materials) { if ((material->albedoTexture && !material->albedoTexture->isLoaded()) || (material->normalTexture && !material->normalTexture->isLoaded()) || @@ -148,7 +150,9 @@ bool NetworkGeometry::isLoadedWithTextures() const { if (material->albedoTexture) { // Reset the materialKey transparentTexture key only, as it is albedoTexture-dependent const auto& usage = material->albedoTexture->getGPUTexture()->getUsage(); - material->_material->setTransparentTexture(usage.isAlpha() && !usage.isAlphaMask()); + bool isTransparentTexture = usage.isAlpha() && !usage.isAlphaMask(); + material->_material->setTransparentTexture(isTransparentTexture); + _hasTransparentTextures = _hasTransparentTextures || isTransparentTexture; } } diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 60f185f691..7f01bdafaa 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -75,6 +75,10 @@ public: // true when the requested geometry and its textures are loaded. bool isLoadedWithTextures() const; + // true if the albedo texture has a non-masking alpha channel. + // This can only be known after isLoadedWithTextures(). + bool hasTransparentTextures() const { return _hasTransparentTextures; } + // WARNING: only valid when isLoaded returns true. const FBXGeometry& getFBXGeometry() const { return *_geometry; } const std::vector>& getMeshes() const { return _meshes; } @@ -151,6 +155,7 @@ protected: // cache for isLoadedWithTextures() mutable bool _isLoadedWithTextures = false; + mutable bool _hasTransparentTextures = false; }; /// Reads geometry in a worker thread. From a89a76dc4b8034833bea89fa6c011ffd91eb62bd Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 11 Mar 2016 14:25:39 -0800 Subject: [PATCH 175/209] Require model fixup if tex is transparent --- libraries/render-utils/src/Model.cpp | 17 +++++++++++++++++ libraries/render-utils/src/Model.h | 12 +++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index ce6dfd6849..8b6cc41f35 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -74,6 +74,21 @@ Model::~Model() { AbstractViewStateInterface* Model::_viewState = NULL; +bool Model::needsFixupInScene() { + if (readyToAddToScene()) { + // Once textures are loaded, fixup if they are now transparent + if (!_needsReload && _needsUpdateTransparentTextures && _geometry->isLoadedWithTextures()) { + _needsUpdateTransparentTextures = false; + if (_hasTransparentTextures != _geometry->hasTransparentTextures()) { + return true; + } + } + if (!_readyWhenAdded) { + return true; + } + } + return false; +} void Model::setTranslation(const glm::vec3& translation) { _translation = translation; @@ -728,6 +743,8 @@ void Model::setURL(const QUrl& url) { } _needsReload = true; + _needsUpdateTransparentTextures = true; + _hasTransparentTextures = false; _meshGroupsKnown = false; invalidCalculatedMeshBoxes(); deleteGeometry(); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 424eed1e66..e90d51813b 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -70,7 +70,7 @@ public: // new Scene/Engine rendering support void setVisibleInScene(bool newValue, std::shared_ptr scene); - bool needsFixupInScene() { return !_readyWhenAdded && readyToAddToScene(); } + bool needsFixupInScene(); bool readyToAddToScene(RenderArgs* renderArgs = nullptr) { return !_needsReload && isRenderable() && isActive() && isLoaded(); } @@ -365,10 +365,12 @@ protected: QSet> _renderItemsSet; QMap _renderItems; - bool _readyWhenAdded = false; - bool _needsReload = true; - bool _needsUpdateClusterMatrices = true; - bool _showCollisionHull = false; + bool _readyWhenAdded { false }; + bool _needsReload { true }; + bool _needsUpdateClusterMatrices { true }; + bool _needsUpdateTransparentTextures { true }; + bool _hasTransparentTextures { false }; + bool _showCollisionHull { false }; friend class ModelMeshPartPayload; RigPointer _rig; From 9dcdf26567f5829b9973ede55b5c27b47988eb05 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 11 Mar 2016 15:15:30 -0800 Subject: [PATCH 176/209] Only consider model transparent if all texs are --- .../model-networking/src/model-networking/ModelCache.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index af9fe97e93..3f7e0405d4 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -135,7 +135,7 @@ bool NetworkGeometry::isLoadedWithTextures() const { } if (!_isLoadedWithTextures) { - _hasTransparentTextures = false; + _hasTransparentTextures = true; for (auto&& material : _materials) { if ((material->albedoTexture && !material->albedoTexture->isLoaded()) || @@ -152,7 +152,8 @@ bool NetworkGeometry::isLoadedWithTextures() const { const auto& usage = material->albedoTexture->getGPUTexture()->getUsage(); bool isTransparentTexture = usage.isAlpha() && !usage.isAlphaMask(); material->_material->setTransparentTexture(isTransparentTexture); - _hasTransparentTextures = _hasTransparentTextures || isTransparentTexture; + // FIXME: Materials with *some* transparent textures seem to give all *other* textures alphas of 0. + _hasTransparentTextures = isTransparentTexture && _hasTransparentTextures; } } From 895920a211f4e9a91bed0e54dc2492ca40628ffe Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 15:19:41 -0800 Subject: [PATCH 177/209] short circuit upload when file cannot be opened --- libraries/networking/src/AssetUpload.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/networking/src/AssetUpload.cpp b/libraries/networking/src/AssetUpload.cpp index f99f5badb6..077a0388cf 100644 --- a/libraries/networking/src/AssetUpload.cpp +++ b/libraries/networking/src/AssetUpload.cpp @@ -69,6 +69,8 @@ void AssetUpload::start() { // emit that we are done emit finished(this, QString()); + + return; } } From 6d6a53a69a30986e7fb19d24720fc67016ff4b10 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 13:27:45 -0800 Subject: [PATCH 178/209] use timer for upload click handle to avoid focus issue --- interface/resources/qml/AssetServer.qml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 1be5867413..48c005270f 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -447,7 +447,22 @@ Window { width: 155 enabled: fileUrlTextField.text != "" - onClicked: root.uploadClicked() + onClicked: uploadClickedTimer.running = true + + // For some reason trigginer an API that enters + // an internal event loop directly from the button clicked + // trigger below causes the appliction to behave oddly. + // Most likely because the button onClicked handling is never + // completed until the function returns. + // FIXME find a better way of handling the input dialogs that + // doesn't trigger this. + Timer { + id: uploadClickedTimer + interval: 5 + repeat: false + running: false + onTriggered: uploadClicked(); + } } } From 31f0e4a919ba66fe17aab67cfaae8b64cc6d0c0f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 13:32:50 -0800 Subject: [PATCH 179/209] disable the rename and delete buttons if nothing selected --- interface/resources/qml/AssetServer.qml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 48c005270f..a1c2fc2398 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -272,6 +272,10 @@ Window { }); } + function itemSelected() { + return treeView.selection.hasSelection() + } + Column { width: pane.contentWidth @@ -317,6 +321,7 @@ Window { width: 80 onClicked: root.renameFile() + enabled: treeView.selection.hasSelection } HifiControls.Button { @@ -329,6 +334,7 @@ Window { width: 80 onClicked: root.deleteFile() + enabled: treeView.selection.hasSelection } } From 188712a55bec61e2d0c2975c9026a88a9854c281 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 14:13:42 -0800 Subject: [PATCH 180/209] select a right-clicked item in asset browser --- interface/resources/qml/AssetServer.qml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index a1c2fc2398..82970011a0 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -379,6 +379,9 @@ Window { acceptedButtons: Qt.RightButton onClicked: { var index = treeView.indexAt(mouse.x, mouse.y); + + treeView.selection.setCurrentIndex(index, 0x0002); + contextMenu.currentIndex = index; contextMenu.popup(); } From 890266e0bdde2d1edf77bfb8691b9c9cf0f299de Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 15:45:44 -0800 Subject: [PATCH 181/209] shrink message dialog to contentWidth --- interface/resources/qml/dialogs/MessageDialog.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/dialogs/MessageDialog.qml b/interface/resources/qml/dialogs/MessageDialog.qml index 4a25c51012..4275428d31 100644 --- a/interface/resources/qml/dialogs/MessageDialog.qml +++ b/interface/resources/qml/dialogs/MessageDialog.qml @@ -72,7 +72,7 @@ ModalWindow { readonly property int maxHeight: 720 function resize() { - var targetWidth = mainTextContainer.width + var targetWidth = mainTextContainer.contentWidth var targetHeight = mainTextContainer.height + 3 * hifi.dimensions.contentSpacing.y + (informativeTextContainer.text != "" ? informativeTextContainer.contentHeight + 3 * hifi.dimensions.contentSpacing.y : 0) + buttons.height From 8375de451790fbf4e7c37d5b849a1f10d5d253bc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 17:32:24 -0800 Subject: [PATCH 182/209] make the ATPAssetMigrator hmd friendly and a little less brittle --- interface/src/assets/ATPAssetMigrator.cpp | 115 +++++++++----- interface/src/assets/ATPAssetMigrator.h | 7 +- interface/src/ui/AssetUploadDialogFactory.cpp | 143 ------------------ interface/src/ui/AssetUploadDialogFactory.h | 44 ------ 4 files changed, 85 insertions(+), 224 deletions(-) delete mode 100644 interface/src/ui/AssetUploadDialogFactory.cpp delete mode 100644 interface/src/ui/AssetUploadDialogFactory.h diff --git a/interface/src/assets/ATPAssetMigrator.cpp b/interface/src/assets/ATPAssetMigrator.cpp index e9327924a9..8da3c79999 100644 --- a/interface/src/assets/ATPAssetMigrator.cpp +++ b/interface/src/assets/ATPAssetMigrator.cpp @@ -24,9 +24,9 @@ #include #include #include +#include #include "OffscreenUi.h" -#include "../ui/AssetUploadDialogFactory.h" Q_DECLARE_LOGGING_CATEGORY(asset_migrator); Q_LOGGING_CATEGORY(asset_migrator, "hf.asset_migrator"); @@ -41,15 +41,14 @@ static const QString MODEL_URL_KEY = "modelURL"; static const QString MESSAGE_BOX_TITLE = "ATP Asset Migration"; void ATPAssetMigrator::loadEntityServerFile() { - auto filename = QFileDialog::getOpenFileName(_dialogParent, "Select an entity-server content file to migrate", - QString(), QString("Entity-Server Content (*.gz)")); + auto filename = OffscreenUi::getOpenFileName(_dialogParent, tr("Select an entity-server content file to migrate"), QString(), tr("Entity-Server Content (*.gz)")); if (!filename.isEmpty()) { qCDebug(asset_migrator) << "Selected filename for ATP asset migration: " << filename; static const QString MIGRATION_CONFIRMATION_TEXT { - "The ATP Asset Migration process will scan the selected entity-server file, upload discovered resources to the"\ - " current asset-server and then save a new entity-server file with the ATP URLs.\n\nAre you ready to"\ + "The ATP Asset Migration process will scan the selected entity-server file,\nupload discovered resources to the"\ + " current asset-server\nand then save a new entity-server file with the ATP URLs.\n\nAre you ready to"\ " continue?\n\nMake sure you are connected to the right domain." }; @@ -108,16 +107,17 @@ void ATPAssetMigrator::loadEntityServerFile() { if (request->getResult() == ResourceRequest::Success) { migrateResource(request); } else { - OffscreenUi::warning(_dialogParent, "Error", - QString("Could not retrieve asset at %1").arg(modelURL.toString())); + ++_errorCount; + _pendingReplacements.remove(modelURL); + qWarning() << "Could not retrieve asset at" << modelURL.toString(); } request->deleteLater(); }); request->send(); } else { - OffscreenUi::warning(_dialogParent, "Error", - QString("Could not create request for asset at %1").arg(modelURL.toString())); + ++_errorCount; + qWarning() << "Count not create request for asset at" << modelURL.toString(); } } else { @@ -140,8 +140,6 @@ void ATPAssetMigrator::migrateResource(ResourceRequest* request) { // use an asset client to upload the asset auto assetClient = DependencyManager::get(); - QFileInfo assetInfo { request->getUrl().fileName() }; - auto upload = assetClient->createUpload(request->getData()); // add this URL to our hash of AssetUpload to original URL @@ -157,41 +155,78 @@ void ATPAssetMigrator::migrateResource(ResourceRequest* request) { } void ATPAssetMigrator::assetUploadFinished(AssetUpload *upload, const QString& hash) { + // remove this modelURL from the key for the AssetUpload pointer + auto modelURL = _originalURLs.take(upload); + if (upload->getError() == AssetUpload::NoError) { - const auto& modelURL = _originalURLs[upload]; - + // use the path of the modelURL to add a mapping in the Asset Server + auto assetClient = DependencyManager::get(); + auto setMappingRequest = assetClient->createSetMappingRequest(modelURL.path(), hash); + + connect(setMappingRequest, &SetMappingRequest::finished, this, &ATPAssetMigrator::setMappingFinished); + + // add this modelURL with the key for the SetMappingRequest pointer + _originalURLs[setMappingRequest] = modelURL; + + setMappingRequest->start(); + } else { + // this is a fail for this modelURL, remove it from pending replacements + _pendingReplacements.remove(modelURL); + + ++_errorCount; + qWarning() << "Failed to upload" << modelURL << "- error was" << upload->getErrorString(); + } + + checkIfFinished(); + + upload->deleteLater(); +} + +void ATPAssetMigrator::setMappingFinished(SetMappingRequest* request) { + // take the modelURL for this SetMappingRequest + auto modelURL = _originalURLs.take(request); + + if (request->getError() == MappingRequest::NoError) { + // successfully uploaded asset - make any required replacements found in the pending replacements auto values = _pendingReplacements.values(modelURL); - - - QString atpURL = getATPUrl(hash).toString(); - + + QString atpURL = QString("atp:%1").arg(request->getPath()); + for (auto value : values) { // replace the modelURL in this QJsonValueRef with the hash QJsonObject valueObject = value.toObject(); valueObject[MODEL_URL_KEY] = atpURL; value = valueObject; } - + // add this URL to our list of uploaded assets _uploadedAssets.insert(modelURL, atpURL); - + // pull the replaced models from _pendingReplacements _pendingReplacements.remove(modelURL); - - // are we out of pending replacements? if so it is time to save the entity-server file - if (_doneReading && _pendingReplacements.empty()) { - saveEntityServerFile(); - - // reset after the attempted save, success or fail - reset(); - } } else { - AssetUploadDialogFactory::showErrorDialog(upload, _dialogParent); + // this is a fail for this modelURL, remove it from pending replacements + _pendingReplacements.remove(modelURL); + + ++_errorCount; + qWarning() << "Error setting mapping for" << modelURL << "- error was " << request->getErrorString(); + } + + checkIfFinished(); + + request->deleteLater(); +} + +void ATPAssetMigrator::checkIfFinished() { + // are we out of pending replacements? if so it is time to save the entity-server file + if (_doneReading && _pendingReplacements.empty()) { + saveEntityServerFile(); + + // reset after the attempted save, success or fail + reset(); } - - upload->deleteLater(); } bool ATPAssetMigrator::wantsToMigrateResource(const QUrl& url) { @@ -200,8 +235,8 @@ bool ATPAssetMigrator::wantsToMigrateResource(const QUrl& url) { if (!hasAskedForCompleteMigration) { // this is the first resource migration - ask the user if they just want to migrate everything - static const QString COMPLETE_MIGRATION_TEXT { "Do you want to migrate all assets found in this entity-server file?\n\n"\ - "Select \"Yes\" to upload all discovered assets to the current asset-server immediately.\n\n"\ + static const QString COMPLETE_MIGRATION_TEXT { "Do you want to migrate all assets found in this entity-server file?\n"\ + "Select \"Yes\" to upload all discovered assets to the current asset-server immediately.\n"\ "Select \"No\" to be prompted for each discovered asset." }; @@ -228,7 +263,7 @@ bool ATPAssetMigrator::wantsToMigrateResource(const QUrl& url) { void ATPAssetMigrator::saveEntityServerFile() { // show a dialog to ask the user where they want to save the file - QString saveName = QFileDialog::getSaveFileName(_dialogParent, "Save Migrated Entities File"); + QString saveName = OffscreenUi::getSaveFileName(_dialogParent, "Save Migrated Entities File"); QFile saveFile { saveName }; @@ -243,9 +278,16 @@ void ATPAssetMigrator::saveEntityServerFile() { saveFile.write(jsonDataForFile); saveFile.close(); - - QMessageBox::information(_dialogParent, "Success", - QString("Your new entities file has been saved at %1").arg(saveName)); + + QString infoMessage = QString("Your new entities file has been saved at\n%1.").arg(saveName); + + if (_errorCount > 0) { + infoMessage += QString("\nThere were %1 models that could not be migrated.\n").arg(_errorCount); + infoMessage += "Check the warnings in your log for details.\n"; + infoMessage += "You can re-attempt migration on those models\nby restarting this process with the newly saved file."; + } + + OffscreenUi::information(_dialogParent, "Success", infoMessage); } else { OffscreenUi::warning(_dialogParent, "Error", "Could not gzip JSON data for new entities file."); } @@ -263,4 +305,5 @@ void ATPAssetMigrator::reset() { _uploadedAssets.clear(); _originalURLs.clear(); _ignoredUrls.clear(); + _errorCount = 0; } diff --git a/interface/src/assets/ATPAssetMigrator.h b/interface/src/assets/ATPAssetMigrator.h index 454eb1eac1..8e20c5ab7a 100644 --- a/interface/src/assets/ATPAssetMigrator.h +++ b/interface/src/assets/ATPAssetMigrator.h @@ -21,6 +21,7 @@ class AssetUpload; class ResourceRequest; +class SetMappingRequest; class ATPAssetMigrator : public QObject { Q_OBJECT @@ -32,8 +33,11 @@ public slots: void loadEntityServerFile(); private slots: void assetUploadFinished(AssetUpload* upload, const QString& hash); + void setMappingFinished(SetMappingRequest* request); private: void migrateResource(ResourceRequest* request); + + void checkIfFinished(); void saveEntityServerFile(); void reset(); @@ -47,8 +51,9 @@ private: QMultiHash _pendingReplacements; QHash _uploadedAssets; - QHash _originalURLs; + QHash _originalURLs; QSet _ignoredUrls; + int _errorCount { 0 }; }; diff --git a/interface/src/ui/AssetUploadDialogFactory.cpp b/interface/src/ui/AssetUploadDialogFactory.cpp deleted file mode 100644 index 7b2da4c83b..0000000000 --- a/interface/src/ui/AssetUploadDialogFactory.cpp +++ /dev/null @@ -1,143 +0,0 @@ -// -// AssetUploadDialogFactory.cpp -// interface/src/ui -// -// Created by Stephen Birarda on 2015-08-26. -// Copyright 2015 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 "AssetUploadDialogFactory.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -AssetUploadDialogFactory& AssetUploadDialogFactory::getInstance() { - static AssetUploadDialogFactory staticInstance; - return staticInstance; -} - - - -void AssetUploadDialogFactory::showDialog() { - auto nodeList = DependencyManager::get(); - - if (nodeList->getThisNodeCanRez()) { - auto filename = QFileDialog::getOpenFileName(_dialogParent, "Select a file to upload"); - - if (!filename.isEmpty()) { - qDebug() << "Selected filename for upload to asset-server: " << filename; - - auto assetClient = DependencyManager::get(); - auto upload = assetClient->createUpload(filename); - - // connect to the finished signal so we know when the AssetUpload is done - QObject::connect(upload, &AssetUpload::finished, this, &AssetUploadDialogFactory::handleUploadFinished); - - // start the upload now - upload->start(); - } - } else { - // we don't have permission to upload to asset server in this domain - show the permission denied error - showErrorDialog(nullptr, _dialogParent, AssetUpload::PERMISSION_DENIED_ERROR); - } - -} - -void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const QString& hash) { - if (upload->getError() == AssetUpload::NoError) { - // show message box for successful upload, with copiable text for ATP hash - QDialog* hashCopyDialog = new QDialog(_dialogParent); - - // delete the dialog on close - hashCopyDialog->setAttribute(Qt::WA_DeleteOnClose); - - // set the window title - hashCopyDialog->setWindowTitle(tr("Successful Asset Upload")); - - // setup a layout for the contents of the dialog - QVBoxLayout* boxLayout = new QVBoxLayout; - - // set the label text (this shows above the text box) - QLabel* lineEditLabel = new QLabel; - lineEditLabel->setText(QString("ATP URL for %1").arg(QFileInfo(upload->getFilename()).fileName())); - - // setup the line edit to hold the copiable text - QLineEdit* lineEdit = new QLineEdit; - - QString atpURL = QString("%1:%2").arg(URL_SCHEME_ATP).arg(hash); - - // set the ATP URL as the text value so it's copiable - lineEdit->insert(atpURL); - - // figure out what size this line edit should be using font metrics - QFontMetrics textMetrics { lineEdit->font() }; - - // set the fixed width on the line edit - // pad it by 10 to cover the border and some extra space on the right side (for clicking) - static const int LINE_EDIT_RIGHT_PADDING { 10 }; - - lineEdit->setFixedWidth(textMetrics.width(atpURL) + LINE_EDIT_RIGHT_PADDING ); - - // left align the ATP URL line edit - lineEdit->home(true); - - // add the label and line edit to the dialog - boxLayout->addWidget(lineEditLabel); - boxLayout->addWidget(lineEdit); - - // setup an OK button to close the dialog - QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); - connect(buttonBox, &QDialogButtonBox::accepted, hashCopyDialog, &QDialog::close); - boxLayout->addWidget(buttonBox); - - // set the new layout on the dialog - hashCopyDialog->setLayout(boxLayout); - - // show the new dialog - hashCopyDialog->show(); - } else { - // display a message box with the error - showErrorDialog(upload, _dialogParent); - } - - upload->deleteLater(); -} - -void AssetUploadDialogFactory::showErrorDialog(AssetUpload* upload, QWidget* dialogParent, const QString& overrideMessage) { - QString filename; - - if (upload) { - filename = QFileInfo { upload->getFilename() }.fileName(); - } - - QString errorMessage = overrideMessage; - - if (errorMessage.isEmpty() && upload) { - errorMessage = upload->getErrorString(); - } - - QString dialogMessage; - - if (upload) { - dialogMessage += QString("Failed to upload %1.\n\n").arg(filename); - } - - dialogMessage += errorMessage; - - OffscreenUi::warning(dialogParent, "Failed Upload", dialogMessage); -} diff --git a/interface/src/ui/AssetUploadDialogFactory.h b/interface/src/ui/AssetUploadDialogFactory.h deleted file mode 100644 index fe3ecf5dc4..0000000000 --- a/interface/src/ui/AssetUploadDialogFactory.h +++ /dev/null @@ -1,44 +0,0 @@ -// -// AssetUploadDialogFactory.h -// interface/src/ui -// -// Created by Stephen Birarda on 2015-08-26. -// Copyright 2015 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_AssetUploadDialogFactory_h -#define hifi_AssetUploadDialogFactory_h - -#include - -class AssetUpload; - -class AssetUploadDialogFactory : public QObject { - Q_OBJECT -public: - AssetUploadDialogFactory(const AssetUploadDialogFactory& other) = delete; - AssetUploadDialogFactory& operator=(const AssetUploadDialogFactory& rhs) = delete; - - static AssetUploadDialogFactory& getInstance(); - static void showErrorDialog(AssetUpload* upload, QWidget* dialogParent, const QString& overrideMessage = QString()); - - void setDialogParent(QWidget* dialogParent) { _dialogParent = dialogParent; } - -public slots: - void showDialog(); - void handleUploadFinished(AssetUpload* upload, const QString& hash); - -private: - AssetUploadDialogFactory() = default; - - - - QWidget* _dialogParent { nullptr }; -}; - -#endif // hifi_AssetUploadDialogFactory_h From 76e547498d8e356d0a81169b5c8f09733d19e612 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 18:02:06 -0800 Subject: [PATCH 183/209] support compound shape URLs in ATPAssetMigrator --- interface/src/assets/ATPAssetMigrator.cpp | 150 +++++++++++++--------- interface/src/assets/ATPAssetMigrator.h | 6 +- 2 files changed, 91 insertions(+), 65 deletions(-) diff --git a/interface/src/assets/ATPAssetMigrator.cpp b/interface/src/assets/ATPAssetMigrator.cpp index 8da3c79999..e0e9d5a73a 100644 --- a/interface/src/assets/ATPAssetMigrator.cpp +++ b/interface/src/assets/ATPAssetMigrator.cpp @@ -38,6 +38,7 @@ ATPAssetMigrator& ATPAssetMigrator::getInstance() { static const QString ENTITIES_OBJECT_KEY = "Entities"; static const QString MODEL_URL_KEY = "modelURL"; +static const QString COMPOUND_SHAPE_URL_KEY = "compoundShapeURL"; static const QString MESSAGE_BOX_TITLE = "ATP Asset Migration"; void ATPAssetMigrator::loadEntityServerFile() { @@ -76,58 +77,75 @@ void ATPAssetMigrator::loadEntityServerFile() { for (auto jsonValue : _entitiesArray) { QJsonObject entityObject = jsonValue.toObject(); QString modelURLString = entityObject.value(MODEL_URL_KEY).toString(); - - if (!modelURLString.isEmpty()) { - QUrl modelURL = QUrl(modelURLString); - - if (!_ignoredUrls.contains(modelURL) - && (modelURL.scheme() == URL_SCHEME_HTTP || modelURL.scheme() == URL_SCHEME_HTTPS - || modelURL.scheme() == URL_SCHEME_FILE || modelURL.scheme() == URL_SCHEME_FTP)) { - - if (_pendingReplacements.contains(modelURL)) { - // we already have a request out for this asset, just store the QJsonValueRef - // so we can do the hash replacement when the request comes back - _pendingReplacements.insert(modelURL, jsonValue); - } else if (_uploadedAssets.contains(modelURL)) { - // we already have a hash for this asset - // so just do the replacement immediately - entityObject[MODEL_URL_KEY] = _uploadedAssets.value(modelURL).toString(); - jsonValue = entityObject; - } else if (wantsToMigrateResource(modelURL)) { - auto request = ResourceManager::createResourceRequest(this, modelURL); - - if (request) { - qCDebug(asset_migrator) << "Requesting" << modelURL << "for ATP asset migration"; - - // add this combination of QUrl and QJsonValueRef to our multi hash so we can change the URL - // to an ATP one once ready - _pendingReplacements.insert(modelURL, jsonValue); - - connect(request, &ResourceRequest::finished, this, [=]() { - if (request->getResult() == ResourceRequest::Success) { - migrateResource(request); + QString compoundURLString = entityObject.value(COMPOUND_SHAPE_URL_KEY).toString(); + + for (int i = 0; i < 2; ++i) { + bool isModelURL = (i == 0); + quint8 replacementType = i; + auto migrationURLString = (isModelURL) ? modelURLString : compoundURLString; + + if (!migrationURLString.isEmpty()) { + QUrl migrationURL = QUrl(migrationURLString); + + if (!_ignoredUrls.contains(migrationURL) + && (migrationURL.scheme() == URL_SCHEME_HTTP || migrationURL.scheme() == URL_SCHEME_HTTPS + || migrationURL.scheme() == URL_SCHEME_FILE || migrationURL.scheme() == URL_SCHEME_FTP)) { + + if (_pendingReplacements.contains(migrationURL)) { + // we already have a request out for this asset, just store the QJsonValueRef + // so we can do the hash replacement when the request comes back + _pendingReplacements.insert(migrationURL, { jsonValue, replacementType }); + } else if (_uploadedAssets.contains(migrationURL)) { + // we already have a hash for this asset + // so just do the replacement immediately + if (isModelURL) { + entityObject[MODEL_URL_KEY] = _uploadedAssets.value(migrationURL).toString(); + } else { + entityObject[COMPOUND_SHAPE_URL_KEY] = _uploadedAssets.value(migrationURL).toString(); + } + + jsonValue = entityObject; + } else if (wantsToMigrateResource(migrationURL)) { + auto request = ResourceManager::createResourceRequest(this, migrationURL); + + if (request) { + qCDebug(asset_migrator) << "Requesting" << migrationURL << "for ATP asset migration"; + + // add this combination of QUrl and QJsonValueRef to our multi hash so we can change the URL + // to an ATP one once ready + _pendingReplacements.insert(migrationURL, { jsonValue, (isModelURL ? 0 : 1)}); + + connect(request, &ResourceRequest::finished, this, [=]() { + if (request->getResult() == ResourceRequest::Success) { + migrateResource(request); + } else { + ++_errorCount; + _pendingReplacements.remove(migrationURL); + qWarning() << "Could not retrieve asset at" << migrationURL.toString(); + + checkIfFinished(); + } + request->deleteLater(); + }); + + request->send(); } else { ++_errorCount; - _pendingReplacements.remove(modelURL); - qWarning() << "Could not retrieve asset at" << modelURL.toString(); + qWarning() << "Count not create request for asset at" << migrationURL.toString(); } - request->deleteLater(); - }); - - request->send(); - } else { - ++_errorCount; - qWarning() << "Count not create request for asset at" << modelURL.toString(); + + } else { + _ignoredUrls.insert(migrationURL); + } } - - } else { - _ignoredUrls.insert(modelURL); - } } } + } _doneReading = true; + + checkIfFinished(); } else { OffscreenUi::warning(_dialogParent, "Error", @@ -155,27 +173,27 @@ void ATPAssetMigrator::migrateResource(ResourceRequest* request) { } void ATPAssetMigrator::assetUploadFinished(AssetUpload *upload, const QString& hash) { - // remove this modelURL from the key for the AssetUpload pointer - auto modelURL = _originalURLs.take(upload); + // remove this migrationURL from the key for the AssetUpload pointer + auto migrationURL = _originalURLs.take(upload); if (upload->getError() == AssetUpload::NoError) { - // use the path of the modelURL to add a mapping in the Asset Server + // use the path of the migrationURL to add a mapping in the Asset Server auto assetClient = DependencyManager::get(); - auto setMappingRequest = assetClient->createSetMappingRequest(modelURL.path(), hash); + auto setMappingRequest = assetClient->createSetMappingRequest(migrationURL.path(), hash); connect(setMappingRequest, &SetMappingRequest::finished, this, &ATPAssetMigrator::setMappingFinished); - // add this modelURL with the key for the SetMappingRequest pointer - _originalURLs[setMappingRequest] = modelURL; + // add this migrationURL with the key for the SetMappingRequest pointer + _originalURLs[setMappingRequest] = migrationURL; setMappingRequest->start(); } else { // this is a fail for this modelURL, remove it from pending replacements - _pendingReplacements.remove(modelURL); + _pendingReplacements.remove(migrationURL); ++_errorCount; - qWarning() << "Failed to upload" << modelURL << "- error was" << upload->getErrorString(); + qWarning() << "Failed to upload" << migrationURL << "- error was" << upload->getErrorString(); } checkIfFinished(); @@ -184,34 +202,40 @@ void ATPAssetMigrator::assetUploadFinished(AssetUpload *upload, const QString& h } void ATPAssetMigrator::setMappingFinished(SetMappingRequest* request) { - // take the modelURL for this SetMappingRequest - auto modelURL = _originalURLs.take(request); + // take the migrationURL for this SetMappingRequest + auto migrationURL = _originalURLs.take(request); if (request->getError() == MappingRequest::NoError) { // successfully uploaded asset - make any required replacements found in the pending replacements - auto values = _pendingReplacements.values(modelURL); + auto values = _pendingReplacements.values(migrationURL); QString atpURL = QString("atp:%1").arg(request->getPath()); for (auto value : values) { // replace the modelURL in this QJsonValueRef with the hash - QJsonObject valueObject = value.toObject(); - valueObject[MODEL_URL_KEY] = atpURL; - value = valueObject; + QJsonObject valueObject = value.first.toObject(); + + if (value.second == 0) { + valueObject[MODEL_URL_KEY] = atpURL; + } else { + valueObject[COMPOUND_SHAPE_URL_KEY] = atpURL; + } + + value.first = valueObject; } // add this URL to our list of uploaded assets - _uploadedAssets.insert(modelURL, atpURL); + _uploadedAssets.insert(migrationURL, atpURL); - // pull the replaced models from _pendingReplacements - _pendingReplacements.remove(modelURL); + // pull the replaced urls from _pendingReplacements + _pendingReplacements.remove(migrationURL); } else { - // this is a fail for this modelURL, remove it from pending replacements - _pendingReplacements.remove(modelURL); + // this is a fail for this migrationURL, remove it from pending replacements + _pendingReplacements.remove(migrationURL); ++_errorCount; - qWarning() << "Error setting mapping for" << modelURL << "- error was " << request->getErrorString(); + qWarning() << "Error setting mapping for" << migrationURL << "- error was " << request->getErrorString(); } checkIfFinished(); diff --git a/interface/src/assets/ATPAssetMigrator.h b/interface/src/assets/ATPAssetMigrator.h index 8e20c5ab7a..c1becb9c7f 100644 --- a/interface/src/assets/ATPAssetMigrator.h +++ b/interface/src/assets/ATPAssetMigrator.h @@ -48,8 +48,10 @@ private: QJsonArray _entitiesArray; bool _doneReading { false }; - - QMultiHash _pendingReplacements; + + using JSONTypePair = std::pair; + + QMultiHash> _pendingReplacements; QHash _uploadedAssets; QHash _originalURLs; QSet _ignoredUrls; From 3cf32b17be236a22ca0b672ccc48e0e64527daa2 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 11 Mar 2016 18:52:02 -0800 Subject: [PATCH 184/209] Trying to fix the jittering issue, foound an extra matrix inversion that could be the source --- libraries/gpu/src/gpu/Context.cpp | 18 ++++--- libraries/gpu/src/gpu/Context.h | 6 +-- libraries/gpu/src/gpu/GLBackendTransform.cpp | 5 +- libraries/gpu/src/gpu/Transform.slh | 54 +++++++++++--------- 4 files changed, 48 insertions(+), 35 deletions(-) diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index e1dc94fcd7..013433102a 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -74,9 +74,11 @@ void Context::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, cons _backend->downloadFramebuffer(srcFramebuffer, region, destImage); } -const Backend::TransformCamera& Backend::TransformCamera::recomputeDerived() const { +const Backend::TransformCamera& Backend::TransformCamera::recomputeDerived(const Transform& xformView) const { _projectionInverse = glm::inverse(_projection); - _viewInverse = glm::inverse(_view); + // _viewInverse = glm::inverse(_view); + xformView.getMatrix(_viewInverse); + _view = glm::inverse(_viewInverse); Mat4 viewUntranslated = _view; viewUntranslated[3] = Vec4(0.0f, 0.0f, 0.0f, 1.0f); @@ -84,16 +86,18 @@ const Backend::TransformCamera& Backend::TransformCamera::recomputeDerived() con return *this; } -Backend::TransformCamera Backend::TransformCamera::getEyeCamera(int eye, const StereoState& _stereo) const { +Backend::TransformCamera Backend::TransformCamera::getEyeCamera(int eye, const StereoState& _stereo, const Transform& xformView) const { TransformCamera result = *this; + Transform offsetTransform = xformView; if (!_stereo._skybox) { result._view = _stereo._eyeViews[eye] * result._view; + offsetTransform.postTranslate(-Vec3(_stereo._eyeViews[eye][3])); } else { - glm::mat4 skyboxView = _stereo._eyeViews[eye]; - skyboxView[3] = vec4(0, 0, 0, 1); - result._view = skyboxView * result._view; + // glm::mat4 skyboxView = _stereo._eyeViews[eye]; + // skyboxView[3] = vec4(0, 0, 0, 1); + // result._view = skyboxView * result._view; } result._projection = _stereo._eyeProjections[eye]; - result.recomputeDerived(); + result.recomputeDerived(xformView); return result; } diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index dceb606f20..d584f54acc 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -79,15 +79,15 @@ public: // UBO class... layout MUST match the layout in TransformCamera.slh class TransformCamera { public: - Mat4 _view; + mutable Mat4 _view; mutable Mat4 _viewInverse; mutable Mat4 _projectionViewUntranslated; Mat4 _projection; mutable Mat4 _projectionInverse; Vec4 _viewport; // Public value is int but float in the shader to stay in floats for all the transform computations. - const Backend::TransformCamera& recomputeDerived() const; - TransformCamera getEyeCamera(int eye, const StereoState& stereo) const; + const Backend::TransformCamera& recomputeDerived(const Transform& xformView) const; + TransformCamera getEyeCamera(int eye, const StereoState& stereo, const Transform& xformView) const; }; diff --git a/libraries/gpu/src/gpu/GLBackendTransform.cpp b/libraries/gpu/src/gpu/GLBackendTransform.cpp index d5bcfa3321..19cb7fb2a9 100755 --- a/libraries/gpu/src/gpu/GLBackendTransform.cpp +++ b/libraries/gpu/src/gpu/GLBackendTransform.cpp @@ -105,6 +105,7 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo } if (_invalidView) { + // This is when the _view matrix gets assigned _view.getInverseMatrix(_camera._view); } @@ -113,11 +114,11 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo if (stereo._enable) { _cameraOffsets.push_back(TransformStageState::Pair(commandIndex, offset)); for (int i = 0; i < 2; ++i) { - _cameras.push_back(_camera.getEyeCamera(i, stereo)); + _cameras.push_back(_camera.getEyeCamera(i, stereo, _view)); } } else { _cameraOffsets.push_back(TransformStageState::Pair(commandIndex, offset)); - _cameras.push_back(_camera.recomputeDerived()); + _cameras.push_back(_camera.recomputeDerived(_view)); } } diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index ea5ee06a7b..e4f8f5dd87 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -76,24 +76,40 @@ TransformObject getTransformObject() { <$viewport$> = <$cameraTransform$>._viewport; <@endfunc@> -<@func transformModelToClipPos(cameraTransform, objectTransform, modelPos, clipPos)@> - - { // transformModelToClipPos - vec4 _eyepos = (<$objectTransform$>._model * <$modelPos$>) + vec4(-<$modelPos$>.w * <$cameraTransform$>._viewInverse[3].xyz, 0.0); - <$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * _eyepos; +<@func transformModelToEyeWorldAlignedPos(cameraTransform, objectTransform, modelPos, eyeWorldAlignedPos)@> + + { // _transformModelToEyeWorldAlignedPos + highp mat4 _mv = <$objectTransform$>._model; + _mv[3].xyz -= <$cameraTransform$>._viewInverse[3].xyz; + highp vec4 _eyeWApos = (_mv * <$modelPos$>); + <$eyeWorldAlignedPos$> = _eyeWApos; } <@endfunc@> -<@func $transformModelToEyeAndClipPos(cameraTransform, objectTransform, modelPos, eyePos, clipPos)@> - +<@func transformModelToClipPos(cameraTransform, objectTransform, modelPos, clipPos)@> { // transformModelToClipPos - vec4 _worldpos = (<$objectTransform$>._model * <$modelPos$>); - <$eyePos$> = (<$cameraTransform$>._view * _worldpos); - vec4 _eyepos =(<$objectTransform$>._model * <$modelPos$>) + vec4(-<$modelPos$>.w * <$cameraTransform$>._viewInverse[3].xyz, 0.0); - <$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * _eyepos; - // <$eyePos$> = (<$cameraTransform$>._projectionInverse * <$clipPos$>); + vec4 eyeWAPos; + <$transformModelToEyeWorldAlignedPos($cameraTransform$, $objectTransform$, $modelPos$, eyeWAPos)$> + + <$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * eyeWAPos; + } +<@endfunc@> + +<@func transformModelToEyeAndClipPos(cameraTransform, objectTransform, modelPos, eyePos, clipPos)@> + { // transformModelToEyeAndClipPos + vec4 eyeWAPos; + <$transformModelToEyeWorldAlignedPos($cameraTransform$, $objectTransform$, $modelPos$, eyeWAPos)$> + + <$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * eyeWAPos; + <$eyePos$> = vec4((<$cameraTransform$>._view * vec4(eyeWAPos.xyz, 0.0)).xyz, 1.0); + } +<@endfunc@> + +<@func transformModelToEyePos(cameraTransform, objectTransform, modelPos, eyePos)@> + { // transformModelToEyePos + vec4 eyeWAPos; + <$transformModelToEyeWorldAlignedPos($cameraTransform$, $objectTransform$, $modelPos$, eyeWAPos)$> + <$eyePos$> = vec4((<$cameraTransform$>._view * vec4(eyeWAPos.xyz, 0.0)).xyz, 1.0); } <@endfunc@> @@ -103,6 +119,7 @@ TransformObject getTransformObject() { } <@endfunc@> + <@func transformModelToEyeDir(cameraTransform, objectTransform, modelDir, eyeDir)@> { // transformModelToEyeDir vec3 mr0 = vec3(<$objectTransform$>._modelInverse[0].x, <$objectTransform$>._modelInverse[1].x, <$objectTransform$>._modelInverse[2].x); @@ -129,15 +146,6 @@ TransformObject getTransformObject() { } <@endfunc@> -<@func $transformModelToEyePos(cameraTransform, objectTransform, modelPos, eyePos)@> - - { // transformModelToEyePos - vec4 _worldpos = (<$objectTransform$>._model * vec4(<$modelPos$>.xyz, 1.0)); - <$eyePos$> = (<$cameraTransform$>._view * _worldpos); - } -<@endfunc@> - <@func transformEyeToClipPos(cameraTransform, eyePos, clipPos)@> { // transformEyeToClipPos <$clipPos$> = <$cameraTransform$>._projection * vec4(<$eyePos$>.xyz, 1.0); From 6c27bd9eb26042e9ca1443e5a3707218597a01cd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Sun, 13 Mar 2016 21:04:07 -0700 Subject: [PATCH 185/209] Update upload flow and make asset list dynamically sized --- interface/resources/qml/AssetServer.qml | 230 ++++++++++-------- .../AssetMappingsScriptingInterface.cpp | 19 +- .../AssetMappingsScriptingInterface.h | 2 +- 3 files changed, 139 insertions(+), 112 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index c5ebb04819..3ed562f59a 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -36,7 +36,6 @@ Window { property var assetProxyModel: Assets.proxyModel; property var assetMappingsModel: Assets.mappingModel; property var currentDirectory; - property alias currentFileUrl: fileUrlTextField.text; Settings { category: "Overlay.AssetServer" @@ -46,8 +45,8 @@ Window { } Component.onCompleted: { - assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError) - reload() + assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError); + reload(); } function doDeleteFile(path) { @@ -220,47 +219,69 @@ Window { }); } - function chooseClicked() { - var browser = desktop.fileDialog({ - selectDirectory: false, - dir: currentDirectory - }); - browser.selectedFile.connect(function(url){ - fileUrlTextField.text = fileDialogHelper.urlToPath(url); - currentDirectory = browser.dir; - }); - } property var uploadOpen: false; + Timer { + id: timer + } function uploadClicked() { if (uploadOpen) { return; } uploadOpen = true; - var fileUrl = fileUrlTextField.text - var shouldAddToWorld = addToWorldCheckBox.checked + var fileUrl = ""; - var path = assetProxyModel.data(treeView.selection.currentIndex, 0x100); - var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/"; - var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); - - Assets.uploadFile(fileUrl, directory + filename, function(err, path) { - if (err) { - console.log("Asset Browser - error uploading: ", fileUrl, " - error ", err); - var box = errorMessage("There was an error uploading:\n" + fileUrl + "\n" + Assets.getErrorString(err)); - box.selected.connect(reload); - } else { - console.log("Asset Browser - finished uploading: ", fileUrl); - - if (shouldAddToWorld) { - addToWorld("atp:" + path); - } - - reload(); - } + var browser = desktop.fileDialog({ + selectDirectory: false, + dir: currentDirectory + }); + browser.canceled.connect(function() { + uploadOpen = false; + }); + browser.selectedFile.connect(function(url){ + var fileUrl = fileDialogHelper.urlToPath(url); + currentDirectory = browser.dir; + + //var fileUrl = fileUrlTextField.text + + var path = assetProxyModel.data(treeView.selection.currentIndex, 0x100); + var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/"; + var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); + + Assets.uploadFile(fileUrl, directory + filename, + function() { + // Upload started + uploadSpinner.visible = true; + uploadButton.enabled = false; + uploadProgressLabel.text = "In progress..."; + }, + function(err, path) { + print(err, path); + if (!err) { + uploadProgressLabel.text = "Upload Complete"; + timer.interval = 1000; + timer.repeat = false; + timer.triggered.connect(function() { + uploadSpinner.visible = false; + uploadButton.enabled = true; + uploadOpen = false; + }); + timer.start(); + console.log("Asset Browser - finished uploading: ", fileUrl); + reload(); + } else { + if (err > 0) { + console.log("Asset Browser - error uploading: ", fileUrl, " - error ", err); + var box = errorMessage("There was an error uploading:\n" + fileUrl + "\n" + Assets.getErrorString(err)); + box.selected.connect(reload); + } + uploadSpinner.visible = false; + uploadButton.enabled = true; + uploadOpen = false; + } + }) }); - uploadOpen = false; } function errorMessageBox(message) { @@ -272,8 +293,9 @@ Window { }); } - Column { + Item { width: pane.contentWidth + height: pane.height HifiControls.ContentSection { id: assetDirectory @@ -359,99 +381,95 @@ Window { } } } + } - HifiControls.Tree { - id: treeView - height: 400 - treeModel: assetProxyModel - colorScheme: root.colorScheme - anchors.left: parent.left - anchors.right: parent.right - MouseArea { - propagateComposedEvents: true - anchors.fill: parent - acceptedButtons: Qt.RightButton - onClicked: { - var index = treeView.indexAt(mouse.x, mouse.y); - contextMenu.currentIndex = index; - contextMenu.popup(); - } + HifiControls.Tree { + id: treeView + anchors.top: assetDirectory.bottom + anchors.bottom: uploadSection.top + anchors.margins: 12 + anchors.bottomMargin: 0 + treeModel: assetProxyModel + colorScheme: root.colorScheme + anchors.left: parent.left + anchors.right: parent.right + MouseArea { + propagateComposedEvents: true + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: { + print("onClicked"); + var index = treeView.indexAt(mouse.x, mouse.y); + print("onClicked", assetProxyModel.data(index, 0x0100)); + treeView.selection.select(index, 0x0001 | 0x0002 | 0x0010 | 0x0020); + print("done"); + //contextMenu.currentIndex = index; + //treeView.selection.clearSelection() + //treeView.selection.clear(); + //contextMenu.popup(); } } } - HifiControls.ContentSection { id: uploadSection - name: "" + name: "Upload A File" spacing: hifi.dimensions.contentSpacing.y - - HifiControls.TextField { - id: fileUrlTextField - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: chooseButton.width + hifi.dimensions.contentSpacing.x - - label: "Upload File" - placeholderText: "Paste URL or choose file" - colorScheme: root.colorScheme - } + anchors.bottom: parent.bottom + height: 130 Item { - // Take the chooseButton out of the column flow. - id: chooseButtonContainer - anchors.top: fileUrlTextField.top - anchors.right: parent.right - - HifiControls.Button { - id: chooseButton - anchors.right: parent.right - - text: "Choose" - color: hifi.buttons.white - colorScheme: root.colorScheme - enabled: true - - width: 100 - - onClicked: root.chooseClicked() - } - } - - HifiControls.CheckBox { - id: addToWorldCheckBox - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: uploadButton.width + hifi.dimensions.contentSpacing.x - - text: "Add to world on upload" - - opacity: canAddToWorld(fileUrlTextField.text) ? 1 : 0 - - checked: false - } - - Item { - // Take the uploadButton out of the column flow. - id: uploadButtonContainer - anchors.top: addToWorldCheckBox.top - anchors.right: parent.right - + height: parent.height + width: parent.width HifiControls.Button { id: uploadButton anchors.right: parent.right - text: "Upload" + text: "Choose File" color: hifi.buttons.blue colorScheme: root.colorScheme height: 30 width: 155 - enabled: fileUrlTextField.text != "" onClicked: root.uploadClicked() } + + Item { + id: uploadSpinner + visible: false + anchors.top: parent.top + anchors.left: parent.left + width: 40 + height: 32 + + Image { + id: image + width: 24 + height: 24 + source: "../images/Loading-Outer-Ring.png" + RotationAnimation on rotation { + loops: Animation.Infinite + from: 0 + to: 360 + duration: 2000 + } + } + Image { + width: 24 + height: 24 + source: "../images/Loading-Inner-H.png" + } + HifiControls.Label { + id: uploadProgressLabel + anchors.left: image.right + anchors.leftMargin: 10 + anchors.verticalCenter: image.verticalCenter + text: "In progress..." + colorScheme: root.colorScheme + } + + } } - HifiControls.VerticalSpacer {} } } } diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 32b697459c..0a2a12ee24 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -80,11 +80,16 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback request->start(); } -void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue callback) { +void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue startedCallback, QJSValue completedCallback) { + static const QString helpText = + "Upload your asset to a specific folder by enter the full path. Specifying " + "a new folder name will automatically create that folder for you."; + auto offscreenUi = DependencyManager::get(); - auto result = offscreenUi->inputDialog(OffscreenUi::ICON_NONE, "Enter asset path:", "", mapping); + auto result = offscreenUi->inputDialog(OffscreenUi::ICON_INFORMATION, "Specify Asset Path", helpText, mapping); if (!result.isValid()) { + completedCallback.call({ -1 }); return; } mapping = result.toString(); @@ -100,19 +105,22 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, auto button = offscreenUi->messageBox(OffscreenUi::ICON_QUESTION, "Overwrite File", message, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (button == QMessageBox::No) { + completedCallback.call({ -1 }); return; } } + startedCallback.call(); + auto upload = DependencyManager::get()->createUpload(path); QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { if (upload->getError() != AssetUpload::NoError) { - if (callback.isCallable()) { + if (completedCallback.isCallable()) { QJSValueList args { uint8_t(upload->getError()) }; - callback.call(args); + completedCallback.call(args); } } else { - setMapping(mapping, hash, callback); + setMapping(mapping, hash, completedCallback); } upload->deleteLater(); @@ -198,6 +206,7 @@ AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, } + static int assetMappingModelMetatypeId = qRegisterMetaType("AssetMappingModel*"); void AssetMappingModel::refresh() { diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index 35a1c1ae7e..5465901ed4 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -64,7 +64,7 @@ public: Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback = QJSValue()); Q_INVOKABLE void getMapping(QString path, QJSValue callback = QJSValue()); - Q_INVOKABLE void uploadFile(QString path, QString mapping, QJSValue callback = QJSValue()); + Q_INVOKABLE void uploadFile(QString path, QString mapping, QJSValue startedCallback = QJSValue(), QJSValue completedCallback = QJSValue()); Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); Q_INVOKABLE void deleteMapping(QString path, QJSValue callback) { deleteMappings(QStringList(path), callback = QJSValue()); } Q_INVOKABLE void getAllMappings(QJSValue callback = QJSValue()); From 960047f4127ac15fbbec04f2febd790474c65d93 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Sun, 13 Mar 2016 21:06:52 -0700 Subject: [PATCH 186/209] Remove right click selection --- interface/resources/qml/AssetServer.qml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 3ed562f59a..b6d86b17fd 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -398,15 +398,9 @@ Window { anchors.fill: parent acceptedButtons: Qt.RightButton onClicked: { - print("onClicked"); var index = treeView.indexAt(mouse.x, mouse.y); - print("onClicked", assetProxyModel.data(index, 0x0100)); - treeView.selection.select(index, 0x0001 | 0x0002 | 0x0010 | 0x0020); - print("done"); - //contextMenu.currentIndex = index; - //treeView.selection.clearSelection() - //treeView.selection.clear(); - //contextMenu.popup(); + contextMenu.currentIndex = index; + contextMenu.popup(); } } } From a7f21d5fceab614f2f5c236d0cf47c0dd03859af Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 14 Mar 2016 10:36:19 -0700 Subject: [PATCH 187/209] Clena up comments, ready to PR --- libraries/gpu/src/gpu/Context.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index 013433102a..46c07e4265 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -76,7 +76,10 @@ void Context::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, cons const Backend::TransformCamera& Backend::TransformCamera::recomputeDerived(const Transform& xformView) const { _projectionInverse = glm::inverse(_projection); - // _viewInverse = glm::inverse(_view); + + // Get the viewEyeToWorld matrix form the transformView as passed to the gpu::Batch + // this is the "_viewInverse" fed to the shader + // Genetrate the "_view" matrix as wekll forom the xform xformView.getMatrix(_viewInverse); _view = glm::inverse(_viewInverse); @@ -90,12 +93,9 @@ Backend::TransformCamera Backend::TransformCamera::getEyeCamera(int eye, const S TransformCamera result = *this; Transform offsetTransform = xformView; if (!_stereo._skybox) { - result._view = _stereo._eyeViews[eye] * result._view; offsetTransform.postTranslate(-Vec3(_stereo._eyeViews[eye][3])); } else { - // glm::mat4 skyboxView = _stereo._eyeViews[eye]; - // skyboxView[3] = vec4(0, 0, 0, 1); - // result._view = skyboxView * result._view; + // FIXME: If "skybox" the ipd is set to 0 for now, let s try to propose a better solution for this in the future } result._projection = _stereo._eyeProjections[eye]; result.recomputeDerived(xformView); From fbc19ec74fde27f3de2aed0c89866581927a2f96 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 14 Mar 2016 12:11:17 -0700 Subject: [PATCH 188/209] Back to the previous comuputation for the eye position in the hope to fix local lighting in stereo --- libraries/gpu/src/gpu/Transform.slh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index e4f8f5dd87..5881b18066 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -101,7 +101,10 @@ TransformObject getTransformObject() { <$transformModelToEyeWorldAlignedPos($cameraTransform$, $objectTransform$, $modelPos$, eyeWAPos)$> <$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * eyeWAPos; - <$eyePos$> = vec4((<$cameraTransform$>._view * vec4(eyeWAPos.xyz, 0.0)).xyz, 1.0); + vec4 _worldpos = (<$objectTransform$>._model * <$modelPos$>); + <$eyePos$> = (<$cameraTransform$>._view * _worldpos); + = vec4((<$cameraTransform$>._view * vec4(eyeWAPos.xyz, 0.0)).xyz, 1.0); !> } <@endfunc@> From 7823882aa16ad1c11265fd282cffe6bf166f25e2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 14 Mar 2016 16:13:33 -0700 Subject: [PATCH 189/209] Add atp filename to entities added to world --- interface/resources/qml/AssetServer.qml | 12 ++++++------ libraries/entities/src/EntityScriptingInterface.cpp | 3 ++- libraries/entities/src/EntityScriptingInterface.h | 3 ++- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 82970011a0..17e6214a26 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -137,19 +137,19 @@ Window { ); } - function addToWorld(url) { - if (!url) { - url = assetProxyModel.data(treeView.selection.currentIndex, 0x103); - } + function addToWorld() { + var url = assetProxyModel.data(treeView.selection.currentIndex, 0x103); if (!url || !canAddToWorld(url)) { return; } - console.log("Asset browser - adding asset " + url + " to world."); + var name = assetProxyModel.data(treeView.selection.currentIndex); + + console.log("Asset browser - adding asset " + url + " (" + name + ") to world."); var addPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(MyAvatar.orientation))); - Entities.addModelEntity(url, addPosition); + Entities.addModelEntity(name, url, addPosition); } function copyURLToClipboard(index) { diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 44da37b0c1..ae538b26c7 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -178,9 +178,10 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties return id; } -QUuid EntityScriptingInterface::addModelEntity(const QString& modelUrl, const glm::vec3& position) { +QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QString& modelUrl, const glm::vec3& position) { EntityItemProperties properties; properties.setType(EntityTypes::Model); + properties.setName(name); properties.setModelURL(modelUrl); properties.setPosition(position); return addEntity(properties); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index fda2aa7e59..b65bc55dbb 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -84,7 +84,8 @@ public slots: /// adds a model with the specific properties Q_INVOKABLE QUuid addEntity(const EntityItemProperties& properties); - Q_INVOKABLE QUuid addModelEntity(const QString& modelUrl, const glm::vec3& position); + /// temporary method until addEntity can be used from QJSEngine + Q_INVOKABLE QUuid addModelEntity(const QString& name, const QString& modelUrl, const glm::vec3& position); /// gets the current model properties for a specific model /// this function will not find return results in script engine contexts which don't have access to models From 5ab21588f23180a32ae75656c7890be2dd7aee24 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 14 Mar 2016 14:42:11 -0700 Subject: [PATCH 190/209] Add gpu timer to background --- .../render-utils/src/RenderDeferredTask.cpp | 4 ++++ .../render-utils/src/RenderDeferredTask.h | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index f87ca26df1..ba5b2a59d5 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -291,6 +291,7 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const RenderArgs* args = renderContext->args; doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; + _gpuTimer.begin(batch); auto lightingFBO = DependencyManager::get()->getLightingFramebuffer(); @@ -310,8 +311,11 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const batch.setViewTransform(viewMat); renderItems(sceneContext, renderContext, inItems); + _gpuTimer.end(batch); }); args->_batch = nullptr; + + std::static_pointer_cast(renderContext->jobConfig)->gpuTime = _gpuTimer.getAverage(); } void Blit::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index bbcaec34f3..0125ef79fe 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -82,11 +82,27 @@ protected: static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable }; +class DrawBackgroundDeferredConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(double gpuTime READ getGpuTime) +public: + double getGpuTime() { return gpuTime; } + +protected: + friend class DrawBackgroundDeferred; + double gpuTime; +}; + class DrawBackgroundDeferred { public: + using Config = DrawBackgroundDeferredConfig; + using JobModel = render::Job::ModelI; + + void configure(const Config& config) {} void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemBounds& inItems); - using JobModel = render::Job::ModelI; +protected: + gpu::RangeTimer _gpuTimer; }; class DrawOverlay3DConfig : public render::Job::Config { From 0ea70f234fd83ac9dfe7bd3bc327ee5e81001dcc Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 14 Mar 2016 17:49:17 -0700 Subject: [PATCH 191/209] Add bg gpu timer display --- examples/utilities/tools/render/BG.qml | 22 ++++++++++++++++++++++ examples/utilities/tools/render/debugBG.js | 21 +++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 examples/utilities/tools/render/BG.qml create mode 100644 examples/utilities/tools/render/debugBG.js diff --git a/examples/utilities/tools/render/BG.qml b/examples/utilities/tools/render/BG.qml new file mode 100644 index 0000000000..40ce5a89fe --- /dev/null +++ b/examples/utilities/tools/render/BG.qml @@ -0,0 +1,22 @@ +// +// BG.qml +// examples/utilities/tools/render +// +// Created by Zach Pomerantz on 2/8/2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html +// +import QtQuick 2.5 +import QtQuick.Controls 1.4 + +Item { + Timer { + running: true; repeat: true + onTriggered: time.text = Render.getConfig("DrawBackgroundDeferred").gpuTime + } + + Text { id: time; font.pointSize: 20 } +} + diff --git a/examples/utilities/tools/render/debugBG.js b/examples/utilities/tools/render/debugBG.js new file mode 100644 index 0000000000..21fe024c32 --- /dev/null +++ b/examples/utilities/tools/render/debugBG.js @@ -0,0 +1,21 @@ +// +// debugBG.js +// examples/utilities/tools/render +// +// Zach Pomerantz, created on 1/27/2016. +// 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 +// + +// Set up the qml ui +var qml = Script.resolvePath('BG.qml'); +var window = new OverlayWindow({ + title: 'Background Timer', + source: qml, + width: 300 +}); +window.setPosition(25, 50); +window.closed.connect(function() { Script.stop(); }); + From 605474a32c6fad56f2c7508b98cd5bec762b7fe3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 14 Mar 2016 18:11:34 -0700 Subject: [PATCH 192/209] actually use the JSONTypePair alias --- interface/src/assets/ATPAssetMigrator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/assets/ATPAssetMigrator.h b/interface/src/assets/ATPAssetMigrator.h index c1becb9c7f..edb12f6e5d 100644 --- a/interface/src/assets/ATPAssetMigrator.h +++ b/interface/src/assets/ATPAssetMigrator.h @@ -51,7 +51,7 @@ private: using JSONTypePair = std::pair; - QMultiHash> _pendingReplacements; + QMultiHash _pendingReplacements; QHash _uploadedAssets; QHash _originalURLs; QSet _ignoredUrls; From 98851679c5d029e5087d8414c01b88d4c087e79d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 14 Mar 2016 13:23:33 -0700 Subject: [PATCH 193/209] Remove unused AssetMappingItem --- .../src/scripting/AssetMappingsScriptingInterface.cpp | 8 -------- .../src/scripting/AssetMappingsScriptingInterface.h | 10 ---------- 2 files changed, 18 deletions(-) diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index d4f5431d32..313bfca905 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -169,14 +169,6 @@ bool AssetMappingModel::isKnownFolder(QString path) const { return false; } -AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder) : - name(name), - fullPath(fullPath), - isFolder(isFolder) -{ - -} - static int assetMappingModelMetatypeId = qRegisterMetaType("AssetMappingModel*"); void AssetMappingModel::refresh() { diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index 9a427a05ed..d1840e33c0 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -20,16 +20,6 @@ #include #include - class AssetMappingItem : public QStandardItem { - public: - AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder); - - QString name; - QString fullPath; - bool isFolder; - }; - - class AssetMappingModel : public QStandardItemModel { Q_OBJECT public: From 9b8b1d41e30a8ad8a5aa772c738ae87697b1ddf6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Mar 2016 08:41:25 -0700 Subject: [PATCH 194/209] Edit in place --- interface/resources/qml/AssetServer.qml | 27 ++++++ interface/resources/qml/controls-uit/Tree.qml | 92 +++++++++++++++++-- 2 files changed, 113 insertions(+), 6 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 82970011a0..453ecfeb6c 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -164,6 +164,28 @@ Window { Window.copyToClipboard(url); } + function renameEl(index, data) { + if (!index) { + return false; + } + + var path = assetProxyModel.data(index, 0x100); + if (!path) { + return false; + } + + var destinationPath = path.split('/'); + destinationPath[destinationPath.length - (path[path.length - 1] === '/' ? 2 : 1)] = data; + destinationPath = destinationPath.join('/').trim(); + + console.log("Renaming " + path + " to " + destinationPath); + if (path === destinationPath) { + return; + } + if (!fileExists(destinationPath)) { + doRenameFile(path, destinationPath); + } + } function renameFile(index) { if (!index) { index = treeView.selection.currentIndex; @@ -371,8 +393,13 @@ Window { height: 400 treeModel: assetProxyModel colorScheme: root.colorScheme + canEdit: true + anchors.left: parent.left anchors.right: parent.right + + modifyEl: renameEl + MouseArea { propagateComposedEvents: true anchors.fill: parent diff --git a/interface/resources/qml/controls-uit/Tree.qml b/interface/resources/qml/controls-uit/Tree.qml index a2572a2f5c..2dfa289096 100644 --- a/interface/resources/qml/controls-uit/Tree.qml +++ b/interface/resources/qml/controls-uit/Tree.qml @@ -19,9 +19,12 @@ TreeView { id: treeView property var treeModel: ListModel { } + property var canEdit: false property int colorScheme: hifi.colorSchemes.light readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light + property var modifyEl: function(index, data) { return false; } + model: treeModel selection: ItemSelectionModel { model: treeModel @@ -124,7 +127,9 @@ TreeView { : (styleData.alternate ? hifi.colors.tableRowDarkEven : hifi.colors.tableRowDarkOdd) } - itemDelegate: FiraSansSemiBold { + itemDelegate: Loader { + id: itemDelegateLoader + anchors { left: parent ? parent.left : undefined leftMargin: (2 + styleData.depth) * hifi.dimensions.tablePadding @@ -133,11 +138,86 @@ TreeView { verticalCenter: parent ? parent.verticalCenter : undefined } - text: styleData.value - size: hifi.fontSizes.tableText - color: colorScheme == hifi.colorSchemes.light - ? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight) - : (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText) + function getComponent() { + if (treeView.canEdit && styleData.selected) { + return textFieldComponent; + } else { + return labelComponent; + } + + } + sourceComponent: getComponent() + + Component { + id: labelComponent + FiraSansSemiBold { + + text: styleData.value + size: hifi.fontSizes.tableText + color: colorScheme == hifi.colorSchemes.light + ? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight) + : (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText) + } + } + Component { + id: textFieldComponent + + TextField { + id: textField + readOnly: !activeFocus + + text: styleData.value + + FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } + font.family: firaSansSemiBold.name + font.pixelSize: hifi.fontSizes.textFieldInput + height: hifi.dimensions.tableRowHeight + + style: TextFieldStyle { + textColor: readOnly + ? hifi.colors.black + : (treeView.isLightColorScheme ? hifi.colors.black : hifi.colors.white) + background: Rectangle { + visible: !readOnly + color: treeView.isLightColorScheme ? hifi.colors.white : hifi.colors.black + border.color: hifi.colors.primaryHighlight + border.width: 1 + } + selectedTextColor: hifi.colors.black + selectionColor: hifi.colors.primaryHighlight + padding.left: readOnly ? 0 : hifi.dimensions.textPadding + padding.right: readOnly ? 0 : hifi.dimensions.textPadding + } + + validator: RegExpValidator { + regExp: /[^/]+/ + } + + Keys.onPressed: { + if (event.key == Qt.Key_Escape) { + text = styleData.value; + unfocusHelper.forceActiveFocus(); + event.accepted = true; + } + } + onAccepted: { + console.log("Data " + acceptableInput + " " + styleData.selected); + console.log("Index " + selection.currentIndex + " " + styleData.index); + if (acceptableInput && styleData.selected) { + console.log("Accepted " + styleData.index + " " + text); + if (!modifyEl(selection.currentIndex, text)) { + text = styleData.value; + } + unfocusHelper.forceActiveFocus(); + } + } + } + } + } + + Item { + id: unfocusHelper + visible: false } onDoubleClicked: isExpanded(index) ? collapse(index) : expand(index) From 07d2213628ca06b6096c2ffc2df2d1c0977429cd Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Mar 2016 08:42:55 -0700 Subject: [PATCH 195/209] Remove debug --- interface/resources/qml/AssetServer.qml | 1 - interface/resources/qml/controls-uit/Tree.qml | 3 --- 2 files changed, 4 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 453ecfeb6c..86ccae6f3e 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -178,7 +178,6 @@ Window { destinationPath[destinationPath.length - (path[path.length - 1] === '/' ? 2 : 1)] = data; destinationPath = destinationPath.join('/').trim(); - console.log("Renaming " + path + " to " + destinationPath); if (path === destinationPath) { return; } diff --git a/interface/resources/qml/controls-uit/Tree.qml b/interface/resources/qml/controls-uit/Tree.qml index 2dfa289096..6d4d202e2c 100644 --- a/interface/resources/qml/controls-uit/Tree.qml +++ b/interface/resources/qml/controls-uit/Tree.qml @@ -201,10 +201,7 @@ TreeView { } } onAccepted: { - console.log("Data " + acceptableInput + " " + styleData.selected); - console.log("Index " + selection.currentIndex + " " + styleData.index); if (acceptableInput && styleData.selected) { - console.log("Accepted " + styleData.index + " " + text); if (!modifyEl(selection.currentIndex, text)) { text = styleData.value; } From 7947bd77241fcceed9fe16c0d1ce3ce4b10a6877 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 15 Mar 2016 10:11:53 -0700 Subject: [PATCH 196/209] Fix message typo enter => entering --- interface/src/scripting/AssetMappingsScriptingInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index f75a597733..64a378e14d 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -61,7 +61,7 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue startedCallback, QJSValue completedCallback) { static const QString helpText = - "Upload your asset to a specific folder by enter the full path. Specifying " + "Upload your asset to a specific folder by entering the full path. Specifying " "a new folder name will automatically create that folder for you."; auto offscreenUi = DependencyManager::get(); From 4a90ec303c7293d58981e8ee3b24c5c1bcb459f0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Mar 2016 11:22:42 -0700 Subject: [PATCH 197/209] Fix drag&drop --- interface/resources/qml/AssetServer.qml | 40 ++++++++++--------- interface/src/Application.cpp | 3 +- interface/src/Application.h | 2 + .../AssetMappingsScriptingInterface.h | 1 + 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index d1b38eccc6..3e8942c206 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -45,6 +45,7 @@ Window { } Component.onCompleted: { + ApplicationInterface.uploadRequest.connect(uploadClicked); assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError); reload(); } @@ -245,24 +246,14 @@ Window { Timer { id: timer } - function uploadClicked() { + function uploadClicked(fileUrl) { if (uploadOpen) { return; } uploadOpen = true; - var fileUrl = ""; - - var browser = desktop.fileDialog({ - selectDirectory: false, - dir: currentDirectory - }); - browser.canceled.connect(function() { - uploadOpen = false; - }); - browser.selectedFile.connect(function(url){ + function doUpload(url) { var fileUrl = fileDialogHelper.urlToPath(url); - currentDirectory = browser.dir; var path = assetProxyModel.data(treeView.selection.currentIndex, 0x100); var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/"; @@ -299,8 +290,24 @@ Window { uploadButton.enabled = true; uploadOpen = false; } - }) - }); + }); + } + + if (fileUrl) { + doUpload(fileUrl); + } else { + var browser = desktop.fileDialog({ + selectDirectory: false, + dir: currentDirectory + }); + browser.canceled.connect(function() { + uploadOpen = false; + }); + browser.selectedFile.connect(function(url) { + currentDirectory = browser.dir; + doUpload(url); + }); + } } function errorMessageBox(message) { @@ -312,10 +319,6 @@ Window { }); } - function itemSelected() { - return treeView.selection.hasSelection() - } - Item { width: pane.contentWidth height: pane.height @@ -457,7 +460,6 @@ Window { height: 30 width: 155 - enabled: fileUrlTextField.text != "" onClicked: uploadClickedTimer.running = true // For some reason trigginer an API that enters diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d7cae2483b..2e459362ab 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4457,9 +4457,10 @@ void Application::toggleRunningScriptsWidget() { void Application::toggleAssetServerWidget(QString filePath) { static const QUrl url("AssetServer.qml"); auto urlSetter = [=](QQmlContext* context, QObject* newObject){ - newObject->setProperty("currentFileUrl", filePath); + emit uploadRequest(filePath); }; DependencyManager::get()->show(url, "AssetServer", urlSetter); + emit uploadRequest(filePath); } void Application::packageModel() { diff --git a/interface/src/Application.h b/interface/src/Application.h index c70d3412b7..029590966c 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -231,6 +231,8 @@ signals: void beforeAboutToQuit(); void activeDisplayPluginChanged(); + void uploadRequest(QString path); + public slots: QVector pasteEntities(float x, float y, float z); bool exportEntities(const QString& filename, const QVector& entityIDs); diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index 8e5d09cbd1..5b5170f7bb 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -30,6 +30,7 @@ public: bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); } bool isKnownFolder(QString path) const; +signals: void errorGettingMappings(QString errorString); private: From 4265ddbd0e5b1c3af3a6330b094ff6735e16c091 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Mar 2016 11:42:48 -0700 Subject: [PATCH 198/209] Can't drop fbx if you can't rez --- interface/src/Application.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2e459362ab..3e9c4f5a5a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4455,6 +4455,10 @@ void Application::toggleRunningScriptsWidget() { } void Application::toggleAssetServerWidget(QString filePath) { + if (!DependencyManager::get()->getThisNodeCanRez()) { + return; + } + static const QUrl url("AssetServer.qml"); auto urlSetter = [=](QQmlContext* context, QObject* newObject){ emit uploadRequest(filePath); From ddc658af5f189c1208a746a3e86eb34e1eba2078 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 15 Mar 2016 12:20:51 -0700 Subject: [PATCH 199/209] After a modelURL change to an existing model, allow the model to be snapped and scaled to the existing entity registration and dimensions. --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index c637cf4bb9..e2c7bb56c1 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -48,6 +48,13 @@ RenderableModelEntityItem::~RenderableModelEntityItem() { void RenderableModelEntityItem::setModelURL(const QString& url) { auto& currentURL = getParsedModelURL(); + if (_model && (currentURL != url)) { + // The machinery for updateModelBounds will give existing models the opportunity to fix their translation/rotation/scale/registration. + // The first two are straightforward, but the latter two have guards to make sure they don't happen after they've already been set. + // Here we reset those guards. This doesn't cause the entity values to change -- it just allows the model to match once it comes in. + _model->setScaleToFit(false, getDimensions()); + _model->setSnapModelToRegistrationPoint(false, getRegistrationPoint()); + } ModelEntityItem::setModelURL(url); if (currentURL != getParsedModelURL() || !_model) { From 03efde5b3c169ed17f028e436016b719496f855e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Mar 2016 13:53:13 -0700 Subject: [PATCH 200/209] Change text in case of drag and drop. --- interface/resources/qml/AssetServer.qml | 8 ++++---- interface/src/Application.cpp | 10 ++++++---- .../src/scripting/AssetMappingsScriptingInterface.cpp | 11 ++++++++--- .../src/scripting/AssetMappingsScriptingInterface.h | 2 +- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 3e8942c206..37291480b2 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -252,7 +252,7 @@ Window { } uploadOpen = true; - function doUpload(url) { + function doUpload(url, dropping) { var fileUrl = fileDialogHelper.urlToPath(url); var path = assetProxyModel.data(treeView.selection.currentIndex, 0x100); @@ -290,11 +290,11 @@ Window { uploadButton.enabled = true; uploadOpen = false; } - }); + }, dropping); } if (fileUrl) { - doUpload(fileUrl); + doUpload(fileUrl, true); } else { var browser = desktop.fileDialog({ selectDirectory: false, @@ -305,7 +305,7 @@ Window { }); browser.selectedFile.connect(function(url) { currentDirectory = browser.dir; - doUpload(url); + doUpload(url, false); }); } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3e9c4f5a5a..fda5a0e72d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4460,11 +4460,13 @@ void Application::toggleAssetServerWidget(QString filePath) { } static const QUrl url("AssetServer.qml"); - auto urlSetter = [=](QQmlContext* context, QObject* newObject){ - emit uploadRequest(filePath); + auto startUpload = [=](QQmlContext* context, QObject* newObject){ + if (!filePath.isEmpty()) { + emit uploadRequest(filePath); + } }; - DependencyManager::get()->show(url, "AssetServer", urlSetter); - emit uploadRequest(filePath); + DependencyManager::get()->show(url, "AssetServer", startUpload); + startUpload(nullptr, nullptr); } void Application::packageModel() { diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index b721d3c286..3c95eb007a 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -59,13 +59,18 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback request->start(); } -void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue startedCallback, QJSValue completedCallback) { +void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue startedCallback, QJSValue completedCallback, bool dropEvent) { static const QString helpText = - "Upload your asset to a specific folder by entering the full path. Specifying " + "Upload your asset to a specific folder by entering the full path. Specifying\n" "a new folder name will automatically create that folder for you."; + static const QString dropHelpText = + "This file will be added to your Asset Server.\n" + "Use the field below to place your file in a specific folder or to rename it.\n" + "Specifying a new folder name will automatically create that folder for you."; auto offscreenUi = DependencyManager::get(); - auto result = offscreenUi->inputDialog(OffscreenUi::ICON_INFORMATION, "Specify Asset Path", helpText, mapping); + auto result = offscreenUi->inputDialog(OffscreenUi::ICON_INFORMATION, "Specify Asset Path", + dropEvent ? dropHelpText : helpText, mapping); if (!result.isValid()) { completedCallback.call({ -1 }); diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index 5b5170f7bb..831b30513a 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -54,7 +54,7 @@ public: Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback = QJSValue()); Q_INVOKABLE void getMapping(QString path, QJSValue callback = QJSValue()); - Q_INVOKABLE void uploadFile(QString path, QString mapping, QJSValue startedCallback = QJSValue(), QJSValue completedCallback = QJSValue()); + Q_INVOKABLE void uploadFile(QString path, QString mapping, QJSValue startedCallback = QJSValue(), QJSValue completedCallback = QJSValue(), bool dropEvent = false); Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); Q_INVOKABLE void deleteMapping(QString path, QJSValue callback) { deleteMappings(QStringList(path), callback = QJSValue()); } Q_INVOKABLE void getAllMappings(QJSValue callback = QJSValue()); From f3daa9e1c58d81e08fde57553d7569255ea0c5c1 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 15 Mar 2016 14:35:43 -0700 Subject: [PATCH 201/209] Fixing the lighting issue in stereo --- libraries/entities-renderer/src/textured_particle.slv | 3 ++- libraries/gpu/src/gpu/Context.cpp | 5 +++-- libraries/gpu/src/gpu/Transform.slh | 6 +----- libraries/render-utils/src/DeferredLightingEffect.cpp | 4 +++- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libraries/entities-renderer/src/textured_particle.slv b/libraries/entities-renderer/src/textured_particle.slv index bbd7a1daa7..d3747d21eb 100644 --- a/libraries/entities-renderer/src/textured_particle.slv +++ b/libraries/entities-renderer/src/textured_particle.slv @@ -125,7 +125,8 @@ void main(void) { vec4 quadPos = radius * UNIT_QUAD[twoTriID]; vec4 anchorPoint; - <$transformModelToEyePos(cam, obj, inPosition, anchorPoint)$> + vec4 _inPosition = vec4(inPosition, 1.0); + <$transformModelToEyePos(cam, obj, _inPosition, anchorPoint)$> vec4 eyePos = anchorPoint + quadPos; <$transformEyeToClipPos(cam, eyePos, gl_Position)$> diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index 46c07e4265..dd26ab2823 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -79,7 +79,7 @@ const Backend::TransformCamera& Backend::TransformCamera::recomputeDerived(const // Get the viewEyeToWorld matrix form the transformView as passed to the gpu::Batch // this is the "_viewInverse" fed to the shader - // Genetrate the "_view" matrix as wekll forom the xform + // Genetrate the "_view" matrix as well from the xform xformView.getMatrix(_viewInverse); _view = glm::inverse(_viewInverse); @@ -98,6 +98,7 @@ Backend::TransformCamera Backend::TransformCamera::getEyeCamera(int eye, const S // FIXME: If "skybox" the ipd is set to 0 for now, let s try to propose a better solution for this in the future } result._projection = _stereo._eyeProjections[eye]; - result.recomputeDerived(xformView); + result.recomputeDerived(offsetTransform); + return result; } diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index 5881b18066..52ddf92158 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -99,12 +99,8 @@ TransformObject getTransformObject() { { // transformModelToEyeAndClipPos vec4 eyeWAPos; <$transformModelToEyeWorldAlignedPos($cameraTransform$, $objectTransform$, $modelPos$, eyeWAPos)$> - <$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * eyeWAPos; - vec4 _worldpos = (<$objectTransform$>._model * <$modelPos$>); - <$eyePos$> = (<$cameraTransform$>._view * _worldpos); - = vec4((<$cameraTransform$>._view * vec4(eyeWAPos.xyz, 0.0)).xyz, 1.0); !> + <$eyePos$> = vec4((<$cameraTransform$>._view * vec4(eyeWAPos.xyz, 0.0)).xyz, 1.0); } <@endfunc@> diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 82bd0e73d0..f3fa4a43b2 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -264,7 +264,9 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo deferredTransforms[i].projection = projMats[i]; auto sideViewMat = monoViewMat * glm::inverse(eyeViews[i]); - viewTransforms[i].evalFromRawMatrix(sideViewMat); + // viewTransforms[i].evalFromRawMatrix(sideViewMat); + viewTransforms[i] = monoViewTransform; + viewTransforms[i].postTranslate(-glm::vec3((eyeViews[i][3])));// evalFromRawMatrix(sideViewMat); deferredTransforms[i].viewInverse = sideViewMat; deferredTransforms[i].stereoSide = (i == 0 ? -1.0f : 1.0f); From b8abb1b6ddff30d0d29c986effa832bae323597f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 15 Mar 2016 11:24:22 -0700 Subject: [PATCH 202/209] remove redundant static from const in AssetServer --- assignment-client/src/assets/AssetServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index ff7d869a0b..4331b3ad31 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -438,7 +438,7 @@ void AssetServer::sendStatsPacket() { ThreadedAssignment::addPacketStatsAndSendStatsPacket(serverStats); } -static const QString MAP_FILE_NAME = "map.json"; +const QString MAP_FILE_NAME = "map.json"; void AssetServer::loadMappingsFromFile() { From 29cd487f848eb6bdcd71a450b0f745c5d518910d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 15 Mar 2016 11:26:20 -0700 Subject: [PATCH 203/209] fixes for styling and logging from CR --- assignment-client/src/assets/AssetServer.cpp | 5 ++--- interface/src/scripting/AssetMappingsScriptingInterface.cpp | 3 +-- libraries/script-engine/src/AssetScriptingInterface.cpp | 4 ---- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 4331b3ad31..d1e51d8545 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -222,8 +222,7 @@ void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNode auto assetHash = it->toString(); replyPacket.writePrimitive(AssetServerError::NoError); replyPacket.write(QByteArray::fromHex(assetHash.toUtf8())); - } - else { + } else { replyPacket.writePrimitive(AssetServerError::AssetNotFound); } } @@ -578,7 +577,7 @@ bool AssetServer::deleteMappings(AssetPathList& paths) { if (sizeBefore != sizeNow) { qDebug() << "Deleted" << sizeBefore - sizeNow << "mappings in folder: " << path; } else { - qDebug() << "Did not find any mappings in folder:" << path; + qDebug() << "Did not find any mappings to delete in folder:" << path; } } else { diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 3c95eb007a..005f8a597c 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -225,8 +225,7 @@ void AssetMappingModel::refresh() { lastItem = item; _pathToItemMap[fullPath] = lastItem; - } - else { + } else { lastItem = it.value(); } } diff --git a/libraries/script-engine/src/AssetScriptingInterface.cpp b/libraries/script-engine/src/AssetScriptingInterface.cpp index aaa4f97fb3..80cd30a8b6 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetScriptingInterface.cpp @@ -50,10 +50,6 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb 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); From b13dff1c771c9969cd55c948fef2836c079d6a40 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 15 Mar 2016 11:49:45 -0700 Subject: [PATCH 204/209] Revert "remove redundant static from const in AssetServer" This reverts commit 0837261d403e844f648f4f4ddcce7d7b79c7083b. --- assignment-client/src/assets/AssetServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index d1e51d8545..b63cf41b7c 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -437,7 +437,7 @@ void AssetServer::sendStatsPacket() { ThreadedAssignment::addPacketStatsAndSendStatsPacket(serverStats); } -const QString MAP_FILE_NAME = "map.json"; +static const QString MAP_FILE_NAME = "map.json"; void AssetServer::loadMappingsFromFile() { From 00129677349bdb451317f2279703870d20eae261 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 15 Mar 2016 11:57:26 -0700 Subject: [PATCH 205/209] use curly braced initialization for consts --- interface/src/Application.cpp | 3 ++- libraries/networking/src/AssetResourceRequest.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fda5a0e72d..4777d86d5e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4459,7 +4459,8 @@ void Application::toggleAssetServerWidget(QString filePath) { return; } - static const QUrl url("AssetServer.qml"); + static const QUrl url { "AssetServer.qml" }; + auto startUpload = [=](QQmlContext* context, QObject* newObject){ if (!filePath.isEmpty()) { emit uploadRequest(filePath); diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index c9063d7eae..6b94ee152a 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -26,7 +26,7 @@ AssetResourceRequest::~AssetResourceRequest() { } bool AssetResourceRequest::urlIsAssetHash() const { - static const QString ATP_HASH_REGEX_STRING = "^atp:([A-Fa-f0-9]{64})(\\.[\\w]+)?$"; + static const QString ATP_HASH_REGEX_STRING { "^atp:([A-Fa-f0-9]{64})(\\.[\\w]+)?$" }; QRegExp hashRegex { ATP_HASH_REGEX_STRING }; return hashRegex.exactMatch(_url.toString()); From 1cd16da83edbd92105ed89dfb20aafebd3c4d0e0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 15 Mar 2016 15:28:55 -0700 Subject: [PATCH 206/209] do sleep timing off when next packet would have been --- libraries/networking/src/udt/SendQueue.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 5c6db5adf3..3149c5c7bf 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -280,11 +280,11 @@ void SendQueue::run() { // Once we're here we've either received the handshake ACK or it's going to be time to re-send a handshake. // Either way let's continue processing - no packets will be sent if no handshake ACK has been received. } - + + // Keep an HRC to know when the next packet should have been + auto nextPacketTimestamp = p_high_resolution_clock::now(); + while (_state == State::Running) { - // Record how long the loop takes to execute - const auto loopStartTimestamp = p_high_resolution_clock::now(); - bool sentAPacket = maybeResendPacket(); // if we didn't find a packet to re-send AND we think we can fit a new packet on the wire @@ -304,9 +304,15 @@ void SendQueue::run() { return; } + // grab the current HRC timestamp + const auto now = p_high_resolution_clock::now(); + + // push the next packet timestamp forwards by the current packet send period + nextPacketTimestamp += std::chrono::microseconds(_packetSendPeriod); + // sleep as long as we need until next packet send, if we can - const auto loopEndTimestamp = p_high_resolution_clock::now(); - const auto timeToSleep = (loopStartTimestamp + std::chrono::microseconds(_packetSendPeriod)) - loopEndTimestamp; + const auto timeToSleep = std::chrono::duration_cast(nextPacketTimestamp - now); + std::this_thread::sleep_for(timeToSleep); } } From 92b287355c4799cae3e11b71ee01e7c2ef0a2631 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 15 Mar 2016 15:56:13 -0700 Subject: [PATCH 207/209] make TRUNCATED_HASH_NUM_CHAR a non-static const --- assignment-client/src/assets/AssetServer.cpp | 42 ++++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index b63cf41b7c..f5f83399d6 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -111,7 +111,7 @@ void AssetServer::completeSetup() { // load whatever mappings we currently have from the local file loadMappingsFromFile(); - + qInfo() << "Serving files from: " << _filesDirectory.path(); // Check the asset directory to output some information about what we have @@ -154,7 +154,7 @@ void AssetServer::performMappingMigration() { qDebug() << "\tRenamed pre-mapping file" << fileInfo.fileName(); // add a new mapping with the old extension and a truncated version of the hash - static const int TRUNCATED_HASH_NUM_CHAR = 16; + const int TRUNCATED_HASH_NUM_CHAR = 16; auto fakeFileName = "/" + hash.left(TRUNCATED_HASH_NUM_CHAR) + fullExtension; qDebug() << "\tAdding a migration mapping from" << fakeFileName << "to" << hash; @@ -330,7 +330,7 @@ void AssetServer::handleAssetGetInfo(QSharedPointer message, Sh void AssetServer::handleAssetGet(QSharedPointer message, SharedNodePointer senderNode) { auto minSize = qint64(sizeof(MessageID) + SHA256_HASH_LENGTH + sizeof(DataOffset) + sizeof(DataOffset)); - + if (message->getSize() < minSize) { qDebug() << "ERROR bad file request"; return; @@ -342,26 +342,26 @@ void AssetServer::handleAssetGet(QSharedPointer message, Shared } void AssetServer::handleAssetUpload(QSharedPointer message, SharedNodePointer senderNode) { - + if (senderNode->getCanRez()) { qDebug() << "Starting an UploadAssetTask for upload from" << uuidStringWithoutCurlyBraces(senderNode->getUUID()); - + auto task = new UploadAssetTask(message, senderNode, _filesDirectory); _taskPool.start(task); } else { // this is a node the domain told us is not allowed to rez entities // for now this also means it isn't allowed to add assets // so return a packet with error that indicates that - + auto permissionErrorPacket = NLPacket::create(PacketType::AssetUploadReply, sizeof(MessageID) + sizeof(AssetServerError)); - + MessageID messageID; message->readPrimitive(&messageID); - + // write the message ID and a permission denied error permissionErrorPacket->writePrimitive(messageID); permissionErrorPacket->writePrimitive(AssetServerError::PermissionDenied); - + // send off the packet auto nodeList = DependencyManager::get(); nodeList->sendPacket(std::move(permissionErrorPacket), *senderNode); @@ -370,19 +370,19 @@ void AssetServer::handleAssetUpload(QSharedPointer message, Sha void AssetServer::sendStatsPacket() { QJsonObject serverStats; - + auto stats = DependencyManager::get()->sampleStatsForAllConnections(); - + for (const auto& stat : stats) { QJsonObject nodeStats; auto endTimeMs = std::chrono::duration_cast(stat.second.endTime); QDateTime date = QDateTime::fromMSecsSinceEpoch(endTimeMs.count()); - + static const float USEC_PER_SEC = 1000000.0f; static const float MEGABITS_PER_BYTE = 8.0f / 1000000.0f; // Bytes => Mbits float elapsed = (float)(stat.second.endTime - stat.second.startTime).count() / USEC_PER_SEC; // sec float megabitsPerSecPerByte = MEGABITS_PER_BYTE / elapsed; // Bytes => Mb/s - + QJsonObject connectionStats; connectionStats["1. Last Heard"] = date.toString(); connectionStats["2. Est. Max (P/s)"] = stat.second.estimatedBandwith; @@ -392,10 +392,10 @@ void AssetServer::sendStatsPacket() { connectionStats["6. Up (Mb/s)"] = stat.second.sentBytes * megabitsPerSecPerByte; connectionStats["7. Down (Mb/s)"] = stat.second.receivedBytes * megabitsPerSecPerByte; nodeStats["Connection Stats"] = connectionStats; - + using Events = udt::ConnectionStats::Stats::Event; const auto& events = stat.second.events; - + QJsonObject upstreamStats; upstreamStats["1. Sent (P/s)"] = stat.second.sendRate; upstreamStats["2. Sent Packets"] = stat.second.sentPackets; @@ -407,7 +407,7 @@ void AssetServer::sendStatsPacket() { upstreamStats["8. Sent ACK2"] = events[Events::SentACK2]; upstreamStats["9. Retransmitted"] = events[Events::Retransmission]; nodeStats["Upstream Stats"] = upstreamStats; - + QJsonObject downstreamStats; downstreamStats["1. Recvd (P/s)"] = stat.second.receiveRate; downstreamStats["2. Recvd Packets"] = stat.second.receivedPackets; @@ -418,7 +418,7 @@ void AssetServer::sendStatsPacket() { downstreamStats["7. Recvd ACK2"] = events[Events::ReceivedACK2]; downstreamStats["8. Duplicates"] = events[Events::Duplicate]; nodeStats["Downstream Stats"] = downstreamStats; - + QString uuid; auto nodelist = DependencyManager::get(); if (stat.first == nodelist->getDomainHandler().getSockAddr()) { @@ -429,10 +429,10 @@ void AssetServer::sendStatsPacket() { uuid = uuidStringWithoutCurlyBraces(node ? node->getUUID() : QUuid()); nodeStats[USERNAME_UUID_REPLACEMENT_STATS_KEY] = uuid; } - + serverStats[uuid] = nodeStats; } - + // send off the stats packets ThreadedAssignment::addPacketStatsAndSendStatsPacket(serverStats); } @@ -607,7 +607,7 @@ bool AssetServer::deleteMappings(AssetPathList& paths) { bool AssetServer::renameMapping(AssetPath oldPath, AssetPath newPath) { oldPath = oldPath.trimmed(); newPath = newPath.trimmed(); - + if (!isValidPath(oldPath) || !isValidPath(newPath)) { qWarning() << "Cannot perform rename with invalid paths - both should have leading forward slashes:" << oldPath << "=>" << newPath; @@ -646,7 +646,7 @@ bool AssetServer::renameMapping(AssetPath oldPath, AssetPath newPath) { if (writeMappingsToFile()) { // persisted the changed mappings, return success qDebug() << "Renamed folder mapping:" << oldPath << "=>" << newPath; - + return true; } else { // couldn't persist the renamed paths, rollback and return failure From d58ac269eec8d8a8235c6e4d559964396e35e539 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 15 Mar 2016 17:01:26 -0700 Subject: [PATCH 208/209] Fixing a bug when albedo map transaprent but not quite loaded yet --- .../src/model-networking/ModelCache.cpp | 2 +- .../render-utils/src/model_translucent.slf | 36 ++++++++++++------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 3f7e0405d4..c9ff8e681b 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -147,7 +147,7 @@ bool NetworkGeometry::isLoadedWithTextures() const { (material->lightmapTexture && !material->lightmapTexture->isLoaded())) { return false; } - if (material->albedoTexture) { + if (material->albedoTexture && material->albedoTexture->getGPUTexture()) { // Reset the materialKey transparentTexture key only, as it is albedoTexture-dependent const auto& usage = material->albedoTexture->getGPUTexture()->getUsage(); bool isTransparentTexture = usage.isAlpha() && !usage.isAlphaMask(); diff --git a/libraries/render-utils/src/model_translucent.slf b/libraries/render-utils/src/model_translucent.slf index 086f9fe168..b99b5c8a2a 100755 --- a/libraries/render-utils/src/model_translucent.slf +++ b/libraries/render-utils/src/model_translucent.slf @@ -20,7 +20,8 @@ <@include gpu/Transform.slh@> <$declareStandardCameraTransform()$> -uniform sampler2D albedoMap; +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$> in vec2 _texCoord0; in vec4 _position; @@ -31,16 +32,27 @@ in float _alpha; out vec4 _fragColor; void main(void) { - vec4 albedo = texture(albedoMap, _texCoord0); - Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTextures(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex, occlusionTex)$> + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + float roughness = getMaterialRoughness(mat); + <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + + float metallic = getMaterialMetallic(mat); + + vec3 emissive = getMaterialEmissive(mat); + <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; + + vec3 fragPosition = _position.xyz; vec3 fragNormal = normalize(_normal); - vec3 fragAlbedo = getMaterialAlbedo(mat) * albedo.rgb * _color; - float fragMetallic = getMaterialMetallic(mat); - vec3 fragEmissive = getMaterialEmissive(mat); - float fragRoughness = getMaterialRoughness(mat); - float fragOpacity = getMaterialOpacity(mat) * albedo.a * _alpha; + + float fragOpacity = getMaterialOpacity(mat) * albedoTex.a * _alpha; TransformCamera cam = getTransformCamera(); @@ -50,9 +62,9 @@ void main(void) { 1.0, fragPosition, fragNormal, - fragAlbedo, - fragMetallic, - fragEmissive, - fragRoughness), + albedo, + metallic, + emissive, + roughness), fragOpacity); } From c94e2bdc8b71dcf1925edf76aaef1fa8095c5456 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 16 Mar 2016 08:53:31 -0700 Subject: [PATCH 209/209] grab the now timestamp only when needed --- libraries/networking/src/udt/SendQueue.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 3149c5c7bf..8e5141b58a 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -29,6 +29,7 @@ #include "Socket.h" using namespace udt; +using namespace std::chrono; template class DoubleLock { @@ -303,15 +304,12 @@ void SendQueue::run() { if (_state != State::Running || isInactive(sentAPacket)) { return; } - - // grab the current HRC timestamp - const auto now = p_high_resolution_clock::now(); // push the next packet timestamp forwards by the current packet send period nextPacketTimestamp += std::chrono::microseconds(_packetSendPeriod); // sleep as long as we need until next packet send, if we can - const auto timeToSleep = std::chrono::duration_cast(nextPacketTimestamp - now); + const auto timeToSleep = duration_cast(nextPacketTimestamp - p_high_resolution_clock::now()); std::this_thread::sleep_for(timeToSleep); }