Merge pull request #76 from huffman/atp-mappings

Atp mappings
This commit is contained in:
Stephen Birarda 2016-03-08 11:21:18 -08:00
commit 79e788523b
14 changed files with 614 additions and 11 deletions

View file

@ -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() {
}

View file

@ -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;
};

View file

@ -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();
}

View file

@ -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;

View file

@ -21,7 +21,6 @@
#include "ResourceCache.h"
AssetRequest::AssetRequest(const QString& hash, const QString& extension) :
QObject(),
_hash(hash),
_extension(extension)
{

View file

@ -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) {

View file

@ -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);

View file

@ -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;

View file

@ -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 };

View file

@ -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;

View file

@ -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);

View file

@ -91,7 +91,9 @@ public:
MessagesData,
MessagesSubscribe,
MessagesUnsubscribe,
ICEServerHeartbeatDenied
ICEServerHeartbeatDenied,
AssetMappingOperation,
AssetMappingOperationReply
};
};

View file

@ -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;

View file

@ -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);