mirror of
https://github.com/overte-org/overte.git
synced 2025-04-25 00:56:48 +02:00
commit
79e788523b
14 changed files with 614 additions and 11 deletions
|
@ -42,6 +42,7 @@ AssetServer::AssetServer(ReceivedMessage& message) :
|
|||
packetReceiver.registerListener(PacketType::AssetGet, this, "handleAssetGet");
|
||||
packetReceiver.registerListener(PacketType::AssetGetInfo, this, "handleAssetGetInfo");
|
||||
packetReceiver.registerListener(PacketType::AssetUpload, this, "handleAssetUpload");
|
||||
packetReceiver.registerListener(PacketType::AssetMappingOperation, this, "handleAssetMappingOperation");
|
||||
}
|
||||
|
||||
void AssetServer::run() {
|
||||
|
@ -161,6 +162,67 @@ void AssetServer::completeSetup() {
|
|||
nodeList->addNodeTypeToInterestSet(NodeType::Agent);
|
||||
}
|
||||
|
||||
|
||||
void AssetServer::handleAssetMappingOperation(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
|
||||
MessageID messageID;
|
||||
message->readPrimitive(&messageID);
|
||||
|
||||
AssetMappingOperationType operationType;
|
||||
message->readPrimitive(&operationType);
|
||||
|
||||
auto replyPacket = NLPacketList::create(PacketType::AssetMappingOperationReply, QByteArray(), true, true);
|
||||
replyPacket->writePrimitive(messageID);
|
||||
|
||||
switch (operationType) {
|
||||
case AssetMappingOperationType::Get: {
|
||||
QString assetPath = message->readString();
|
||||
|
||||
auto it = _fileMapping.find(assetPath);
|
||||
if (it != _fileMapping.end()) {
|
||||
auto assetHash = it->second;
|
||||
qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash;
|
||||
replyPacket->writePrimitive(AssetServerError::NoError);
|
||||
//replyPacket->write(assetHash.toLatin1().toHex());
|
||||
replyPacket->writeString(assetHash.toLatin1());
|
||||
}
|
||||
else {
|
||||
qDebug() << "Mapping not found for: " << assetPath;
|
||||
replyPacket->writePrimitive(AssetServerError::AssetNotFound);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AssetMappingOperationType::GetAll: {
|
||||
replyPacket->writePrimitive(AssetServerError::NoError);
|
||||
auto count = _fileMapping.size();
|
||||
replyPacket->writePrimitive(count);
|
||||
for (auto& kv : _fileMapping) {
|
||||
replyPacket->writeString(kv.first);
|
||||
replyPacket->writeString(kv.second);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AssetMappingOperationType::Set: {
|
||||
QString assetPath = message->readString();
|
||||
//auto assetHash = message->read(SHA256_HASH_LENGTH);
|
||||
auto assetHash = message->readString();
|
||||
_fileMapping[assetPath] = assetHash;
|
||||
|
||||
replyPacket->writePrimitive(AssetServerError::NoError);
|
||||
break;
|
||||
}
|
||||
case AssetMappingOperationType::Delete: {
|
||||
QString assetPath = message->readString();
|
||||
bool removed = _fileMapping.erase(assetPath) > 0;
|
||||
|
||||
replyPacket->writePrimitive(AssetServerError::NoError);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
nodeList->sendPacketList(std::move(replyPacket), *senderNode);
|
||||
}
|
||||
|
||||
void AssetServer::handleAssetGetInfo(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
|
||||
QByteArray assetHash;
|
||||
MessageID messageID;
|
||||
|
@ -308,3 +370,9 @@ void AssetServer::sendStatsPacket() {
|
|||
// send off the stats packets
|
||||
ThreadedAssignment::addPacketStatsAndSendStatsPacket(serverStats);
|
||||
}
|
||||
|
||||
void AssetServer::loadMappingFromFile() {
|
||||
}
|
||||
|
||||
void AssetServer::writeMappingToFile() {
|
||||
}
|
||||
|
|
|
@ -34,11 +34,18 @@ private slots:
|
|||
void handleAssetGetInfo(QSharedPointer<ReceivedMessage> packet, SharedNodePointer senderNode);
|
||||
void handleAssetGet(QSharedPointer<ReceivedMessage> packet, SharedNodePointer senderNode);
|
||||
void handleAssetUpload(QSharedPointer<ReceivedMessage> packetList, SharedNodePointer senderNode);
|
||||
void handleAssetMappingOperation(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
|
||||
void sendStatsPacket();
|
||||
|
||||
private:
|
||||
|
||||
void loadMappingFromFile();
|
||||
void writeMappingToFile();
|
||||
|
||||
static void writeError(NLPacketList* packetList, AssetServerError error);
|
||||
|
||||
AssetMapping _fileMapping;
|
||||
QDir _resourcesDirectory;
|
||||
QThreadPool _taskPool;
|
||||
};
|
||||
|
|
|
@ -30,6 +30,148 @@
|
|||
|
||||
MessageID AssetClient::_currentID = 0;
|
||||
|
||||
void MappingRequest::start() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "start", Qt::AutoConnection);
|
||||
return;
|
||||
}
|
||||
doStart();
|
||||
};
|
||||
|
||||
GetMappingRequest::GetMappingRequest(AssetPath path) : _path(path) {
|
||||
};
|
||||
|
||||
void GetMappingRequest::doStart() {
|
||||
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
|
||||
// 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<ReceivedMessage> message) {
|
||||
if (!responseReceived) {
|
||||
_error = NetworkError;
|
||||
} else {
|
||||
switch (error) {
|
||||
case AssetServerError::NoError:
|
||||
_error = NoError;
|
||||
break;
|
||||
case AssetServerError::AssetNotFound:
|
||||
_error = NotFound;
|
||||
break;
|
||||
default:
|
||||
_error = UnknownError;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_error) {
|
||||
//_hash = message->read(SHA256_HASH_HEX_LENGTH);
|
||||
_hash = message->readString();
|
||||
assetClient->_mappingCache[_path] = _hash;
|
||||
}
|
||||
emit finished(this);
|
||||
});
|
||||
};
|
||||
|
||||
GetAllMappingsRequest::GetAllMappingsRequest() {
|
||||
};
|
||||
|
||||
void GetAllMappingsRequest::doStart() {
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
assetClient->getAllAssetMappings([this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer<ReceivedMessage> message) {
|
||||
if (!responseReceived) {
|
||||
_error = NetworkError;
|
||||
} else {
|
||||
switch (error) {
|
||||
case AssetServerError::NoError:
|
||||
_error = NoError;
|
||||
break;
|
||||
default:
|
||||
_error = UnknownError;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!error) {
|
||||
size_t numberOfMappings;
|
||||
message->readPrimitive(&numberOfMappings);
|
||||
assetClient->_mappingCache.clear();
|
||||
for (auto i = 0; i < numberOfMappings; ++i) {
|
||||
auto path = message->readString();
|
||||
auto hash = message->readString();
|
||||
_mappings[path] = hash;
|
||||
assetClient->_mappingCache[path] = hash;
|
||||
}
|
||||
}
|
||||
emit finished(this);
|
||||
});
|
||||
};
|
||||
|
||||
SetMappingRequest::SetMappingRequest(AssetPath path, AssetHash hash) : _path(path), _hash(hash) {
|
||||
};
|
||||
|
||||
void SetMappingRequest::doStart() {
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
assetClient->setAssetMapping(_path, _hash, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer<ReceivedMessage> message) {
|
||||
if (!responseReceived) {
|
||||
_error = NetworkError;
|
||||
} else {
|
||||
switch (error) {
|
||||
case AssetServerError::NoError:
|
||||
_error = NoError;
|
||||
break;
|
||||
case AssetServerError::PermissionDenied:
|
||||
_error = PermissionDenied;
|
||||
break;
|
||||
default:
|
||||
_error = UnknownError;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!error) {
|
||||
assetClient->_mappingCache[_path] = _hash;
|
||||
}
|
||||
emit finished(this);
|
||||
});
|
||||
};
|
||||
|
||||
DeleteMappingRequest::DeleteMappingRequest(AssetPath path) : _path(path) {
|
||||
};
|
||||
|
||||
void DeleteMappingRequest::doStart() {
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
assetClient->deleteAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer<ReceivedMessage> message) {
|
||||
if (!responseReceived) {
|
||||
_error = NetworkError;
|
||||
} else {
|
||||
switch (error) {
|
||||
case AssetServerError::NoError:
|
||||
_error = NoError;
|
||||
break;
|
||||
case AssetServerError::PermissionDenied:
|
||||
_error = PermissionDenied;
|
||||
break;
|
||||
default:
|
||||
_error = UnknownError;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!error) {
|
||||
assetClient->_mappingCache.remove(_path);
|
||||
}
|
||||
emit finished(this);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
AssetClient::AssetClient() {
|
||||
|
||||
|
@ -39,6 +181,7 @@ AssetClient::AssetClient() {
|
|||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
auto& packetReceiver = nodeList->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::AssetMappingOperationReply, this, "handleAssetMappingOperationReply");
|
||||
packetReceiver.registerListener(PacketType::AssetGetInfoReply, this, "handleAssetGetInfoReply");
|
||||
packetReceiver.registerListener(PacketType::AssetGetReply, this, "handleAssetGetReply", true);
|
||||
packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply");
|
||||
|
@ -89,6 +232,8 @@ void AssetClient::clearCache() {
|
|||
return;
|
||||
}
|
||||
|
||||
_mappingCache.clear();
|
||||
|
||||
if (auto cache = NetworkAccessManager::getInstance().cache()) {
|
||||
qDebug() << "AssetClient::clearCache(): Clearing disk cache.";
|
||||
cache->clear();
|
||||
|
@ -97,6 +242,33 @@ void AssetClient::clearCache() {
|
|||
}
|
||||
}
|
||||
|
||||
void AssetClient::handleAssetMappingOperationReply(QSharedPointer<ReceivedMessage> 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<NodeList>();
|
||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||
|
@ -109,8 +281,23 @@ bool haveAssetServer() {
|
|||
|
||||
return true;
|
||||
}
|
||||
GetMappingRequest* AssetClient::createGetMappingRequest(const AssetPath& path) {
|
||||
return new GetMappingRequest(path);
|
||||
}
|
||||
|
||||
AssetRequest* AssetClient::createRequest(const QString& hash, const QString& extension) {
|
||||
GetAllMappingsRequest* AssetClient::createGetAllMappingsRequest() {
|
||||
return new GetAllMappingsRequest();
|
||||
}
|
||||
|
||||
DeleteMappingRequest* AssetClient::createDeleteMappingRequest(const AssetPath& path) {
|
||||
return new DeleteMappingRequest(path);
|
||||
}
|
||||
|
||||
SetMappingRequest* AssetClient::createSetMappingRequest(const AssetPath& path, const AssetHash& hash) {
|
||||
return new SetMappingRequest(path, hash);
|
||||
}
|
||||
|
||||
AssetRequest* AssetClient::createRequest(const AssetHash& hash, const QString& extension) {
|
||||
if (hash.length() != SHA256_HASH_HEX_LENGTH) {
|
||||
qCWarning(asset_client) << "Invalid hash size";
|
||||
return nullptr;
|
||||
|
@ -128,8 +315,6 @@ AssetRequest* AssetClient::createRequest(const QString& hash, const QString& ext
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AssetUpload* AssetClient::createUpload(const QString& filename) {
|
||||
|
||||
if (haveAssetServer()) {
|
||||
|
@ -305,6 +490,100 @@ void AssetClient::handleAssetGetReply(QSharedPointer<ReceivedMessage> message, S
|
|||
}
|
||||
}
|
||||
|
||||
bool AssetClient::getAssetMapping(const AssetPath& path, MappingOperationCallback callback) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||
if (assetServer) {
|
||||
auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true);
|
||||
|
||||
auto messageID = ++_currentID;
|
||||
packetList->writePrimitive(messageID);
|
||||
|
||||
packetList->writePrimitive(AssetMappingOperationType::Get);
|
||||
|
||||
packetList->writeString(path);
|
||||
|
||||
nodeList->sendPacketList(std::move(packetList), *assetServer);
|
||||
|
||||
_pendingMappingRequests[assetServer][messageID] = callback;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AssetClient::getAllAssetMappings(MappingOperationCallback callback) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
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<NodeList>();
|
||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||
|
||||
if (assetServer) {
|
||||
auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true);
|
||||
|
||||
auto messageID = ++_currentID;
|
||||
packetList->writePrimitive(messageID);
|
||||
|
||||
packetList->writePrimitive(AssetMappingOperationType::Delete);
|
||||
|
||||
packetList->writeString(path);
|
||||
|
||||
nodeList->sendPacketList(std::move(packetList), *assetServer);
|
||||
|
||||
_pendingMappingRequests[assetServer][messageID] = callback;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AssetClient::setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||
|
||||
if (assetServer) {
|
||||
auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true);
|
||||
|
||||
auto messageID = ++_currentID;
|
||||
packetList->writePrimitive(messageID);
|
||||
|
||||
packetList->writePrimitive(AssetMappingOperationType::Set);
|
||||
|
||||
packetList->writeString(path);
|
||||
packetList->writeString(hash);
|
||||
|
||||
nodeList->sendPacketList(std::move(packetList), *assetServer);
|
||||
|
||||
_pendingMappingRequests[assetServer][messageID] = callback;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AssetClient::uploadAsset(const QByteArray& data, const QString& extension, UploadResultCallback callback) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||
|
@ -404,6 +683,18 @@ void AssetClient::handleNodeKilled(SharedNodePointer node) {
|
|||
messageMapIt->second.clear();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto messageMapIt = _pendingMappingRequests.find(node);
|
||||
if (messageMapIt != _pendingMappingRequests.end()) {
|
||||
for (const auto& value : messageMapIt->second) {
|
||||
value.second(false, AssetServerError::NoError, QSharedPointer<ReceivedMessage>());
|
||||
}
|
||||
messageMapIt->second.clear();
|
||||
}
|
||||
}
|
||||
|
||||
_mappingCache.clear();
|
||||
}
|
||||
|
||||
void AssetScriptingInterface::uploadData(QString data, QString extension, QScriptValue callback) {
|
||||
|
@ -471,4 +762,75 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb
|
|||
});
|
||||
|
||||
assetRequest->start();
|
||||
}
|
||||
}
|
||||
|
||||
void AssetScriptingInterface::setMapping(QString path, QString hash, QScriptValue callback) {
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
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<AssetClient>();
|
||||
auto request = assetClient->createGetMappingRequest(path);
|
||||
|
||||
connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable {
|
||||
QScriptValueList args { uint8_t(request->getError()), request->getHash() };
|
||||
|
||||
callback.call(_engine->currentContext()->thisObject(), args);
|
||||
|
||||
request->deleteLater();
|
||||
|
||||
});
|
||||
|
||||
request->start();
|
||||
}
|
||||
|
||||
void AssetScriptingInterface::deleteMapping(QString path, QScriptValue callback) {
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
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<AssetClient>();
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#include <QString>
|
||||
#include <QScriptValue>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#include "AssetUtils.h"
|
||||
|
@ -25,6 +27,8 @@
|
|||
#include "ReceivedMessage.h"
|
||||
#include "ResourceCache.h"
|
||||
|
||||
class GetMappingRequest;
|
||||
class SetMappingRequest;
|
||||
class AssetRequest;
|
||||
class AssetUpload;
|
||||
|
||||
|
@ -33,18 +37,114 @@ struct AssetInfo {
|
|||
int64_t size;
|
||||
};
|
||||
|
||||
using MappingOperationCallback = std::function<void(bool responseReceived, AssetServerError serverError, QSharedPointer<ReceivedMessage> message)>;
|
||||
using ReceivedAssetCallback = std::function<void(bool responseReceived, AssetServerError serverError, const QByteArray& data)>;
|
||||
using GetInfoCallback = std::function<void(bool responseReceived, AssetServerError serverError, AssetInfo info)>;
|
||||
using UploadResultCallback = std::function<void(bool responseReceived, AssetServerError serverError, const QString& hash)>;
|
||||
using ProgressCallback = std::function<void(qint64 totalReceived, qint64 total)>;
|
||||
|
||||
class MappingRequest : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Error {
|
||||
NoError,
|
||||
NotFound,
|
||||
NetworkError,
|
||||
PermissionDenied,
|
||||
UnknownError
|
||||
};
|
||||
|
||||
Q_INVOKABLE void start();
|
||||
Error getError() const { return _error; }
|
||||
|
||||
protected:
|
||||
Error _error { NoError };
|
||||
|
||||
private:
|
||||
virtual void doStart() = 0;
|
||||
};
|
||||
|
||||
|
||||
class GetMappingRequest : public MappingRequest {
|
||||
Q_OBJECT
|
||||
public:
|
||||
GetMappingRequest(AssetPath path);
|
||||
|
||||
AssetHash getHash() const { return _hash; }
|
||||
|
||||
signals:
|
||||
void finished(GetMappingRequest* thisRequest);
|
||||
|
||||
private:
|
||||
virtual void doStart() override;
|
||||
|
||||
AssetPath _path;
|
||||
AssetHash _hash;
|
||||
};
|
||||
|
||||
class SetMappingRequest : public MappingRequest {
|
||||
Q_OBJECT
|
||||
public:
|
||||
SetMappingRequest(AssetPath path, AssetHash hash);
|
||||
|
||||
AssetHash getHash() const { return _hash; }
|
||||
|
||||
signals:
|
||||
void finished(SetMappingRequest* thisRequest);
|
||||
|
||||
private:
|
||||
virtual void doStart() override;
|
||||
|
||||
AssetPath _path;
|
||||
AssetHash _hash;
|
||||
};
|
||||
|
||||
class DeleteMappingRequest : public MappingRequest {
|
||||
Q_OBJECT
|
||||
public:
|
||||
DeleteMappingRequest(AssetPath path);
|
||||
|
||||
Q_INVOKABLE void start();
|
||||
|
||||
signals:
|
||||
void finished(DeleteMappingRequest* thisRequest);
|
||||
|
||||
private:
|
||||
virtual void doStart() override;
|
||||
|
||||
AssetPath _path;
|
||||
};
|
||||
|
||||
class GetAllMappingsRequest : public MappingRequest {
|
||||
Q_OBJECT
|
||||
public:
|
||||
GetAllMappingsRequest();
|
||||
|
||||
Q_INVOKABLE void start();
|
||||
|
||||
AssetMapping getMappings() const { return _mappings; }
|
||||
|
||||
signals:
|
||||
void finished(GetAllMappingsRequest* thisRequest);
|
||||
|
||||
private:
|
||||
virtual void doStart() override;
|
||||
|
||||
std::map<AssetPath, AssetHash> _mappings;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class AssetClient : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AssetClient();
|
||||
|
||||
Q_INVOKABLE AssetRequest* createRequest(const QString& hash, const QString& extension);
|
||||
Q_INVOKABLE GetMappingRequest* createGetMappingRequest(const AssetPath& path);
|
||||
Q_INVOKABLE GetAllMappingsRequest* createGetAllMappingsRequest();
|
||||
Q_INVOKABLE DeleteMappingRequest* createDeleteMappingRequest(const AssetPath& path);
|
||||
Q_INVOKABLE SetMappingRequest* createSetMappingRequest(const AssetPath& path, const AssetHash& hash);
|
||||
Q_INVOKABLE AssetRequest* createRequest(const AssetHash& hash, const QString& extension);
|
||||
Q_INVOKABLE AssetUpload* createUpload(const QString& filename);
|
||||
Q_INVOKABLE AssetUpload* createUpload(const QByteArray& data, const QString& extension);
|
||||
|
||||
|
@ -55,6 +155,7 @@ public slots:
|
|||
void clearCache();
|
||||
|
||||
private slots:
|
||||
void handleAssetMappingOperationReply(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
void handleAssetGetInfoReply(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
void handleAssetGetReply(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
void handleAssetUploadReply(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
|
@ -62,6 +163,11 @@ private slots:
|
|||
void handleNodeKilled(SharedNodePointer node);
|
||||
|
||||
private:
|
||||
bool getAssetMapping(const AssetHash& hash, MappingOperationCallback callback);
|
||||
bool getAllAssetMappings(MappingOperationCallback callback);
|
||||
bool setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback);
|
||||
bool deleteAssetMapping(const AssetPath& path, MappingOperationCallback callback);
|
||||
|
||||
bool getAssetInfo(const QString& hash, const QString& extension, GetInfoCallback callback);
|
||||
bool getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end,
|
||||
ReceivedAssetCallback callback, ProgressCallback progressCallback);
|
||||
|
@ -73,12 +179,19 @@ private:
|
|||
};
|
||||
|
||||
static MessageID _currentID;
|
||||
std::unordered_map<SharedNodePointer, std::unordered_map<MessageID, MappingOperationCallback>> _pendingMappingRequests;
|
||||
std::unordered_map<SharedNodePointer, std::unordered_map<MessageID, GetAssetCallbacks>> _pendingRequests;
|
||||
std::unordered_map<SharedNodePointer, std::unordered_map<MessageID, GetInfoCallback>> _pendingInfoRequests;
|
||||
std::unordered_map<SharedNodePointer, std::unordered_map<MessageID, UploadResultCallback>> _pendingUploads;
|
||||
|
||||
QHash<QString, QString> _mappingCache;
|
||||
|
||||
friend class AssetRequest;
|
||||
friend class AssetUpload;
|
||||
friend class GetMappingRequest;
|
||||
friend class GetAllMappingsRequest;
|
||||
friend class SetMappingRequest;
|
||||
friend class DeleteMappingRequest;
|
||||
};
|
||||
|
||||
|
||||
|
@ -89,6 +202,10 @@ public:
|
|||
|
||||
Q_INVOKABLE void uploadData(QString data, QString extension, QScriptValue callback);
|
||||
Q_INVOKABLE void downloadData(QString url, QScriptValue downloadComplete);
|
||||
Q_INVOKABLE void setMapping(QString path, QString hash, QScriptValue callback);
|
||||
Q_INVOKABLE void getMapping(QString path, QScriptValue callback);
|
||||
Q_INVOKABLE void deleteMapping(QString path, QScriptValue callback);
|
||||
Q_INVOKABLE void getAllMappings(QScriptValue callback);
|
||||
protected:
|
||||
QSet<AssetRequest*> _pendingRequests;
|
||||
QScriptEngine* _engine;
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "ResourceCache.h"
|
||||
|
||||
AssetRequest::AssetRequest(const QString& hash, const QString& extension) :
|
||||
QObject(),
|
||||
_hash(hash),
|
||||
_extension(extension)
|
||||
{
|
||||
|
|
|
@ -21,8 +21,6 @@ AssetResourceRequest::~AssetResourceRequest() {
|
|||
}
|
||||
|
||||
void AssetResourceRequest::doSend() {
|
||||
// Make request to atp
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
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<AssetClient>();
|
||||
_assetRequest = assetClient->createRequest(hash, extension);
|
||||
|
||||
if (!_assetRequest) {
|
||||
|
|
|
@ -14,12 +14,18 @@
|
|||
|
||||
#include <cstdint>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QUrl>
|
||||
|
||||
using MessageID = uint32_t;
|
||||
using DataOffset = int64_t;
|
||||
|
||||
using AssetPath = QString;
|
||||
using AssetHash = QString;
|
||||
using AssetMapping = std::map<AssetPath, AssetHash>;
|
||||
|
||||
const size_t SHA256_HASH_LENGTH = 32;
|
||||
const size_t SHA256_HASH_HEX_LENGTH = 64;
|
||||
const uint64_t MAX_UPLOAD_SIZE = 1000 * 1000 * 1000; // 1GB
|
||||
|
@ -32,6 +38,13 @@ enum AssetServerError : uint8_t {
|
|||
PermissionDenied
|
||||
};
|
||||
|
||||
enum AssetMappingOperationType : uint8_t {
|
||||
Get = 0,
|
||||
GetAll,
|
||||
Set,
|
||||
Delete
|
||||
};
|
||||
|
||||
QUrl getATPUrl(const QString& hash, const QString& extension = QString());
|
||||
|
||||
QByteArray hashData(const QByteArray& data);
|
||||
|
|
|
@ -107,6 +107,15 @@ QByteArray ReceivedMessage::readAll() {
|
|||
return read(getBytesLeftToRead());
|
||||
}
|
||||
|
||||
QString ReceivedMessage::readString() {
|
||||
uint32_t size;
|
||||
readPrimitive(&size);
|
||||
//Q_ASSERT(size <= _size - _position);
|
||||
auto string = QString::fromUtf8(_data.constData() + _position, size);
|
||||
_position += size;
|
||||
return string;
|
||||
}
|
||||
|
||||
QByteArray ReceivedMessage::readWithoutCopy(qint64 size) {
|
||||
QByteArray data { QByteArray::fromRawData(_data.constData() + _position, size) };
|
||||
_position += size;
|
||||
|
|
|
@ -63,6 +63,8 @@ public:
|
|||
QByteArray read(qint64 size);
|
||||
QByteArray readAll();
|
||||
|
||||
QString readString();
|
||||
|
||||
QByteArray readHead(qint64 size);
|
||||
|
||||
// This will return a QByteArray referencing the underlying data _without_ refcounting that data.
|
||||
|
@ -86,7 +88,6 @@ private:
|
|||
QByteArray _data;
|
||||
QByteArray _headData;
|
||||
|
||||
std::atomic<qint64> _size { true };
|
||||
std::atomic<qint64> _position { 0 };
|
||||
std::atomic<qint64> _numPackets { 0 };
|
||||
|
||||
|
|
|
@ -150,6 +150,20 @@ QByteArray BasePacket::readWithoutCopy(qint64 maxSize) {
|
|||
return data;
|
||||
}
|
||||
|
||||
qint64 BasePacket::writeString(const QString& string) {
|
||||
QByteArray data = string.toUtf8();
|
||||
writePrimitive(static_cast<uint32_t>(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;
|
||||
|
|
|
@ -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<typename T> qint64 peekPrimitive(T* data);
|
||||
template<typename T> qint64 readPrimitive(T* data);
|
||||
template<typename T> qint64 writePrimitive(const T& data);
|
||||
|
|
|
@ -91,7 +91,9 @@ public:
|
|||
MessagesData,
|
||||
MessagesSubscribe,
|
||||
MessagesUnsubscribe,
|
||||
ICEServerHeartbeatDenied
|
||||
ICEServerHeartbeatDenied,
|
||||
AssetMappingOperation,
|
||||
AssetMappingOperationReply
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -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<uint32_t>(data.length()));
|
||||
return writeData(data.constData(), data.length());
|
||||
}
|
||||
|
||||
qint64 PacketList::writeData(const char* data, qint64 maxSize) {
|
||||
auto sizeRemaining = maxSize;
|
||||
|
||||
|
|
|
@ -59,6 +59,8 @@ public:
|
|||
|
||||
template<typename T> qint64 readPrimitive(T* data);
|
||||
template<typename T> qint64 writePrimitive(const T& data);
|
||||
|
||||
qint64 writeString(const QString& string);
|
||||
|
||||
protected:
|
||||
PacketList(PacketType packetType, QByteArray extendedHeader = QByteArray(), bool isReliable = false, bool isOrdered = false);
|
||||
|
|
Loading…
Reference in a new issue