diff options
author | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2018-07-01 22:48:38 +0900 |
---|---|---|
committer | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2018-07-04 09:07:32 +0900 |
commit | f1ffe1e7a3e81c07a07a8416ce307e4413ec8fbc (patch) | |
tree | f2435183d11a4cea52a7532eb9ff3d4d837e1d22 /lib/events/event.cpp | |
parent | d5397fe5ae2ca34d5cfb11394dac17728a2b50ce (diff) | |
download | libquotient-f1ffe1e7a3e81c07a07a8416ce307e4413ec8fbc.tar.gz libquotient-f1ffe1e7a3e81c07a07a8416ce307e4413ec8fbc.zip |
Event types system remade to be extensible
There were two common points that had to be updated every time a new event is introduced:
the EventType enumeration and one of 3 doMakeEvent<> specialisations. The new code
has a template class, EventFactory<>, that uses a list of static factory methods
to create events instead of typelists used in doMakeEvent<>(); the EventType enumeration
is replaced with a namespace populated with constants as necessary.
In general, EventType is considered a deprecated mechanism altogether; instead, a set
of facilities is provided: is<>() to check if an event has a certain type (to replace
comparison against an EventType value) and visit<>() to execute actions based on
the event type (replacing switch statements over EventType values).
Closes #129.
Diffstat (limited to 'lib/events/event.cpp')
-rw-r--r-- | lib/events/event.cpp | 140 |
1 files changed, 48 insertions, 92 deletions
diff --git a/lib/events/event.cpp b/lib/events/event.cpp index 576e9426..3f507347 100644 --- a/lib/events/event.cpp +++ b/lib/events/event.cpp @@ -33,117 +33,93 @@ using namespace QMatrixClient; -Event::Event(Type type, const QJsonObject& rep) - : _type(type), _originalJson(rep) +event_type_t EventTypeRegistry::nextTypeId() { - if (!rep.contains("content") && - !rep.value("unsigned").toObject().contains("redacted_because")) + static event_type_t typeIndex = unknownTypeId(); + return ++typeIndex; +} + +Event::Event(Type type, const QJsonObject& json) + : _type(type), _json(json) +{ + if (!json.contains(ContentKeyL) && + !json.value(UnsignedKeyL).toObject().contains(RedactedCauseKeyL)) { qCWarning(EVENTS) << "Event without 'content' node"; - qCWarning(EVENTS) << formatJson << rep; + qCWarning(EVENTS) << formatJson << json; } } +Event::Event(Type type, event_mtype_t matrixType, const QJsonObject& contentJson) + : Event(type, basicEventJson(matrixType, contentJson)) +{ } + Event::~Event() = default; -QString Event::jsonType() const +QString Event::matrixType() const { - return originalJsonObject().value("type").toString(); + return fullJson()[TypeKeyL].toString(); } QByteArray Event::originalJson() const { - return QJsonDocument(_originalJson).toJson(); -} - -QJsonObject Event::originalJsonObject() const -{ - return _originalJson; + return QJsonDocument(_json).toJson(); } const QJsonObject Event::contentJson() const { - return _originalJson["content"].toObject(); -} - -template <typename BaseEventT> -inline event_ptr_tt<BaseEventT> makeIfMatches(const QJsonObject&, const QString&) -{ - return nullptr; + return fullJson()[ContentKeyL].toObject(); } -template <typename BaseEventT, typename EventT, typename... EventTs> -inline event_ptr_tt<BaseEventT> makeIfMatches(const QJsonObject& o, - const QString& selector) +const QJsonObject Event::unsignedJson() const { - if (selector == EventT::typeId()) - return _impl::create<EventT>(o); - - return makeIfMatches<BaseEventT, EventTs...>(o, selector); + return fullJson()[UnsignedKeyL].toObject(); } -template <> -EventPtr _impl::doMakeEvent<Event>(const QJsonObject& obj) -{ - // Check more specific event types first - if (auto e = doMakeEvent<RoomEvent>(obj)) - return ptrCast<Event>(move(e)); - - return makeIfMatches<Event, - TypingEvent, ReceiptEvent, TagEvent, ReadMarkerEvent, DirectChatEvent>( - obj, obj["type"].toString()); -} +[[gnu::unused]] static auto roomEventTypeInitialised = + EventTypeRegistry::chainFactories<Event, RoomEvent>(); -RoomEvent::RoomEvent(Event::Type type) : Event(type) { } +RoomEvent::RoomEvent(Type type, event_mtype_t matrixType, + const QJsonObject& contentJson) + : Event(type, matrixType, contentJson) +{ } -RoomEvent::RoomEvent(Type type, const QJsonObject& rep) - : Event(type, rep) - , _id(rep["event_id"].toString()) +RoomEvent::RoomEvent(Type type, const QJsonObject& json) + : Event(type, json) { -// if (_id.isEmpty()) -// { -// qCWarning(EVENTS) << "Can't find event_id in a room event"; -// qCWarning(EVENTS) << formatJson << rep; -// } -// if (!rep.contains("origin_server_ts")) -// { -// qCWarning(EVENTS) << "Can't find server timestamp in a room event"; -// qCWarning(EVENTS) << formatJson << rep; -// } -// if (_senderId.isEmpty()) -// { -// qCWarning(EVENTS) << "Can't find sender in a room event"; -// qCWarning(EVENTS) << formatJson << rep; -// } - auto unsignedData = rep["unsigned"].toObject(); - auto redaction = unsignedData.value("redacted_because"); + const auto unsignedData = json[UnsignedKeyL].toObject(); + const auto redaction = unsignedData[RedactedCauseKeyL]; if (redaction.isObject()) { - _redactedBecause = _impl::create<RedactionEvent>(redaction.toObject()); + _redactedBecause = makeEvent<RedactionEvent>(redaction.toObject()); return; } - _txnId = unsignedData.value("transactionId").toString(); + _txnId = unsignedData.value("transactionId"_ls).toString(); if (!_txnId.isEmpty()) qCDebug(EVENTS) << "Event transactionId:" << _txnId; } RoomEvent::~RoomEvent() = default; // Let the smart pointer do its job +QString RoomEvent::id() const +{ + return fullJson()[EventIdKeyL].toString(); +} + QDateTime RoomEvent::timestamp() const { - return QMatrixClient::fromJson<QDateTime>( - originalJsonObject().value("origin_server_ts")); + return QMatrixClient::fromJson<QDateTime>(fullJson()["origin_server_ts"_ls]); } QString RoomEvent::roomId() const { - return originalJsonObject().value("room_id").toString(); + return fullJson()["room_id"_ls].toString(); } QString RoomEvent::senderId() const { - return originalJsonObject().value("sender").toString(); + return fullJson()["sender"_ls].toString(); } QString RoomEvent::redactionReason() const @@ -151,37 +127,17 @@ QString RoomEvent::redactionReason() const return isRedacted() ? _redactedBecause->reason() : QString{}; } -void RoomEvent::addId(const QString& id) +void RoomEvent::addId(const QString& newId) { - Q_ASSERT(_id.isEmpty()); Q_ASSERT(!id.isEmpty()); - _id = id; + Q_ASSERT(id().isEmpty()); Q_ASSERT(!newId.isEmpty()); + editJson().insert(EventIdKey, newId); } -template <> -RoomEventPtr _impl::doMakeEvent(const QJsonObject& obj) -{ - // Check more specific event types first - if (auto e = doMakeEvent<StateEventBase>(obj)) - return ptrCast<RoomEvent>(move(e)); - - return makeIfMatches<RoomEvent, - RoomMessageEvent, RedactionEvent>(obj, obj["type"].toString()); -} +[[gnu::unused]] static auto stateEventTypeInitialised = + EventTypeRegistry::chainFactories<RoomEvent, StateEventBase>(); bool StateEventBase::repeatsState() const { - auto contentJson = originalJsonObject().value("content"); - auto prevContentJson = originalJsonObject().value("unsigned") - .toObject().value("prev_content"); - return contentJson == prevContentJson; -} - -template<> -StateEventPtr _impl::doMakeEvent<StateEventBase>(const QJsonObject& obj) -{ - return makeIfMatches<StateEventBase, - RoomNameEvent, RoomAliasesEvent, - RoomCanonicalAliasEvent, RoomMemberEvent, RoomTopicEvent, - RoomAvatarEvent, EncryptionEvent>(obj, obj["type"].toString()); - + const auto prevContentJson = unsignedJson().value(PrevContentKeyL); + return fullJson().value(ContentKeyL) == prevContentJson; } |