dynamic compression support

This commit is contained in:
Max-Wilhelm Bruker 2011-06-25 15:58:38 +02:00
parent cc795a2dd7
commit d892d320ea
9 changed files with 85 additions and 13 deletions

View file

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

View file

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

View file

@ -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<ProtocolItem *>(getNewItem(childName + childSubType));
if (!currentItem)
currentItem = new ProtocolItem_Invalid;
if (xml->attributes().value("comp").toString().toInt() == 1)
currentItem->setCompressed(true);
readCurrentItem(xml);
}

View file

@ -1,7 +1,8 @@
#include "serializable_item.h"
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QDebug>
#include <QBuffer>
QHash<QString, SerializableItem::NewItemFunction> 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 = "<d>" + qUncompress(QByteArray::fromBase64(compressedData)) + "</d>";
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,6 +58,18 @@ void SerializableItem::write(QXmlStreamWriter *xml)
xml->writeStartElement(itemType);
if (!itemSubType.isEmpty())
xml->writeAttribute("type", itemSubType);
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);

View file

@ -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<QString, NewItemFunction> 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);
};

View file

@ -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<ServerInfo_User *> _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;
}

View file

@ -30,6 +30,7 @@ protected:
QMap<QString, ServerInfo_User *> buddyList, ignoreList;
void prepareDestroy();
virtual bool getCompressionSupport() const = 0;
private:
QList<ProtocolItem *> itemQueue;
QList<int> messageSizeOverTime, messageCountOverTime;

View file

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

View file

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