From: Manuel Nickschas Date: Mon, 21 May 2012 21:30:56 +0000 (+0200) Subject: Provide (de)serialization for all event types X-Git-Tag: 0.9-beta1~68 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=6f38b6fdeb73e726c24b26a97b98c9cfe0fc8a0e Provide (de)serialization for all event types This allows to (de)serialize events to/from QVariantMap (using only primitive types), a prerequisite for sending events over the wire. Use the following functions: void EventManager::createEvent(const QVariantMap &) QVariantMap Event::toVariantMap() Note that there is only rudimentary plausibility checking, so for now we assume that the QVariantMaps are created by Quassel. Before we allow these to go on the wire, we need to make sure that this can't be tinkered with in annoying ways. --- diff --git a/src/common/ctcpevent.cpp b/src/common/ctcpevent.cpp index 1c6546fb..780cda5d 100644 --- a/src/common/ctcpevent.cpp +++ b/src/common/ctcpevent.cpp @@ -19,3 +19,33 @@ ***************************************************************************/ #include "ctcpevent.h" + +Event *CtcpEvent::create(EventManager::EventType type, QVariantMap &map, Network *network) { + if(type == EventManager::CtcpEvent || type == EventManager::CtcpEventFlush) + return new CtcpEvent(type, map, network); + + return 0; +} + + +CtcpEvent::CtcpEvent(EventManager::EventType type, QVariantMap &map, Network *network) + : IrcEvent(type, map, network) +{ + _ctcpType = static_cast(map.take("ctcpType").toInt()); + _ctcpCmd = map.take("ctcpCmd").toString(); + _target = map.take("target").toString(); + _param = map.take("param").toString(); + _reply = map.take("repy").toString(); + _uuid = map.take("uuid").toString(); +} + + +void CtcpEvent::toVariantMap(QVariantMap &map) const { + IrcEvent::toVariantMap(map); + map["ctcpType"] = ctcpType(); + map["ctcpCmd"] = ctcpCmd(); + map["target"] = target(); + map["param"] = param(); + map["reply"] = reply(); + map["uuid"] = uuid().toString(); +} diff --git a/src/common/ctcpevent.h b/src/common/ctcpevent.h index 925bb3ee..42d8995f 100644 --- a/src/common/ctcpevent.h +++ b/src/common/ctcpevent.h @@ -64,7 +64,12 @@ public: inline QUuid uuid() const { return _uuid; } inline void setUuid(const QUuid &uuid) { _uuid = uuid; } + static Event *create(EventManager::EventType type, QVariantMap &map, Network *network); + protected: + explicit CtcpEvent(EventManager::EventType type, QVariantMap &map, Network *network); + void toVariantMap(QVariantMap &map) const; + virtual inline QString className() const { return "CtcpEvent"; } virtual inline void debugInfo(QDebug &dbg) const { NetworkEvent::debugInfo(dbg); diff --git a/src/common/event.cpp b/src/common/event.cpp index 57e7996e..19b56a7d 100644 --- a/src/common/event.cpp +++ b/src/common/event.cpp @@ -18,14 +18,99 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#include "event.h" +#include "ctcpevent.h" +#include "ircevent.h" +#include "networkevent.h" +#include "messageevent.h" Event::Event(EventManager::EventType type) : _type(type) + , _valid(true) { } + +Event::Event(EventManager::EventType type, QVariantMap &map) + : _type(type) + , _valid(true) +{ + if(!map.contains("flags") || !map.contains("timestamp")) { + qWarning() << "Received invalid serialized event:" << map; + setValid(false); + return; + } + + setFlags(static_cast(map.take("flags").toInt())); // TODO sanity check? + setTimestamp(QDateTime::fromTime_t(map.take("timestamp").toUInt())); +} + + +void Event::toVariantMap(QVariantMap &map) const { + map["type"] = static_cast(type()); + map["flags"] = static_cast(flags()); + map["timestamp"] = timestamp().toTime_t(); +} + + +QVariantMap Event::toVariantMap() const { + QVariantMap map; + toVariantMap(map); + return map; +} + + +Event *Event::fromVariantMap(QVariantMap &map, Network *network) { + int inttype = map.take("type").toInt(); + // sanity check if we have a valid enum value + if(EventManager::enumName(inttype).isEmpty()) { + qWarning() << "Received a serialized event with unknown type" << inttype; + return 0; + } + + EventManager::EventType type = static_cast(inttype); + if(type == EventManager::Invalid || type == EventManager::GenericEvent) + return 0; + + EventManager::EventType group = static_cast(type & EventManager::EventGroupMask); + + Event *e = 0; + + // we use static create() functions to keep group-specific special cases in the files they belong + // e.g. IrcEventRawMessage + switch(group) { + case EventManager::NetworkEvent: + e = NetworkEvent::create(type, map, network); + break; + case EventManager::IrcServerEvent: + // not in use! + break; + case EventManager::IrcEvent: + e = IrcEvent::create(type, map, network); + break; + case EventManager::MessageEvent: + e = MessageEvent::create(type, map, network); + break; + case EventManager::CtcpEvent: + e = CtcpEvent::create(type, map, network); + break; + default: + break; + } + + if(!e) { + qWarning() << "Can't create event of type" << type; + return 0; + } + + if(!map.isEmpty()) { + qWarning() << "Event creation from map did not consume all data:" << map; + } + + return e; +} + + QDebug operator<<(QDebug dbg, Event *e) { dbg.nospace() << qPrintable(e->className()) << "(" << "type = 0x" << qPrintable(QString::number(e->type(), 16)); diff --git a/src/common/event.h b/src/common/event.h index 85081c59..e0fb8e39 100644 --- a/src/common/event.h +++ b/src/common/event.h @@ -26,11 +26,13 @@ #include "eventmanager.h" +class Network; + class Event { public: explicit Event(EventManager::EventType type = EventManager::Invalid); - virtual ~Event() {}; + virtual ~Event() {} inline EventManager::EventType type() const { return _type; } @@ -39,6 +41,7 @@ public: inline bool testFlag(EventManager::EventFlag flag) { return _flags.testFlag(flag); } inline EventManager::EventFlags flags() const { return _flags; } + inline bool isValid() const { return _valid; } inline void stop() { setFlag(EventManager::Stopped); } inline bool isStopped() { return _flags.testFlag(EventManager::Stopped); } @@ -48,15 +51,28 @@ public: //inline void setData(const QVariant &data) { _data = data; } //inline QVariant data() const { return _data; } + // call EventManager::createEvent(map) instead! + static Event *fromVariantMap(QVariantMap &map, Network *network); + QVariantMap toVariantMap() const; + protected: virtual inline QString className() const { return "Event"; } virtual inline void debugInfo(QDebug &dbg) const { Q_UNUSED(dbg); } + explicit Event(EventManager::EventType type, QVariantMap &map); + + // must only use primitive types: string, int, double, list, hash + // we want to convert this to JSON in the future! + virtual void toVariantMap(QVariantMap &map) const; + + inline void setValid(bool valid) { _valid = valid; } + private: EventManager::EventType _type; EventManager::EventFlags _flags; QDateTime _timestamp; //QVariant _data; + bool _valid; friend QDebug operator<<(QDebug dbg, Event *e); }; diff --git a/src/common/eventmanager.cpp b/src/common/eventmanager.cpp index 03e891f4..03c04df3 100644 --- a/src/common/eventmanager.cpp +++ b/src/common/eventmanager.cpp @@ -72,6 +72,13 @@ QString EventManager::enumName(int type) { return eventEnum().valueToKey(type); } +Event *EventManager::createEvent(const QVariantMap &map) { + QVariantMap m = map; + + Network *net = networkById(m.take("network").toInt()); + return Event::fromVariantMap(m, net); +} + /* NOTE: Registering and calling handlers works fine even if they specify a subclass of Event as their parameter. However, this most probably is a result from a reinterpret_cast somewhere deep inside Qt, so there is *no* diff --git a/src/common/eventmanager.h b/src/common/eventmanager.h index 7ead8ba1..eb319212 100644 --- a/src/common/eventmanager.h +++ b/src/common/eventmanager.h @@ -23,7 +23,10 @@ #include +#include "types.h" + class Event; +class Network; class EventManager : public QObject { Q_OBJECT @@ -53,7 +56,7 @@ public: Silent = 0x40, ///< Don't generate a MessageEvent Stopped = 0x80 }; - Q_DECLARE_FLAGS(EventFlags, EventFlag); + Q_DECLARE_FLAGS(EventFlags, EventFlag) /* @@ -107,7 +110,7 @@ public: MessageEvent = 0x00040000, ///< Stringified event suitable for converting to Message CtcpEvent = 0x00050000, - CtcpEventFlush, + CtcpEventFlush }; EventManager(QObject *parent = 0); @@ -117,6 +120,8 @@ public: static QString enumName(EventType type); static QString enumName(int type); // for sanity tests + Event *createEvent(const QVariantMap &map); + public slots: void registerObject(QObject *object, Priority priority = NormalPriority, const QString &methodPrefix = "process", @@ -137,6 +142,7 @@ public slots: void postEvent(Event *event); protected: + virtual Network *networkById(NetworkId id) const = 0; virtual void customEvent(QEvent *event); private: diff --git a/src/common/ircevent.cpp b/src/common/ircevent.cpp index 9757c287..b9f7e45b 100644 --- a/src/common/ircevent.cpp +++ b/src/common/ircevent.cpp @@ -19,3 +19,63 @@ ***************************************************************************/ #include "ircevent.h" + +Event *IrcEvent::create(EventManager::EventType type, QVariantMap &map, Network *network) { + if((type & EventManager::IrcEventNumericMask) == EventManager::IrcEventNumeric) + return new IrcEventNumeric(type, map, network); + + if((type & EventManager::EventGroupMask) != EventManager::IrcEvent) + return 0; + + switch(type) { + case EventManager::IrcEventRawPrivmsg: + case EventManager::IrcEventRawNotice: + return new IrcEventRawMessage(type, map, network); + + default: + return new IrcEvent(type, map, network); + } +} + + +IrcEvent::IrcEvent(EventManager::EventType type, QVariantMap &map, Network *network) + : NetworkEvent(type, map, network) +{ + _prefix = map.take("prefix").toString(); + _params = map.take("params").toStringList(); +} + + +void IrcEvent::toVariantMap(QVariantMap &map) const { + NetworkEvent::toVariantMap(map); + map["prefix"] = prefix(); + map["params"] = params(); +} + + +IrcEventNumeric::IrcEventNumeric(EventManager::EventType type, QVariantMap &map, Network *network) + : IrcEvent(type, map, network) +{ + _number = map.take("number").toUInt(); + _target = map.take("target").toString(); +} + + +void IrcEventNumeric::toVariantMap(QVariantMap &map) const { + IrcEvent::toVariantMap(map); + map["number"] = number(); + map["target"] = target(); +} + + +IrcEventRawMessage::IrcEventRawMessage(EventManager::EventType type, QVariantMap &map, Network *network) + : IrcEvent(type, map, network) +{ + _rawMessage = map.take("rawMessage").toByteArray(); +} + + +void IrcEventRawMessage::toVariantMap(QVariantMap &map) const { + IrcEvent::toVariantMap(map); + map["rawMessage"] = rawMessage(); +} diff --git a/src/common/ircevent.h b/src/common/ircevent.h index 5b93d61e..71e4ad28 100644 --- a/src/common/ircevent.h +++ b/src/common/ircevent.h @@ -40,7 +40,12 @@ public: inline QStringList params() const { return _params; } inline void setParams(const QStringList ¶ms) { _params = params; } + static Event *create(EventManager::EventType type, QVariantMap &map, Network *network); + protected: + explicit IrcEvent(EventManager::EventType type, QVariantMap &map, Network *network); + void toVariantMap(QVariantMap &map) const; + virtual inline QString className() const { return "IrcEvent"; } virtual inline void debugInfo(QDebug &dbg) const { NetworkEvent::debugInfo(dbg); @@ -68,6 +73,9 @@ public: inline void setTarget(const QString &target) { _target = target; } protected: + explicit IrcEventNumeric(EventManager::EventType type, QVariantMap &map, Network *network); + void toVariantMap(QVariantMap &map) const; + virtual inline QString className() const { return "IrcEventNumeric"; } virtual inline void debugInfo(QDebug &dbg) const { dbg << ", num = " << number(); @@ -81,6 +89,7 @@ private: uint _number; QString _target; + friend class IrcEvent; }; class IrcEventRawMessage : public IrcEvent { @@ -101,6 +110,9 @@ public: inline void setRawMessage(const QByteArray &rawMessage) { _rawMessage = rawMessage; } protected: + explicit IrcEventRawMessage(EventManager::EventType type, QVariantMap &map, Network *network); + void toVariantMap(QVariantMap &map) const; + virtual inline QString className() const { return "IrcEventRawMessage"; } virtual inline void debugInfo(QDebug &dbg) const { NetworkEvent::debugInfo(dbg); @@ -112,6 +124,8 @@ protected: private: QByteArray _rawMessage; + + friend class IrcEvent; }; #endif diff --git a/src/common/messageevent.cpp b/src/common/messageevent.cpp index 6c36715e..606103e9 100644 --- a/src/common/messageevent.cpp +++ b/src/common/messageevent.cpp @@ -20,6 +20,13 @@ #include "messageevent.h" +Event *MessageEvent::create(EventManager::EventType type, QVariantMap &map, Network *network) { + if(type == EventManager::MessageEvent) + return new MessageEvent(type, map, network); + + return 0; +} + MessageEvent::MessageEvent(Message::Type msgType, Network *net, const QString &msg, const QString &sender, const QString &target, Message::Flags flags, const QDateTime ×tamp) @@ -47,6 +54,30 @@ MessageEvent::MessageEvent(Message::Type msgType, Network *net, const QString &m setTimestamp(QDateTime::currentDateTime()); } + +MessageEvent::MessageEvent(EventManager::EventType type, QVariantMap &map, Network *network) + : NetworkEvent(type, map, network) +{ + _msgType = static_cast(map.take("messageType").toInt()); + _msgFlags = static_cast(map.take("messageFlags").toInt()); + _bufferType = static_cast(map.take("bufferType").toInt()); + _text = map.take("text").toString(); + _sender = map.take("sender").toString(); + _target = map.take("target").toString(); +} + + +void MessageEvent::toVariantMap(QVariantMap &map) const { + NetworkEvent::toVariantMap(map); + map["messageType"] = msgType(); + map["messageFlags"] = (int)msgFlags(); + map["bufferType"] = bufferType(); + map["text"] = text(); + map["sender"] = sender(); + map["target"] = target(); +} + + BufferInfo::Type MessageEvent::bufferTypeByTarget(const QString &target) const { if(target.isEmpty()) return BufferInfo::StatusBuffer; diff --git a/src/common/messageevent.h b/src/common/messageevent.h index cf77dcee..e93794cd 100644 --- a/src/common/messageevent.h +++ b/src/common/messageevent.h @@ -53,7 +53,12 @@ public: inline void setMsgFlag(Message::Flag flag) { _msgFlags |= flag; } inline void setMsgFlags(Message::Flags flags) { _msgFlags = flags; } + static Event *create(EventManager::EventType type, QVariantMap &map, Network *network); + protected: + explicit MessageEvent(EventManager::EventType type, QVariantMap &map, Network *network); + void toVariantMap(QVariantMap &map) const; + virtual inline QString className() const { return "MessageEvent"; } virtual inline void debugInfo(QDebug &dbg) const { NetworkEvent::debugInfo(dbg); diff --git a/src/common/networkevent.cpp b/src/common/networkevent.cpp index d723b192..1752b586 100644 --- a/src/common/networkevent.cpp +++ b/src/common/networkevent.cpp @@ -19,3 +19,83 @@ ***************************************************************************/ #include "networkevent.h" + +Event *NetworkEvent::create(EventManager::EventType type, QVariantMap &map, Network *network) { + switch(type) { + case EventManager::NetworkIncoming: + return new NetworkDataEvent(type, map, network); + + case EventManager::NetworkConnecting: + case EventManager::NetworkInitializing: + case EventManager::NetworkInitialized: + case EventManager::NetworkReconnecting: + case EventManager::NetworkDisconnecting: + case EventManager::NetworkDisconnected: + return new NetworkConnectionEvent(type, map, network); + + case EventManager::NetworkSplitJoin: + case EventManager::NetworkSplitQuit: + return new NetworkSplitEvent(type, map, network); + + default: + return 0; + } +} + + +NetworkEvent::NetworkEvent(EventManager::EventType type, QVariantMap &map, Network *network) + : Event(type, map) + , _network(network) +{ + +} + + +void NetworkEvent::toVariantMap(QVariantMap &map) const { + Event::toVariantMap(map); + map["network"] = networkId().toInt(); +} + + +NetworkDataEvent::NetworkDataEvent(EventManager::EventType type, QVariantMap &map, Network *network) + : NetworkEvent(type, map, network) +{ + _data = map.take("data").toByteArray(); +} + + +void NetworkDataEvent::toVariantMap(QVariantMap &map) const { + NetworkEvent::toVariantMap(map); + map["data"] = data(); +} + + +NetworkConnectionEvent::NetworkConnectionEvent(EventManager::EventType type, QVariantMap &map, Network *network) + : NetworkEvent(type, map, network) +{ + _state = static_cast(map.take("state").toInt()); // FIXME: check enum plausibility +} + + +void NetworkConnectionEvent::toVariantMap(QVariantMap &map) const { + NetworkEvent::toVariantMap(map); + map["state"] = connectionState(); +} + + +NetworkSplitEvent::NetworkSplitEvent(EventManager::EventType type, QVariantMap &map, Network *network) + : NetworkEvent(type, map, network) +{ + _channel = map.take("channel").toString(); + _users = map.take("users").toStringList(); + _quitMsg = map.take("quitMessage").toString(); +} + + +void NetworkSplitEvent::toVariantMap(QVariantMap &map) const +{ + NetworkEvent::toVariantMap(map); + map["channel"] = channel(); + map["users"] = users(); + map["quitMessage"] = quitMessage(); +} diff --git a/src/common/networkevent.h b/src/common/networkevent.h index 5a08733d..7e46984a 100644 --- a/src/common/networkevent.h +++ b/src/common/networkevent.h @@ -38,7 +38,12 @@ public: inline NetworkId networkId() const { return network()? network()->networkId() : NetworkId(); } inline Network *network() const { return _network; } + static Event *create(EventManager::EventType type, QVariantMap &map, Network *network); + protected: + explicit NetworkEvent(EventManager::EventType type, QVariantMap &map, Network *network); + void toVariantMap(QVariantMap &map) const; + virtual inline QString className() const { return "NetworkEvent"; } virtual inline void debugInfo(QDebug &dbg) const { dbg.nospace() << ", net = " << qPrintable(_network->networkName()); } @@ -46,6 +51,8 @@ private: Network *_network; }; +/*****************************************************************************/ + class NetworkConnectionEvent : public NetworkEvent { public: @@ -58,6 +65,9 @@ public: inline void setConnectionState(Network::ConnectionState state) { _state = state; } protected: + explicit NetworkConnectionEvent(EventManager::EventType type, QVariantMap &map, Network *network); + void toVariantMap(QVariantMap &map) const; + virtual inline QString className() const { return "NetworkConnectionEvent"; } virtual inline void debugInfo(QDebug &dbg) const { NetworkEvent::debugInfo(dbg); @@ -66,6 +76,8 @@ protected: private: Network::ConnectionState _state; + + friend class NetworkEvent; }; class NetworkDataEvent : public NetworkEvent { @@ -80,6 +92,9 @@ public: inline void setData(const QByteArray &data) { _data = data; } protected: + explicit NetworkDataEvent(EventManager::EventType type, QVariantMap &map, Network *network); + void toVariantMap(QVariantMap &map) const; + virtual inline QString className() const { return "NetworkDataEvent"; } virtual inline void debugInfo(QDebug &dbg) const { NetworkEvent::debugInfo(dbg); @@ -88,6 +103,8 @@ protected: private: QByteArray _data; + + friend class NetworkEvent; }; class NetworkSplitEvent : public NetworkEvent { @@ -108,10 +125,24 @@ public: inline QStringList users() const { return _users; } inline QString quitMessage() const { return _quitMsg; } +protected: + explicit NetworkSplitEvent(EventManager::EventType type, QVariantMap &map, Network *network); + void toVariantMap(QVariantMap &map) const; + + virtual inline QString className() const { return "NetworkSplitEvent"; } + virtual inline void debugInfo(QDebug &dbg) const { + NetworkEvent::debugInfo(dbg); + dbg.nospace() << ", channel = " << qPrintable(channel()) + << ", users = " << users() + << ", quitmsg = " << quitMessage(); + } + private: QString _channel; QStringList _users; QString _quitMsg; + + friend class NetworkEvent; }; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 5c6f0b69..6df50bf4 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -46,6 +46,7 @@ set(MOC_HDRS corebufferviewconfig.h corebufferviewmanager.h corecoreinfo.h + coreeventmanager.h coreidentity.h coreignorelistmanager.h coreircchannel.h diff --git a/src/core/coreeventmanager.h b/src/core/coreeventmanager.h new file mode 100644 index 00000000..41e5f1c9 --- /dev/null +++ b/src/core/coreeventmanager.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2005-2012 by the Quassel Project * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef COREEVENTMANAGER_H +#define COREEVENTMANAGER_H + +#include "corenetwork.h" +#include "coresession.h" +#include "eventmanager.h" + +class CoreSession; + +class CoreEventManager : public EventManager +{ + Q_OBJECT + +public: + CoreEventManager(CoreSession *session) + : EventManager(session) + , _coreSession(session) + { } + +protected: + inline Network *networkById(NetworkId id) const { return _coreSession->network(id); } + +private: + CoreSession *_coreSession; +}; + +#endif diff --git a/src/core/coresession.cpp b/src/core/coresession.cpp index 603d291f..6c0c5e13 100644 --- a/src/core/coresession.cpp +++ b/src/core/coresession.cpp @@ -27,6 +27,7 @@ #include "corebuffersyncer.h" #include "corebacklogmanager.h" #include "corebufferviewmanager.h" +#include "coreeventmanager.h" #include "coreidentity.h" #include "coreignorelistmanager.h" #include "coreirclisthelper.h" @@ -35,7 +36,6 @@ #include "coresessioneventprocessor.h" #include "coreusersettings.h" #include "ctcpparser.h" -#include "eventmanager.h" #include "eventstringifier.h" #include "ircchannel.h" #include "ircparser.h" @@ -62,7 +62,7 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent) _ircListHelper(new CoreIrcListHelper(this)), _networkConfig(new CoreNetworkConfig("GlobalNetworkConfig", this)), _coreInfo(this), - _eventManager(new EventManager(this)), + _eventManager(new CoreEventManager(this)), _eventStringifier(new EventStringifier(this)), _sessionEventProcessor(new CoreSessionEventProcessor(this)), _ctcpParser(new CtcpParser(this)),