From d892d320eabf542664efb61970a86eaefa5593b6 Mon Sep 17 00:00:00 2001 From: Max-Wilhelm Bruker Date: Sat, 25 Jun 2011 15:58:38 +0200 Subject: [PATCH] dynamic compression support --- cockatrice/src/localserverinterface.h | 3 +- cockatrice/src/remoteclient.cpp | 1 + common/protocol.cpp | 4 +- common/serializable_item.cpp | 49 ++++++++++++++++++++++-- common/serializable_item.h | 8 +++- common/server_protocolhandler.cpp | 20 ++++++++-- common/server_protocolhandler.h | 1 + servatrice/src/serversocketinterface.cpp | 9 ++++- servatrice/src/serversocketinterface.h | 3 ++ 9 files changed, 85 insertions(+), 13 deletions(-) diff --git a/cockatrice/src/localserverinterface.h b/cockatrice/src/localserverinterface.h index 26194147..1db97412 100644 --- a/cockatrice/src/localserverinterface.h +++ b/cockatrice/src/localserverinterface.h @@ -21,12 +21,13 @@ private: ResponseCode cmdBanFromServer(Command_BanFromServer * /*cmd*/, CommandContainer * /*cont*/) { return RespFunctionNotAllowed; } ResponseCode cmdShutdownServer(Command_ShutdownServer * /*cmd*/, CommandContainer * /*cont*/) { return RespFunctionNotAllowed; } ResponseCode cmdUpdateServerMessage(Command_UpdateServerMessage * /*cmd*/, CommandContainer * /*cont*/) { return RespFunctionNotAllowed; } +protected: + bool getCompressionSupport() const { return false; } public: LocalServerInterface(LocalServer *_server); ~LocalServerInterface(); void sendProtocolItem(ProtocolItem *item, bool deleteItem = true); - signals: void itemToClient(ProtocolItem *item); public slots: diff --git a/cockatrice/src/remoteclient.cpp b/cockatrice/src/remoteclient.cpp index fac63019..8f084487 100644 --- a/cockatrice/src/remoteclient.cpp +++ b/cockatrice/src/remoteclient.cpp @@ -83,6 +83,7 @@ void RemoteClient::readData() xmlWriter->writeStartDocument(); xmlWriter->writeStartElement("cockatrice_client_stream"); xmlWriter->writeAttribute("version", QString::number(ProtocolItem::protocolVersion)); + xmlWriter->writeAttribute("comp", "1"); topLevelItem = new TopLevelProtocolItem; connect(topLevelItem, SIGNAL(protocolItemReceived(ProtocolItem *)), this, SLOT(processProtocolItem(ProtocolItem *))); diff --git a/common/protocol.cpp b/common/protocol.cpp index fe3997ad..1129116e 100644 --- a/common/protocol.cpp +++ b/common/protocol.cpp @@ -74,7 +74,7 @@ TopLevelProtocolItem::TopLevelProtocolItem() bool TopLevelProtocolItem::readCurrentItem(QXmlStreamReader *xml) { if (currentItem) { - if (currentItem->readElement(xml)) { + if (currentItem->read(xml)) { emit protocolItemReceived(currentItem); currentItem = 0; } @@ -92,6 +92,8 @@ bool TopLevelProtocolItem::readElement(QXmlStreamReader *xml) currentItem = dynamic_cast(getNewItem(childName + childSubType)); if (!currentItem) currentItem = new ProtocolItem_Invalid; + if (xml->attributes().value("comp").toString().toInt() == 1) + currentItem->setCompressed(true); readCurrentItem(xml); } diff --git a/common/serializable_item.cpp b/common/serializable_item.cpp index 9c1a7c81..42c14251 100644 --- a/common/serializable_item.cpp +++ b/common/serializable_item.cpp @@ -1,7 +1,8 @@ #include "serializable_item.h" #include #include -#include +#include + QHash SerializableItem::itemNameHash; SerializableItem *SerializableItem::getNewItem(const QString &name) @@ -16,6 +17,32 @@ void SerializableItem::registerSerializableItem(const QString &name, NewItemFunc itemNameHash.insert(name, func); } +bool SerializableItem::read(QXmlStreamReader *xml) +{ + if (!compressed) + return readElement(xml); + if (xml->isEndElement() && (xml->name() == itemType)) { + QByteArray uncompressedData = "" + qUncompress(QByteArray::fromBase64(compressedData)) + ""; + compressedData.clear(); + QBuffer compressedBuffer(&uncompressedData); + compressedBuffer.open(QIODevice::ReadOnly); + QXmlStreamReader *xml2 = new QXmlStreamReader(&compressedBuffer); + while (!xml2->atEnd()) { + xml2->readNext(); + if (xml2->name() == "d") + continue; + readElement(xml2); + } + delete xml2; + compressedBuffer.close(); + + return readElement(xml); + } else { + compressedData.append(xml->text().toString()); + return false; + } +} + bool SerializableItem::readElement(QXmlStreamReader *xml) { if (xml->isEndElement() && (xml->name() == itemType)) @@ -31,7 +58,19 @@ void SerializableItem::write(QXmlStreamWriter *xml) xml->writeStartElement(itemType); if (!itemSubType.isEmpty()) xml->writeAttribute("type", itemSubType); - writeElement(xml); + if (compressed) { + xml->writeAttribute("comp", "1"); + + QBuffer compressBuffer; + compressBuffer.open(QIODevice::WriteOnly); + QXmlStreamWriter *xml2 = new QXmlStreamWriter(&compressBuffer); + writeElement(xml2); + delete xml2; + compressBuffer.close(); + + xml->writeCharacters(qCompress(compressBuffer.data()).toBase64()); + } else + writeElement(xml); xml->writeEndElement(); } @@ -47,7 +86,7 @@ SerializableItem_Map::~SerializableItem_Map() bool SerializableItem_Map::readElement(QXmlStreamReader *xml) { if (currentItem) { - if (currentItem->readElement(xml)) + if (currentItem->read(xml)) currentItem = 0; return false; } else if (firstItem) @@ -57,6 +96,7 @@ bool SerializableItem_Map::readElement(QXmlStreamReader *xml) else if (xml->isStartElement()) { QString childName = xml->name().toString(); QString childSubType = xml->attributes().value("type").toString(); + bool childCompressed = xml->attributes().value("comp").toString().toInt() == 1; currentItem = itemMap.value(childName); if (!currentItem) { currentItem = getNewItem(childName + childSubType); @@ -64,7 +104,8 @@ bool SerializableItem_Map::readElement(QXmlStreamReader *xml) if (!currentItem) currentItem = new SerializableItem_Invalid(childName); } - if (currentItem->readElement(xml)) + currentItem->setCompressed(childCompressed); + if (currentItem->read(xml)) currentItem = 0; } return SerializableItem::readElement(xml); diff --git a/common/serializable_item.h b/common/serializable_item.h index 979ebb98..50da5e36 100644 --- a/common/serializable_item.h +++ b/common/serializable_item.h @@ -15,6 +15,10 @@ class QXmlStreamWriter; class SerializableItem : public QObject { Q_OBJECT +private: + bool compressed; + QByteArray compressedData; + QXmlStreamReader *compressedReader; protected: typedef SerializableItem *(*NewItemFunction)(); static QHash itemNameHash; @@ -23,7 +27,7 @@ protected: bool firstItem; public: SerializableItem(const QString &_itemType, const QString &_itemSubType = QString()) - : QObject(), itemType(_itemType), itemSubType(_itemSubType), firstItem(true) { } + : QObject(), compressed(false), itemType(_itemType), itemSubType(_itemSubType), firstItem(true) { } static void registerSerializableItem(const QString &name, NewItemFunction func); static SerializableItem *getNewItem(const QString &name); const QString &getItemType() const { return itemType; } @@ -31,6 +35,8 @@ public: virtual bool readElement(QXmlStreamReader *xml); virtual void writeElement(QXmlStreamWriter *xml) = 0; virtual bool isEmpty() const = 0; + void setCompressed(bool _compressed) { compressed = _compressed; } + bool read(QXmlStreamReader *xml); void write(QXmlStreamWriter *xml); }; diff --git a/common/server_protocolhandler.cpp b/common/server_protocolhandler.cpp index 10729b8b..b461f833 100644 --- a/common/server_protocolhandler.cpp +++ b/common/server_protocolhandler.cpp @@ -286,7 +286,10 @@ ResponseCode Server_ProtocolHandler::cmdLogin(Command_Login *cmd, CommandContain if (authState == WouldOverwriteOldSession) return RespWouldOverwriteOldSession; - enqueueProtocolItem(new Event_ServerMessage(server->getLoginMessage())); + ProtocolItem *serverMessage = new Event_ServerMessage(server->getLoginMessage()); + if (getCompressionSupport()) + serverMessage->setCompressed(true); + enqueueProtocolItem(serverMessage); QList _buddyList, _ignoreList; if (authState == PasswordRight) { @@ -303,7 +306,10 @@ ResponseCode Server_ProtocolHandler::cmdLogin(Command_Login *cmd, CommandContain _ignoreList.append(new ServerInfo_User(ignoreIterator.next().value())); } - cont->setResponse(new Response_Login(cont->getCmdId(), RespOk, new ServerInfo_User(userInfo, true), _buddyList, _ignoreList)); + ProtocolResponse *resp = new Response_Login(cont->getCmdId(), RespOk, new ServerInfo_User(userInfo, true), _buddyList, _ignoreList); + if (getCompressionSupport()) + resp->setCompressed(true); + cont->setResponse(resp); return RespNothing; } @@ -395,7 +401,10 @@ ResponseCode Server_ProtocolHandler::cmdJoinRoom(Command_JoinRoom *cmd, CommandC } } - cont->setResponse(new Response_JoinRoom(cont->getCmdId(), RespOk, r->getInfo(true))); + ServerInfo_Room *info = r->getInfo(true); + if (getCompressionSupport()) + info->setCompressed(true); + cont->setResponse(new Response_JoinRoom(cont->getCmdId(), RespOk, info)); return RespNothing; } @@ -444,7 +453,10 @@ ResponseCode Server_ProtocolHandler::cmdListUsers(Command_ListUsers * /*cmd*/, C acceptsUserListChanges = true; - cont->setResponse(new Response_ListUsers(cont->getCmdId(), RespOk, resultList)); + ProtocolResponse *resp = new Response_ListUsers(cont->getCmdId(), RespOk, resultList); + if (getCompressionSupport()) + resp->setCompressed(true); + cont->setResponse(resp); return RespNothing; } diff --git a/common/server_protocolhandler.h b/common/server_protocolhandler.h index 5817da22..a73c3008 100644 --- a/common/server_protocolhandler.h +++ b/common/server_protocolhandler.h @@ -30,6 +30,7 @@ protected: QMap buddyList, ignoreList; void prepareDestroy(); + virtual bool getCompressionSupport() const = 0; private: QList itemQueue; QList messageSizeOverTime, messageCountOverTime; diff --git a/servatrice/src/serversocketinterface.cpp b/servatrice/src/serversocketinterface.cpp index 14628a42..769e6588 100644 --- a/servatrice/src/serversocketinterface.cpp +++ b/servatrice/src/serversocketinterface.cpp @@ -33,7 +33,7 @@ #include "server_logger.h" ServerSocketInterface::ServerSocketInterface(Servatrice *_server, QTcpSocket *_socket, QObject *parent) - : Server_ProtocolHandler(_server, parent), servatrice(_server), socket(_socket), topLevelItem(0) + : Server_ProtocolHandler(_server, parent), servatrice(_server), socket(_socket), topLevelItem(0), compressionSupport(false) { xmlWriter = new QXmlStreamWriter(&xmlBuffer); xmlReader = new QXmlStreamReader; @@ -101,6 +101,8 @@ void ServerSocketInterface::readClient() if (topLevelItem) topLevelItem->readElement(xmlReader); else if (xmlReader->isStartElement() && (xmlReader->name().toString() == "cockatrice_client_stream")) { + if (xmlReader->attributes().value("comp").toString().toInt() == 1) + compressionSupport = true; topLevelItem = new TopLevelProtocolItem; connect(topLevelItem, SIGNAL(protocolItemReceived(ProtocolItem *)), this, SLOT(processProtocolItem(ProtocolItem *))); } @@ -295,7 +297,10 @@ ResponseCode ServerSocketInterface::cmdDeckList(Command_DeckList * /*cmd*/, Comm if (!deckListHelper(root)) return RespContextError; - cont->setResponse(new Response_DeckList(cont->getCmdId(), RespOk, root)); + ProtocolResponse *resp = new Response_DeckList(cont->getCmdId(), RespOk, root); + if (getCompressionSupport()) + resp->setCompressed(true); + cont->setResponse(resp); return RespNothing; } diff --git a/servatrice/src/serversocketinterface.h b/servatrice/src/serversocketinterface.h index a155b421..14cf7030 100644 --- a/servatrice/src/serversocketinterface.h +++ b/servatrice/src/serversocketinterface.h @@ -51,6 +51,7 @@ private: QXmlStreamReader *xmlReader; QString xmlBuffer; TopLevelProtocolItem *topLevelItem; + bool compressionSupport; int getUserIdInDB(const QString &name) const; ResponseCode cmdAddToList(Command_AddToList *cmd, CommandContainer *cont); @@ -69,6 +70,8 @@ private: ResponseCode cmdBanFromServer(Command_BanFromServer *cmd, CommandContainer *cont); ResponseCode cmdShutdownServer(Command_ShutdownServer *cmd, CommandContainer *cont); ResponseCode cmdUpdateServerMessage(Command_UpdateServerMessage *cmd, CommandContainer *cont); +protected: + bool getCompressionSupport() const { return compressionSupport; } public: ServerSocketInterface(Servatrice *_server, QTcpSocket *_socket, QObject *parent = 0); ~ServerSocketInterface();