aboutsummaryrefslogtreecommitdiff
path: root/lib/events
diff options
context:
space:
mode:
authorAlexey Rusakov <Kitsune-Ral@users.sf.net>2022-09-05 07:49:16 +0200
committerGitHub <noreply@github.com>2022-09-05 07:49:16 +0200
commit1e263a32fcbc44985e474a626393494a81f15e37 (patch)
tree8811e0a995dcd593cb9f233e02ece9402e76eb1b /lib/events
parent8cb629f406f5b8b1ff7ce787dd3967d5684e07c3 (diff)
parentbd2736bc9f8b6023ecbc21d0d831856703b853db (diff)
downloadlibquotient-1e263a32fcbc44985e474a626393494a81f15e37.tar.gz
libquotient-1e263a32fcbc44985e474a626393494a81f15e37.zip
Merge pull request #565 from quotient-im/kitsune/streamline-event-types-2
Streamline event types, part 2
Diffstat (limited to 'lib/events')
-rw-r--r--lib/events/accountdataevents.h18
-rw-r--r--lib/events/callanswerevent.cpp41
-rw-r--r--lib/events/callanswerevent.h24
-rw-r--r--lib/events/callcandidatesevent.h32
-rw-r--r--lib/events/callevents.cpp82
-rw-r--r--lib/events/callevents.h99
-rw-r--r--lib/events/callhangupevent.h23
-rw-r--r--lib/events/callinviteevent.cpp44
-rw-r--r--lib/events/callinviteevent.h27
-rw-r--r--lib/events/directchatevent.h5
-rw-r--r--lib/events/encryptedevent.cpp30
-rw-r--r--lib/events/encryptedevent.h11
-rw-r--r--lib/events/encryptionevent.cpp1
-rw-r--r--lib/events/encryptionevent.h13
-rw-r--r--lib/events/event.cpp49
-rw-r--r--lib/events/event.h538
-rw-r--r--lib/events/eventloader.h40
-rw-r--r--lib/events/keyverificationevent.h58
-rw-r--r--lib/events/reactionevent.h17
-rw-r--r--lib/events/receiptevent.cpp16
-rw-r--r--lib/events/receiptevent.h16
-rw-r--r--lib/events/redactionevent.h6
-rw-r--r--lib/events/roomavatarevent.h22
-rw-r--r--lib/events/roomcanonicalaliasevent.h23
-rw-r--r--lib/events/roomcreateevent.h9
-rw-r--r--lib/events/roomevent.cpp31
-rw-r--r--lib/events/roomevent.h39
-rw-r--r--lib/events/roomkeyevent.cpp22
-rw-r--r--lib/events/roomkeyevent.h14
-rw-r--r--lib/events/roommemberevent.cpp3
-rw-r--r--lib/events/roommemberevent.h34
-rw-r--r--lib/events/roommessageevent.cpp6
-rw-r--r--lib/events/roommessageevent.h4
-rw-r--r--lib/events/roompowerlevelsevent.h12
-rw-r--r--lib/events/roomtombstoneevent.h9
-rw-r--r--lib/events/simplestateevents.h45
-rw-r--r--lib/events/single_key_value.h15
-rw-r--r--lib/events/stateevent.cpp24
-rw-r--r--lib/events/stateevent.h168
-rw-r--r--lib/events/stickerevent.h3
-rw-r--r--lib/events/typingevent.cpp11
-rw-r--r--lib/events/typingevent.h10
42 files changed, 856 insertions, 838 deletions
diff --git a/lib/events/accountdataevents.h b/lib/events/accountdataevents.h
index 24c3353c..324ce449 100644
--- a/lib/events/accountdataevents.h
+++ b/lib/events/accountdataevents.h
@@ -4,7 +4,6 @@
#pragma once
#include "event.h"
-#include "util.h"
namespace Quotient {
constexpr auto FavouriteTag [[maybe_unused]] = "m.favourite"_ls;
@@ -46,14 +45,21 @@ struct JsonObjectConverter<TagRecord> {
using TagsMap = QHash<QString, TagRecord>;
-DEFINE_SIMPLE_EVENT(TagEvent, Event, "m.tag", TagsMap, tags)
-DEFINE_SIMPLE_EVENT(ReadMarkerEventImpl, Event, "m.fully_read", QString, eventId)
+DEFINE_SIMPLE_EVENT(TagEvent, Event, "m.tag", TagsMap, tags, "tags")
+DEFINE_SIMPLE_EVENT(ReadMarkerEventImpl, Event, "m.fully_read", QString,
+ eventId, "event_id")
class ReadMarkerEvent : public ReadMarkerEventImpl {
public:
using ReadMarkerEventImpl::ReadMarkerEventImpl;
[[deprecated("Use ReadMarkerEvent::eventId() instead")]]
- QString event_id() const { return eventId(); }
+ auto event_id() const { return eventId(); }
+};
+DEFINE_SIMPLE_EVENT(IgnoredUsersEventImpl, Event, "m.ignored_user_list",
+ QSet<QString>, ignoredUsers, "ignored_users")
+class IgnoredUsersEvent : public IgnoredUsersEventImpl {
+public:
+ using IgnoredUsersEventImpl::IgnoredUsersEventImpl;
+ [[deprecated("Use IgnoredUsersEvent::ignoredUsers() instead")]]
+ auto ignored_users() const { return ignoredUsers(); }
};
-DEFINE_SIMPLE_EVENT(IgnoredUsersEvent, Event, "m.ignored_user_list", QSet<QString>,
- ignored_users)
} // namespace Quotient
diff --git a/lib/events/callanswerevent.cpp b/lib/events/callanswerevent.cpp
deleted file mode 100644
index f75f8ad3..00000000
--- a/lib/events/callanswerevent.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-// SPDX-FileCopyrightText: 2017 Marius Gripsgard <marius@ubports.com>
-// SPDX-FileCopyrightText: 2018 Josip Delic <delijati@googlemail.com>
-// SPDX-License-Identifier: LGPL-2.1-or-later
-
-#include "callanswerevent.h"
-
-/*
-m.call.answer
-{
- "age": 242352,
- "content": {
- "answer": {
- "sdp": "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]",
- "type": "answer"
- },
- "call_id": "12345",
- "version": 0
- },
- "event_id": "$WLGTSEFSEF:localhost",
- "origin_server_ts": 1431961217939,
- "room_id": "!Cuyf34gef24t:localhost",
- "sender": "@example:localhost",
- "type": "m.call.answer"
-}
-*/
-
-using namespace Quotient;
-
-CallAnswerEvent::CallAnswerEvent(const QJsonObject& obj)
- : CallEventBase(typeId(), obj)
-{
- qCDebug(EVENTS) << "Call Answer event";
-}
-
-CallAnswerEvent::CallAnswerEvent(const QString& callId, const QString& sdp)
- : CallEventBase(
- typeId(), matrixTypeId(), callId, 0,
- { { QStringLiteral("answer"),
- QJsonObject { { QStringLiteral("type"), QStringLiteral("answer") },
- { QStringLiteral("sdp"), sdp } } } })
-{}
diff --git a/lib/events/callanswerevent.h b/lib/events/callanswerevent.h
deleted file mode 100644
index 4d539b85..00000000
--- a/lib/events/callanswerevent.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// SPDX-FileCopyrightText: 2017 Marius Gripsgard <marius@ubports.com>
-// SPDX-FileCopyrightText: 2018 Josip Delic <delijati@googlemail.com>
-// SPDX-License-Identifier: LGPL-2.1-or-later
-
-#pragma once
-
-#include "roomevent.h"
-
-namespace Quotient {
-class QUOTIENT_API CallAnswerEvent : public CallEventBase {
-public:
- DEFINE_EVENT_TYPEID("m.call.answer", CallAnswerEvent)
-
- explicit CallAnswerEvent(const QJsonObject& obj);
-
- explicit CallAnswerEvent(const QString& callId, const QString& sdp);
-
- QString sdp() const
- {
- return contentPart<QJsonObject>("answer"_ls).value("sdp"_ls).toString();
- }
-};
-REGISTER_EVENT_TYPE(CallAnswerEvent)
-} // namespace Quotient
diff --git a/lib/events/callcandidatesevent.h b/lib/events/callcandidatesevent.h
deleted file mode 100644
index e949f722..00000000
--- a/lib/events/callcandidatesevent.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// SPDX-FileCopyrightText: 2017 Marius Gripsgard <marius@ubports.com>
-// SPDX-FileCopyrightText: 2018 Josip Delic <delijati@googlemail.com>
-// SPDX-FileCopyrightText: 2018 Kitsune Ral <Kitsune-Ral@users.sf.net>
-// SPDX-FileCopyrightText: 2020 Carl Schwan <carlschwan@kde.org>
-// SPDX-License-Identifier: LGPL-2.1-or-later
-
-#pragma once
-
-#include "roomevent.h"
-
-namespace Quotient {
-class CallCandidatesEvent : public CallEventBase {
-public:
- DEFINE_EVENT_TYPEID("m.call.candidates", CallCandidatesEvent)
-
- explicit CallCandidatesEvent(const QJsonObject& obj)
- : CallEventBase(typeId(), obj)
- {}
-
- explicit CallCandidatesEvent(const QString& callId,
- const QJsonArray& candidates)
- : CallEventBase(typeId(), matrixTypeId(), callId, 0,
- { { QStringLiteral("candidates"), candidates } })
- {}
-
- QUO_CONTENT_GETTER(QJsonArray, candidates)
- QUO_CONTENT_GETTER(QString, callId)
- QUO_CONTENT_GETTER(int, version)
-};
-
-REGISTER_EVENT_TYPE(CallCandidatesEvent)
-} // namespace Quotient
diff --git a/lib/events/callevents.cpp b/lib/events/callevents.cpp
new file mode 100644
index 00000000..3873614d
--- /dev/null
+++ b/lib/events/callevents.cpp
@@ -0,0 +1,82 @@
+// SPDX-FileCopyrightText: 2022 Kitsune Ral <Kitsune-Ral@users.sf.net>
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#include "callevents.h"
+
+#include "logging.h"
+
+using namespace Quotient;
+
+QJsonObject CallEvent::basicJson(const QString& matrixType,
+ const QString& callId, int version,
+ QJsonObject contentJson)
+{
+ contentJson.insert(QStringLiteral("call_id"), callId);
+ contentJson.insert(QStringLiteral("version"), version);
+ return RoomEvent::basicJson(matrixType, contentJson);
+}
+
+CallEvent::CallEvent(const QJsonObject& json)
+ : RoomEvent(json)
+{
+ if (callId().isEmpty())
+ qCWarning(EVENTS) << id() << "is a call event with an empty call id";
+}
+
+/*
+m.call.invite
+{
+ "age": 242352,
+ "content": {
+ "call_id": "12345",
+ "lifetime": 60000,
+ "offer": {
+ "sdp": "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]",
+ "type": "offer"
+ },
+ "version": 0
+ },
+ "event_id": "$WLGTSEFSEF:localhost",
+ "origin_server_ts": 1431961217939,
+ "room_id": "!Cuyf34gef24t:localhost",
+ "sender": "@example:localhost",
+ "type": "m.call.invite"
+}
+*/
+
+CallInviteEvent::CallInviteEvent(const QString& callId, int lifetime,
+ const QString& sdp)
+ : EventTemplate(
+ callId,
+ { { QStringLiteral("lifetime"), lifetime },
+ { QStringLiteral("offer"),
+ QJsonObject{ { QStringLiteral("type"), QStringLiteral("offer") },
+ { QStringLiteral("sdp"), sdp } } } })
+{}
+
+/*
+m.call.answer
+{
+ "age": 242352,
+ "content": {
+ "answer": {
+ "sdp": "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]",
+ "type": "answer"
+ },
+ "call_id": "12345",
+ "version": 0
+ },
+ "event_id": "$WLGTSEFSEF:localhost",
+ "origin_server_ts": 1431961217939,
+ "room_id": "!Cuyf34gef24t:localhost",
+ "sender": "@example:localhost",
+ "type": "m.call.answer"
+}
+*/
+
+CallAnswerEvent::CallAnswerEvent(const QString& callId, const QString& sdp)
+ : EventTemplate(callId, { { QStringLiteral("answer"),
+ QJsonObject { { QStringLiteral("type"),
+ QStringLiteral("answer") },
+ { QStringLiteral("sdp"), sdp } } } })
+{}
diff --git a/lib/events/callevents.h b/lib/events/callevents.h
new file mode 100644
index 00000000..752e331d
--- /dev/null
+++ b/lib/events/callevents.h
@@ -0,0 +1,99 @@
+// SPDX-FileCopyrightText: 2022 Kitsune Ral <Kitsune-Ral@users.sf.net>
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#pragma once
+
+#include "roomevent.h"
+
+namespace Quotient {
+
+class QUOTIENT_API CallEvent : public RoomEvent {
+public:
+ QUO_BASE_EVENT(CallEvent, "m.call.*"_ls, RoomEvent::BaseMetaType)
+ static bool matches(const QJsonObject&, const QString& mType)
+ {
+ return mType.startsWith("m.call.");
+ }
+
+ QUO_CONTENT_GETTER(QString, callId)
+ QUO_CONTENT_GETTER(int, version)
+
+protected:
+ explicit CallEvent(const QJsonObject& json);
+
+ static QJsonObject basicJson(const QString& matrixType,
+ const QString& callId, int version,
+ QJsonObject contentJson = {});
+};
+using CallEventBase
+ [[deprecated("CallEventBase is CallEvent now")]] = CallEvent;
+
+template <typename EventT>
+class EventTemplate<EventT, CallEvent> : public CallEvent {
+public:
+ using CallEvent::CallEvent;
+ explicit EventTemplate(const QString& callId,
+ const QJsonObject& contentJson = {})
+ : EventTemplate(basicJson(EventT::TypeId, callId, 0, contentJson))
+ {}
+};
+
+template <typename EventT, typename ContentT>
+class EventTemplate<EventT, CallEvent, ContentT>
+ : public EventTemplate<EventT, CallEvent> {
+public:
+ using EventTemplate<EventT, CallEvent>::EventTemplate;
+ template <typename... ContentParamTs>
+ explicit EventTemplate(const QString& callId,
+ ContentParamTs&&... contentParams)
+ : EventTemplate<EventT, CallEvent>(
+ callId,
+ toJson(ContentT{ std::forward<ContentParamTs>(contentParams)... }))
+ {}
+};
+
+class QUOTIENT_API CallInviteEvent
+ : public EventTemplate<CallInviteEvent, CallEvent> {
+public:
+ QUO_EVENT(CallInviteEvent, "m.call.invite")
+
+ using EventTemplate::EventTemplate;
+
+ explicit CallInviteEvent(const QString& callId, int lifetime,
+ const QString& sdp);
+
+ QUO_CONTENT_GETTER(int, lifetime)
+ QString sdp() const
+ {
+ return contentPart<QJsonObject>("offer"_ls).value("sdp"_ls).toString();
+ }
+};
+
+DEFINE_SIMPLE_EVENT(CallCandidatesEvent, CallEvent, "m.call.candidates",
+ QJsonArray, candidates, "candidates")
+
+class QUOTIENT_API CallAnswerEvent
+ : public EventTemplate<CallAnswerEvent, CallEvent> {
+public:
+ QUO_EVENT(CallAnswerEvent, "m.call.answer")
+
+ using EventTemplate::EventTemplate;
+
+ explicit CallAnswerEvent(const QString& callId, const QString& sdp);
+
+ QString sdp() const
+ {
+ return contentPart<QJsonObject>("answer"_ls).value("sdp"_ls).toString();
+ }
+};
+
+class QUOTIENT_API CallHangupEvent
+ : public EventTemplate<CallHangupEvent, CallEvent> {
+public:
+ QUO_EVENT(CallHangupEvent, "m.call.hangup")
+ using EventTemplate::EventTemplate;
+};
+
+} // namespace Quotient
+Q_DECLARE_METATYPE(Quotient::CallEvent*)
+Q_DECLARE_METATYPE(const Quotient::CallEvent*)
diff --git a/lib/events/callhangupevent.h b/lib/events/callhangupevent.h
deleted file mode 100644
index b0017c59..00000000
--- a/lib/events/callhangupevent.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// SPDX-FileCopyrightText: 2017 Marius Gripsgard <marius@ubports.com>
-// SPDX-FileCopyrightText: 2018 Josip Delic <delijati@googlemail.com>
-// SPDX-License-Identifier: LGPL-2.1-or-later
-
-#pragma once
-
-#include "roomevent.h"
-
-namespace Quotient {
-class QUOTIENT_API CallHangupEvent : public CallEventBase {
-public:
- DEFINE_EVENT_TYPEID("m.call.hangup", CallHangupEvent)
-
- explicit CallHangupEvent(const QJsonObject& obj)
- : CallEventBase(typeId(), obj)
- {}
- explicit CallHangupEvent(const QString& callId)
- : CallEventBase(typeId(), matrixTypeId(), callId, 0)
- {}
-};
-
-REGISTER_EVENT_TYPE(CallHangupEvent)
-} // namespace Quotient
diff --git a/lib/events/callinviteevent.cpp b/lib/events/callinviteevent.cpp
deleted file mode 100644
index 2f26a1cb..00000000
--- a/lib/events/callinviteevent.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-// SPDX-FileCopyrightText: 2017 Marius Gripsgard <marius@ubports.com>
-// SPDX-FileCopyrightText: 2018 Josip Delic <delijati@googlemail.com>
-// SPDX-License-Identifier: LGPL-2.1-or-later
-
-#include "callinviteevent.h"
-
-/*
-m.call.invite
-{
- "age": 242352,
- "content": {
- "call_id": "12345",
- "lifetime": 60000,
- "offer": {
- "sdp": "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]",
- "type": "offer"
- },
- "version": 0
- },
- "event_id": "$WLGTSEFSEF:localhost",
- "origin_server_ts": 1431961217939,
- "room_id": "!Cuyf34gef24t:localhost",
- "sender": "@example:localhost",
- "type": "m.call.invite"
-}
-*/
-
-using namespace Quotient;
-
-CallInviteEvent::CallInviteEvent(const QJsonObject& obj)
- : CallEventBase(typeId(), obj)
-{
- qCDebug(EVENTS) << "Call Invite event";
-}
-
-CallInviteEvent::CallInviteEvent(const QString& callId, int lifetime,
- const QString& sdp)
- : CallEventBase(
- typeId(), matrixTypeId(), callId, 0,
- { { QStringLiteral("lifetime"), lifetime },
- { QStringLiteral("offer"),
- QJsonObject { { QStringLiteral("type"), QStringLiteral("offer") },
- { QStringLiteral("sdp"), sdp } } } })
-{}
diff --git a/lib/events/callinviteevent.h b/lib/events/callinviteevent.h
deleted file mode 100644
index 5b4ca0df..00000000
--- a/lib/events/callinviteevent.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// SPDX-FileCopyrightText: 2017 Marius Gripsgard <marius@ubports.com>
-// SPDX-FileCopyrightText: 2018 Josip Delic <delijati@googlemail.com>
-// SPDX-License-Identifier: LGPL-2.1-or-later
-
-#pragma once
-
-#include "roomevent.h"
-
-namespace Quotient {
-class QUOTIENT_API CallInviteEvent : public CallEventBase {
-public:
- DEFINE_EVENT_TYPEID("m.call.invite", CallInviteEvent)
-
- explicit CallInviteEvent(const QJsonObject& obj);
-
- explicit CallInviteEvent(const QString& callId, int lifetime,
- const QString& sdp);
-
- QUO_CONTENT_GETTER(int, lifetime)
- QString sdp() const
- {
- return contentPart<QJsonObject>("offer"_ls).value("sdp"_ls).toString();
- }
-};
-
-REGISTER_EVENT_TYPE(CallInviteEvent)
-} // namespace Quotient
diff --git a/lib/events/directchatevent.h b/lib/events/directchatevent.h
index 2018d3d6..0756d816 100644
--- a/lib/events/directchatevent.h
+++ b/lib/events/directchatevent.h
@@ -8,11 +8,10 @@
namespace Quotient {
class QUOTIENT_API DirectChatEvent : public Event {
public:
- DEFINE_EVENT_TYPEID("m.direct", DirectChatEvent)
+ QUO_EVENT(DirectChatEvent, "m.direct")
- explicit DirectChatEvent(const QJsonObject& obj) : Event(typeId(), obj) {}
+ using Event::Event;
QMultiHash<QString, QString> usersToDirectChats() const;
};
-REGISTER_EVENT_TYPE(DirectChatEvent)
} // namespace Quotient
diff --git a/lib/events/encryptedevent.cpp b/lib/events/encryptedevent.cpp
index ec00ad4c..94b44901 100644
--- a/lib/events/encryptedevent.cpp
+++ b/lib/events/encryptedevent.cpp
@@ -2,33 +2,31 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
#include "encryptedevent.h"
-#include "roommessageevent.h"
-#include "events/eventloader.h"
+#include "logging.h"
using namespace Quotient;
-EncryptedEvent::EncryptedEvent(const QJsonObject& ciphertext,
+EncryptedEvent::EncryptedEvent(const QJsonObject& ciphertexts,
const QString& senderKey)
- : RoomEvent(typeId(), matrixTypeId(),
- { { AlgorithmKeyL, OlmV1Curve25519AesSha2AlgoKey },
- { CiphertextKeyL, ciphertext },
+ : RoomEvent({ { AlgorithmKeyL, OlmV1Curve25519AesSha2AlgoKey },
+ { CiphertextKeyL, ciphertexts },
{ SenderKeyKeyL, senderKey } })
{}
-EncryptedEvent::EncryptedEvent(QByteArray ciphertext, const QString& senderKey,
+EncryptedEvent::EncryptedEvent(const QByteArray& ciphertext,
+ const QString& senderKey,
const QString& deviceId, const QString& sessionId)
- : RoomEvent(typeId(), matrixTypeId(),
- {
- { AlgorithmKeyL, MegolmV1AesSha2AlgoKey },
- { CiphertextKeyL, QString(ciphertext) },
- { DeviceIdKeyL, deviceId },
- { SenderKeyKeyL, senderKey },
- { SessionIdKeyL, sessionId },
- })
+ : RoomEvent({
+ { AlgorithmKeyL, MegolmV1AesSha2AlgoKey },
+ { CiphertextKeyL, QString(ciphertext) },
+ { DeviceIdKeyL, deviceId },
+ { SenderKeyKeyL, senderKey },
+ { SessionIdKeyL, sessionId },
+ })
{}
EncryptedEvent::EncryptedEvent(const QJsonObject& obj)
- : RoomEvent(typeId(), obj)
+ : RoomEvent(obj)
{
qCDebug(E2EE) << "Encrypted event from" << senderId();
}
diff --git a/lib/events/encryptedevent.h b/lib/events/encryptedevent.h
index ddd5e415..02d4c7aa 100644
--- a/lib/events/encryptedevent.h
+++ b/lib/events/encryptedevent.h
@@ -27,16 +27,17 @@ namespace Quotient {
*/
class QUOTIENT_API EncryptedEvent : public RoomEvent {
public:
- DEFINE_EVENT_TYPEID("m.room.encrypted", EncryptedEvent)
+ QUO_EVENT(EncryptedEvent, "m.room.encrypted")
/* In case with Olm, the encrypted content of the event is
* a map from the recipient Curve25519 identity key to ciphertext
* information */
- explicit EncryptedEvent(const QJsonObject& ciphertext,
+ explicit EncryptedEvent(const QJsonObject& ciphertexts,
const QString& senderKey);
/* In case with Megolm, device_id and session_id are required */
- explicit EncryptedEvent(QByteArray ciphertext, const QString& senderKey,
- const QString& deviceId, const QString& sessionId);
+ explicit EncryptedEvent(const QByteArray& ciphertext,
+ const QString& senderKey, const QString& deviceId,
+ const QString& sessionId);
explicit EncryptedEvent(const QJsonObject& obj);
QString algorithm() const;
@@ -59,6 +60,4 @@ public:
void setRelation(const QJsonObject& relation);
};
-REGISTER_EVENT_TYPE(EncryptedEvent)
-
} // namespace Quotient
diff --git a/lib/events/encryptionevent.cpp b/lib/events/encryptionevent.cpp
index 8872447b..b1b04984 100644
--- a/lib/events/encryptionevent.cpp
+++ b/lib/events/encryptionevent.cpp
@@ -3,6 +3,7 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
#include "encryptionevent.h"
+#include "logging.h"
#include "e2ee/e2ee.h"
diff --git a/lib/events/encryptionevent.h b/lib/events/encryptionevent.h
index 91452c3f..4bf7459c 100644
--- a/lib/events/encryptionevent.h
+++ b/lib/events/encryptionevent.h
@@ -26,20 +26,16 @@ public:
int rotationPeriodMsgs = 100;
};
-class QUOTIENT_API EncryptionEvent : public StateEvent<EncryptionEventContent> {
+class QUOTIENT_API EncryptionEvent
+ : public KeylessStateEventBase<EncryptionEvent, EncryptionEventContent> {
public:
- DEFINE_EVENT_TYPEID("m.room.encryption", EncryptionEvent)
+ QUO_EVENT(EncryptionEvent, "m.room.encryption")
using EncryptionType
[[deprecated("Use Quotient::EncryptionType instead")]] =
Quotient::EncryptionType;
- explicit EncryptionEvent(const QJsonObject& obj)
- : StateEvent(typeId(), obj)
- {}
- explicit EncryptionEvent(EncryptionEventContent&& content)
- : StateEvent(typeId(), matrixTypeId(), QString(), std::move(content))
- {}
+ using KeylessStateEventBase::KeylessStateEventBase;
Quotient::EncryptionType encryption() const { return content().encryption; }
QString algorithm() const { return content().algorithm; }
@@ -48,5 +44,4 @@ public:
bool useEncryption() const { return !algorithm().isEmpty(); }
};
-REGISTER_EVENT_TYPE(EncryptionEvent)
} // namespace Quotient
diff --git a/lib/events/event.cpp b/lib/events/event.cpp
index 1f1eebaa..da7de919 100644
--- a/lib/events/event.cpp
+++ b/lib/events/event.cpp
@@ -3,7 +3,9 @@
#include "event.h"
+#include "callevents.h"
#include "logging.h"
+#include "stateevent.h"
#include <QtCore/QJsonDocument>
@@ -11,15 +13,42 @@ using namespace Quotient;
QString EventTypeRegistry::getMatrixType(event_type_t typeId) { return typeId; }
-void _impl::EventFactoryBase::logAddingMethod(event_type_t TypeId,
- size_t newSize)
+void AbstractEventMetaType::addDerived(AbstractEventMetaType* newType)
{
- qDebug(EVENTS) << "Adding factory method for" << TypeId << "events;"
- << newSize << "methods will be in the" << name
- << "chain";
+ if (const auto existing =
+ std::find_if(derivedTypes.cbegin(), derivedTypes.cend(),
+ [&newType](const AbstractEventMetaType* t) {
+ return t->matrixId == newType->matrixId;
+ });
+ existing != derivedTypes.cend())
+ {
+ if (*existing == newType)
+ return;
+ // Two different metatype objects claim the same Matrix type id; this
+ // is not normal, so give as much information as possible to diagnose
+ if ((*existing)->className == newType->className) {
+ qCritical(EVENTS)
+ << newType->className << "claims" << newType->matrixId
+ << "repeatedly; check that it's exported across translation "
+ "units or shared objects";
+ Q_ASSERT(false); // That situation is plain wrong
+ return; // So maybe std::terminate() even?
+ }
+ qWarning(EVENTS).nospace()
+ << newType->matrixId << " is already mapped to "
+ << (*existing)->className << " before " << newType->className
+ << "; unless the two have different isValid() conditions, the "
+ "latter class will never be used";
+ }
+ derivedTypes.emplace_back(newType);
+ qDebug(EVENTS).nospace()
+ << newType->matrixId << " -> " << newType->className << "; "
+ << derivedTypes.size() << " derived type(s) registered for "
+ << className;
}
-Event::Event(Type type, const QJsonObject& json) : _type(type), _json(json)
+Event::Event(const QJsonObject& json)
+ : _json(json)
{
if (!json.contains(ContentKeyL)
&& !json.value(UnsignedKeyL).toObject().contains(RedactedCauseKeyL)) {
@@ -28,10 +57,6 @@ Event::Event(Type type, const QJsonObject& json) : _type(type), _json(json)
}
}
-Event::Event(Type type, event_mtype_t matrixType, const QJsonObject& contentJson)
- : Event(type, basicJson(matrixType, contentJson))
-{}
-
Event::~Event() = default;
QString Event::matrixType() const { return fullJson()[TypeKeyL].toString(); }
@@ -48,6 +73,10 @@ const QJsonObject Event::unsignedJson() const
return fullJson()[UnsignedKeyL].toObject();
}
+bool Event::isStateEvent() const { return is<StateEvent>(); }
+
+bool Event::isCallEvent() const { return is<CallEvent>(); }
+
void Event::dumpTo(QDebug dbg) const
{
dbg << QJsonDocument(contentJson()).toJson(QJsonDocument::Compact);
diff --git a/lib/events/event.h b/lib/events/event.h
index b7454337..0abef1f0 100644
--- a/lib/events/event.h
+++ b/lib/events/event.h
@@ -4,11 +4,11 @@
#pragma once
#include "converters.h"
-#include "logging.h"
#include "function_traits.h"
+#include "single_key_value.h"
namespace Quotient {
-// === event_ptr_tt<> and type casting facilities ===
+// === event_ptr_tt<> and basic type casting facilities ===
template <typename EventT>
using event_ptr_tt = std::unique_ptr<EventT>;
@@ -48,141 +48,233 @@ const QString RoomIdKey { RoomIdKeyL };
const QString UnsignedKey { UnsignedKeyL };
const QString StateKeyKey { StateKeyKeyL };
-// === Event types ===
-
using event_type_t = QLatin1String;
-using event_mtype_t = const char*;
-
-class QUOTIENT_API EventTypeRegistry {
-public:
- ~EventTypeRegistry() = default;
- [[deprecated("event_type_t is a string now, use it directly instead")]]
+// TODO: Remove in 0.8
+struct QUOTIENT_API EventTypeRegistry {
+ [[deprecated("event_type_t is a string since libQuotient 0.7, use it directly instead")]]
static QString getMatrixType(event_type_t typeId);
-private:
- EventTypeRegistry() = default;
+ EventTypeRegistry() = delete;
+ ~EventTypeRegistry() = default;
Q_DISABLE_COPY_MOVE(EventTypeRegistry)
};
-template <typename EventT>
-constexpr event_type_t typeId()
-{
- return std::decay_t<EventT>::TypeId;
-}
+// === EventMetaType ===
-constexpr event_type_t UnknownEventTypeId = "?"_ls;
-[[deprecated("Use UnknownEventTypeId")]]
-constexpr event_type_t unknownEventTypeId() { return UnknownEventTypeId; }
+class Event;
-// === Event creation facilities ===
+// TODO: move over to std::derived_from<Event> once it's available everywhere
+template <typename EventT, typename BaseEventT = Event>
+concept EventClass = std::is_base_of_v<BaseEventT, EventT>;
-//! Create an event of arbitrary type from its arguments
-template <typename EventT, typename... ArgTs>
-inline event_ptr_tt<EventT> makeEvent(ArgTs&&... args)
-{
- return std::make_unique<EventT>(std::forward<ArgTs>(args)...);
-}
+template <EventClass EventT>
+bool is(const Event& e);
-namespace _impl {
- class QUOTIENT_API EventFactoryBase {
- public:
- EventFactoryBase(const EventFactoryBase&) = delete;
-
- protected: // This class is only to inherit from
- explicit EventFactoryBase(const char* name)
- : name(name)
- {}
- void logAddingMethod(event_type_t TypeId, size_t newSize);
-
- private:
- const char* const name;
- };
-} // namespace _impl
-
-//! \brief A family of event factories to create events from CS API responses
+//! \brief The base class for event metatypes
//!
-//! Each of these factories, as instantiated by event base types (Event,
-//! RoomEvent etc.) is capable of producing an event object derived from
-//! \p BaseEventT, using the JSON payload and the event type passed to its
-//! make() method. Don't use these directly to make events; use loadEvent()
-//! overloads as the frontend for these. Never instantiate new factories
-//! outside of base event classes.
-//! \sa loadEvent, setupFactory, Event::factory, RoomEvent::factory,
-//! StateEventBase::factory
-template <typename BaseEventT>
-class EventFactory : public _impl::EventFactoryBase {
-private:
- using method_t = event_ptr_tt<BaseEventT> (*)(const QJsonObject&,
- const QString&);
- std::vector<method_t> methods {};
-
- template <class EventT>
- static event_ptr_tt<BaseEventT> makeIfMatches(const QJsonObject& json,
- const QString& matrixType)
+//! You should not normally have to use this directly, unless you need to devise
+//! a whole new kind of event metatypes.
+class QUOTIENT_API AbstractEventMetaType {
+public:
+ // The public fields here are const and are not to be changeable anyway.
+ // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
+ const char* const className;
+ const event_type_t matrixId;
+ const AbstractEventMetaType* const baseType = nullptr;
+ // NOLINTEND(misc-non-private-member-variables-in-classes)
+
+ explicit AbstractEventMetaType(const char* className)
+ : className(className)
+ {}
+ explicit AbstractEventMetaType(const char* className, event_type_t matrixId,
+ AbstractEventMetaType& nearestBase)
+ : className(className), matrixId(matrixId), baseType(&nearestBase)
{
- // If your matrix event type is not all ASCII, it's your problem
- // (see https://github.com/matrix-org/matrix-doc/pull/2758)
- return EventT::TypeId == matrixType ? makeEvent<EventT>(json) : nullptr;
+ nearestBase.addDerived(this);
}
+ void addDerived(AbstractEventMetaType *newType);
+
+ virtual ~AbstractEventMetaType() = default;
+
+protected:
+ // Allow template specialisations to call into one another
+ template <class EventT>
+ friend class EventMetaType;
+
+ // The returned value indicates whether a generic object has to be created
+ // on the top level when `event` is empty, instead of returning nullptr
+ virtual bool doLoadFrom(const QJsonObject& fullJson, const QString& type,
+ Event*& event) const = 0;
+
+private:
+ std::vector<const AbstractEventMetaType*> derivedTypes{};
+ Q_DISABLE_COPY_MOVE(AbstractEventMetaType)
+};
+
+// Any event metatype is unique (note Q_DISABLE_COPY_MOVE above) so can be
+// identified by its address
+inline bool operator==(const AbstractEventMetaType& lhs,
+ const AbstractEventMetaType& rhs)
+{
+ return &lhs == &rhs;
+}
+
+//! \brief A family of event meta-types to load and match events
+//!
+//! TL;DR for the loadFrom() story:
+//! - for base event types, use QUO_BASE_EVENT and, if you have additional
+//! validation (e.g., JSON has to contain a certain key - see StateEvent
+//! for a real example), define it in the static EventT::isValid() member
+//! function accepting QJsonObject and returning bool.
+//! - for leaf (specific) event types - simply use QUO_EVENT and it will do
+//! everything necessary, including the TypeId definition.
+//! \sa QUO_EVENT, QUO_BASE_EVENT
+template <class EventT>
+class QUOTIENT_API EventMetaType : public AbstractEventMetaType {
+ // Above: can't constrain EventT to be EventClass because it's incomplete
+ // at the point of EventMetaType<EventT> instantiation.
public:
- explicit EventFactory(const char* fName)
- : EventFactoryBase { fName }
- {}
+ using AbstractEventMetaType::AbstractEventMetaType;
- //! \brief Add a method to create events of a given type
+ //! \brief Try to load an event from JSON, with dynamic type resolution
//!
- //! Adds a standard factory method (makeIfMatches) for \p EventT so that
- //! event objects of this type can be created dynamically by loadEvent.
- //! The caller is responsible for ensuring this method is called only
- //! once per type.
- //! \sa loadEvent, Quotient::loadEvent
- template <class EventT>
- const auto& addMethod()
+ //! The generic logic defined in this class template and invoked applies to
+ //! all event types defined in the library and boils down to the following:
+ //! 1.
+ //! a. If EventT has TypeId defined (which normally is a case of
+ //! all leaf - specific - event types, via QUO_EVENT macro) and
+ //! \p type doesn't exactly match it, nullptr is immediately returned.
+ //! b. In absence of TypeId, an event type is assumed to be a base;
+ //! its derivedTypes are examined, and this algorithm is applied
+ //! recursively on each.
+ //! 2. Optional validation: if EventT (or, due to the way inheritance works,
+ //! any of its base event types) has a static isValid() predicate and
+ //! the event JSON does not satisfy it, nullptr is immediately returned
+ //! to the upper level or to the loadFrom() caller. This is how existence
+ //! of `state_key` is checked in any type derived from StateEvent.
+ //! 3. If step 1b above returned non-nullptr, immediately return it.
+ //! 4.
+ //! a. If EventT::isValid() or EventT::TypeId (either, or both) exist and
+ //! are satisfied (see steps 1a and 2 above), an object of this type
+ //! is created from the passed JSON and returned. In case of a base
+ //! event type, this will be a generic (aka "unknown") event.
+ //! b. If neither exists, a generic event is only created and returned
+ //! when on the top level (i.e., outside of recursion into
+ //! derivedTypes); lower levels return nullptr instead and the type
+ //! lookup continues. The latter is a case of a derived base event
+ //! metatype (e.g. RoomEvent) called from its base event metatype
+ //! (i.e., Event). If no matching type derived from RoomEvent is found,
+ //! the nested lookup returns nullptr rather than a generic RoomEvent,
+ //! so that other types derived from Event could be examined.
+ event_ptr_tt<EventT> loadFrom(const QJsonObject& fullJson,
+ const QString& type) const
{
- const auto m = &makeIfMatches<EventT>;
- const auto it = std::find(methods.cbegin(), methods.cend(), m);
- if (it != methods.cend())
- return *it;
- logAddingMethod(EventT::TypeId, methods.size() + 1);
- return methods.emplace_back(m);
+ Event* event = nullptr;
+ const bool goodEnough = doLoadFrom(fullJson, type, event);
+ if (!event && goodEnough)
+ return event_ptr_tt<EventT>{ new EventT(fullJson) };
+ return event_ptr_tt<EventT>{ static_cast<EventT*>(event) };
}
- auto loadEvent(const QJsonObject& json, const QString& matrixType)
+private:
+ bool doLoadFrom(const QJsonObject& fullJson, const QString& type,
+ Event*& event) const override
{
- for (const auto& f : methods)
- if (auto e = f(json, matrixType))
- return e;
- return makeEvent<BaseEventT>(UnknownEventTypeId, json);
+ if constexpr (requires { EventT::TypeId; }) {
+ if (EventT::TypeId != type)
+ return false;
+ } else {
+ for (const auto& p : derivedTypes) {
+ p->doLoadFrom(fullJson, type, event);
+ if (event) {
+ Q_ASSERT(is<EventT>(*event));
+ return false;
+ }
+ }
+ }
+ if constexpr (requires { EventT::isValid; }) {
+ if (!EventT::isValid(fullJson))
+ return false;
+ } else if constexpr (!requires { EventT::TypeId; })
+ return true; // Create a generic event object if on the top level
+ event = new EventT(fullJson);
+ return false;
}
};
-//! \brief Point of customisation to dynamically load events
+// === Event creation facilities ===
+
+//! \brief Create an event of arbitrary type from its arguments
//!
-//! The default specialisation of this calls BaseEventT::factory.loadEvent()
-//! and if that fails (i.e. returns nullptr) creates an unknown event of
-//! BaseEventT. Other specialisations may reuse other factories, add validations
-//! common to BaseEventT events, and so on.
-template <class BaseEventT>
-event_ptr_tt<BaseEventT> doLoadEvent(const QJsonObject& json,
- const QString& matrixType)
+//! This should not be used to load events from JSON - use loadEvent() for that.
+//! \sa loadEvent
+template <EventClass EventT, typename... ArgTs>
+inline event_ptr_tt<EventT> makeEvent(ArgTs&&... args)
{
- return BaseEventT::factory.loadEvent(json, matrixType);
+ return std::make_unique<EventT>(std::forward<ArgTs>(args)...);
}
+template <EventClass EventT>
+constexpr const auto& mostSpecificMetaType()
+{
+ if constexpr (requires { EventT::MetaType; })
+ return EventT::MetaType;
+ else
+ return EventT::BaseMetaType;
+}
+
+//! \brief Create an event with proper type from a JSON object
+//!
+//! Use this factory template to detect the type from the JSON object
+//! contents (the detected event type should derive from the template
+//! parameter type) and create an event object of that type.
+template <EventClass EventT>
+inline event_ptr_tt<EventT> loadEvent(const QJsonObject& fullJson)
+{
+ return mostSpecificMetaType<EventT>().loadFrom(
+ fullJson, fullJson[TypeKeyL].toString());
+}
+
+//! \brief Create an event from a type string and content JSON
+//!
+//! Use this template to resolve the C++ type from the Matrix type string in
+//! \p matrixType and create an event of that type by passing all parameters
+//! to BaseEventT::basicJson().
+template <EventClass EventT>
+inline event_ptr_tt<EventT> loadEvent(const QString& matrixType,
+ const auto&... otherBasicJsonParams)
+{
+ return mostSpecificMetaType<EventT>().loadFrom(
+ EventT::basicJson(matrixType, otherBasicJsonParams...), matrixType);
+}
+
+template <EventClass EventT>
+struct JsonConverter<event_ptr_tt<EventT>>
+ : JsonObjectUnpacker<event_ptr_tt<EventT>> {
+ // No dump() to avoid any ambiguity on whether a given export to JSON uses
+ // fullJson() or only contentJson()
+ using JsonObjectUnpacker<event_ptr_tt<EventT>>::load;
+ static auto load(const QJsonObject& jo)
+ {
+ return loadEvent<EventT>(jo);
+ }
+};
+
// === Event ===
class QUOTIENT_API Event {
public:
using Type = event_type_t;
- static inline EventFactory<Event> factory { "Event" };
+ static inline EventMetaType<Event> BaseMetaType { "Event" };
+ virtual const AbstractEventMetaType& metaType() const
+ {
+ return BaseMetaType;
+ }
- explicit Event(Type type, const QJsonObject& json);
- explicit Event(Type type, event_mtype_t matrixType,
- const QJsonObject& contentJson = {});
Q_DISABLE_COPY(Event)
- Event(Event&&) = default;
+ Event(Event&&) noexcept = default;
Event& operator=(Event&&) = delete;
virtual ~Event();
@@ -193,8 +285,26 @@ public:
return { { TypeKey, matrixType }, { ContentKey, content } };
}
- Type type() const { return _type; }
+ //! \brief Event Matrix type, as identified by its metatype object
+ //!
+ //! For generic/unknown events it will contain a descriptive/generic string
+ //! defined by the respective base event type (that can be empty).
+ //! \sa matrixType
+ Type type() const { return metaType().matrixId; }
+
+ //! \brief Exact Matrix type stored in JSON
+ //!
+ //! Coincides with the result of type() (but is slower) for events defined
+ //! in C++ (not necessarily in the library); for generic/unknown events
+ //! the returned value will be different.
QString matrixType() const;
+
+ template <EventClass EventT>
+ bool is() const
+ {
+ return Quotient::is<EventT>(*this);
+ }
+
[[deprecated("Use fullJson() and stringify it with QJsonDocument::toJson() "
"or by other means")]]
QByteArray originalJson() const;
@@ -212,6 +322,11 @@ public:
const QJsonObject contentJson() const;
+ //! \brief Get a part of the content object, assuming a given type
+ //!
+ //! This retrieves the value under `content.<key>` from the event JSON and
+ //! then converts it to \p T using fromJson().
+ //! \sa contentJson, fromJson
template <typename T, typename KeyT>
const T contentPart(KeyT&& key) const
{
@@ -227,6 +342,11 @@ public:
const QJsonObject unsignedJson() const;
+ //! \brief Get a part of the unsigned object, assuming a given type
+ //!
+ //! This retrieves the value under `unsigned.<key>` from the event JSON and
+ //! then converts it to \p T using fromJson().
+ //! \sa unsignedJson, fromJson
template <typename T, typename KeyT>
const T unsignedPart(KeyT&& key) const
{
@@ -236,28 +356,138 @@ public:
friend QUOTIENT_API QDebug operator<<(QDebug dbg, const Event& e)
{
QDebugStateSaver _dss { dbg };
- dbg.noquote().nospace() << e.matrixType() << '(' << e.type() << "): ";
+ dbg.noquote().nospace()
+ << e.matrixType() << '(' << e.metaType().className << "): ";
e.dumpTo(dbg);
return dbg;
}
- virtual bool isStateEvent() const { return false; }
- virtual bool isCallEvent() const { return false; }
+ // State events are quite special in Matrix; so isStateEvent() is here,
+ // as an exception. For other base events, Event::is<>() and
+ // Quotient::is<>() should be used; don't add is* methods here
+ bool isStateEvent() const;
+ [[deprecated("Use is<CallEvent>() instead")]] bool isCallEvent() const;
protected:
+ friend class EventMetaType<Event>; // To access the below constructor
+
+ explicit Event(const QJsonObject& json);
+
QJsonObject& editJson() { return _json; }
virtual void dumpTo(QDebug dbg) const;
private:
- Type _type;
QJsonObject _json;
};
using EventPtr = event_ptr_tt<Event>;
-template <typename EventT>
+template <EventClass EventT>
using EventsArray = std::vector<event_ptr_tt<EventT>>;
using Events = EventsArray<Event>;
+// === Facilities for event class definitions ===
+
+//! \brief A template base class to derive your event type from
+//!
+//! This simple class template generates commonly used event constructor
+//! signatures and the content() method with the appropriate return type.
+//! The generic version here is only used with non-trivial \p ContentT (if you
+//! don't need to create an event from its content structure, just go and derive
+//! straight from the respective \p EventBaseT instead of using EventTemplate);
+//! specialisations may override that and provide useful semantics even without
+//! \p ContentT (see EventTemplate<CallEvent>, e.g.).
+//!
+//! The template uses CRTP to pick the event type id from the actual class;
+//! it will fail to compile if \p EventT doesn't provide TypeId. It also uses
+//! the base event type's basicJson(); if you need extra keys to be inserted
+//! you may want to bypass this template as writing the code to that effect in
+//! your class will likely be clearer and more concise.
+//! \sa https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
+//! \sa DEFINE_SIMPLE_EVENT
+template <typename EventT, EventClass BaseEventT, typename ContentT = void>
+class EventTemplate : public BaseEventT {
+ // Above: can't constrain EventT to be EventClass because it's incomplete
+ // by CRTP definition.
+public:
+ static_assert(
+ !std::is_same_v<ContentT, void>,
+ "If you see this, you tried to use EventTemplate with the default"
+ " ContentT type, which is void. This default is only used with explicit"
+ " specialisations (see CallEvent, e.g.). Otherwise, if you don't intend"
+ " to use the content part of EventTemplate then you don't need"
+ " EventTemplate; just use the base event class directly");
+ using content_type = ContentT;
+
+ explicit EventTemplate(const QJsonObject& json)
+ : BaseEventT(json)
+ {}
+ explicit EventTemplate(const ContentT& c)
+ : BaseEventT(EventT::basicJson(EventT::TypeId, toJson(c)))
+ {}
+
+ ContentT content() const { return fromJson<ContentT>(this->contentJson()); }
+};
+
+//! \brief Supply event metatype information in base event types
+//!
+//! Use this macro in a public section of your base event class to provide
+//! type identity and enable dynamic loading of generic events of that type.
+//! Do _not_ add this macro if your class is an intermediate wrapper and is not
+//! supposed to be instantiated on its own. Provides BaseMetaType static field
+//! initialised by parameters passed to the macro, and a metaType() override
+//! pointing to that BaseMetaType.
+//! \sa EventMetaType, EventMetaType::SuppressLoadDerived
+#define QUO_BASE_EVENT(CppType_, ...) \
+ friend class EventMetaType<CppType_>; \
+ static inline EventMetaType<CppType_> BaseMetaType{ \
+ #CppType_ __VA_OPT__(,) __VA_ARGS__ }; \
+ const AbstractEventMetaType& metaType() const override \
+ { \
+ return BaseMetaType; \
+ } \
+ // End of macro
+
+//! Supply event metatype information in (specific) event types
+//!
+//! Use this macro in a public section of your event class to provide type
+//! identity and enable dynamic loading of generic events of that type.
+//! Do _not_ use this macro if your class is an intermediate wrapper and is not
+//! supposed to be instantiated on its own. Provides MetaType static field
+//! initialised as described below; a metaType() override pointing to it; and
+//! the TypeId static field that is equal to MetaType.matrixId.
+//!
+//! The first two macro parameters are used as the first two EventMetaType
+//! constructor parameters; the third EventMetaType parameter is always
+//! BaseMetaType; and additional base types can be passed in extra macro
+//! parameters if you need to include the same event type in more than one
+//! event factory hierarchy (e.g., EncryptedEvent).
+//! \sa EventMetaType
+#define QUO_EVENT(CppType_, MatrixType_, ...) \
+ static inline const auto& TypeId = MatrixType_##_ls; \
+ friend class EventMetaType<CppType_>; \
+ static inline const EventMetaType<CppType_> MetaType{ \
+ #CppType_, TypeId, BaseMetaType __VA_OPT__(,) __VA_ARGS__ \
+ }; \
+ const AbstractEventMetaType& metaType() const override \
+ { \
+ return MetaType; \
+ } \
+ [[deprecated("Use " #CppType_ "::TypeId directly instead")]] \
+ static constexpr const char* matrixTypeId() { return MatrixType_; } \
+ [[deprecated("Use " #CppType_ "::TypeId directly instead")]] \
+ static event_type_t typeId() { return TypeId; } \
+ // End of macro
+
+//! \deprecated This is the old name for what is now known as QUO_EVENT
+#define DEFINE_EVENT_TYPEID(Type_, Id_) QUO_EVENT(Type_, Id_)
+
+#define QUO_CONTENT_GETTER_X(PartType_, PartName_, JsonKey_) \
+ PartType_ PartName_() const \
+ { \
+ static const auto PartName_##JsonKey = JsonKey_; \
+ return contentPart<PartType_>(PartName_##JsonKey); \
+ }
+
//! \brief Define an inline method obtaining a content part
//!
//! This macro adds a const method that extracts a JSON value at the key
@@ -266,32 +496,12 @@ using Events = EventsArray<Event>;
//! \code
//! contentPart<PartType_>(Quotient::toSnakeCase(#PartName_##_ls));
//! \endcode
-#define QUO_CONTENT_GETTER(PartType_, PartName_) \
- PartType_ PartName_() const \
- { \
- static const auto JsonKey = toSnakeCase(#PartName_##_ls); \
- return contentPart<PartType_>(JsonKey); \
- }
-
-// === Facilities for event class definitions ===
+#define QUO_CONTENT_GETTER(PartType_, PartName_) \
+ QUO_CONTENT_GETTER_X(PartType_, PartName_, toSnakeCase(#PartName_##_ls))
-// This macro should be used in a public section of an event class to
-// provide matrixTypeId() and typeId().
-#define DEFINE_EVENT_TYPEID(Id_, Type_) \
- static constexpr event_type_t TypeId = Id_##_ls; \
- [[deprecated("Use " #Type_ "::TypeId directly instead")]] \
- static constexpr event_mtype_t matrixTypeId() { return Id_; } \
- [[deprecated("Use " #Type_ "::TypeId directly instead")]] \
- static event_type_t typeId() { return TypeId; } \
- // End of macro
-
-// This macro should be put after an event class definition (in .h or .cpp)
-// to enable its deserialisation from a /sync and other
-// polymorphic event arrays
-#define REGISTER_EVENT_TYPE(Type_) \
- [[maybe_unused]] inline const auto& factoryMethodFor##Type_ = \
- Type_::factory.addMethod<Type_>(); \
- // End of macro
+//! \deprecated This macro was used after an event class definition
+//! to enable its dynamic loading; it is completely superseded by QUO_EVENT
+#define REGISTER_EVENT_TYPE(Type_)
/// \brief Define a new event class with a single key-value pair in the content
///
@@ -301,35 +511,36 @@ using Events = EventsArray<Event>;
/// To retrieve the value the getter uses a JSON key name that corresponds to
/// its own (getter's) name but written in snake_case. \p GetterName_ must be
/// in camelCase, no quotes (an identifier, not a literal).
-#define DEFINE_SIMPLE_EVENT(Name_, Base_, TypeId_, ValueType_, GetterName_) \
- class QUOTIENT_API Name_ : public Base_ { \
- public: \
- using content_type = ValueType_; \
- DEFINE_EVENT_TYPEID(TypeId_, Name_) \
- explicit Name_(const QJsonObject& obj) : Base_(TypeId, obj) {} \
- explicit Name_(const content_type& content) \
- : Name_(Base_::basicJson(TypeId, { { JsonKey, toJson(content) } })) \
- {} \
- auto GetterName_() const \
- { \
- return contentPart<content_type>(JsonKey); \
- } \
- static inline const auto JsonKey = toSnakeCase(#GetterName_##_ls); \
- }; \
- REGISTER_EVENT_TYPE(Name_) \
+#define DEFINE_SIMPLE_EVENT(Name_, Base_, TypeId_, ValueType_, GetterName_, \
+ JsonKey_) \
+ constexpr auto Name_##ContentKey = JsonKey_##_ls; \
+ class QUOTIENT_API Name_ \
+ : public EventTemplate< \
+ Name_, Base_, \
+ EventContent::SingleKeyValue<ValueType_, Name_##ContentKey>> { \
+ public: \
+ QUO_EVENT(Name_, TypeId_) \
+ using value_type = ValueType_; \
+ using EventTemplate::EventTemplate; \
+ QUO_CONTENT_GETTER_X(ValueType_, GetterName_, Name_##ContentKey) \
+ }; \
// End of macro
// === is<>(), eventCast<>() and switchOnType<>() ===
-template <class EventT>
+template <EventClass EventT>
inline bool is(const Event& e)
{
- return e.type() == typeId<EventT>();
-}
-
-inline bool isUnknown(const Event& e)
-{
- return e.type() == UnknownEventTypeId;
+ if constexpr (requires { EventT::MetaType; }) {
+ return &e.metaType() == &EventT::MetaType;
+ } else {
+ const auto* p = &e.metaType();
+ do {
+ if (p == &EventT::BaseMetaType)
+ return true;
+ } while ((p = p->baseType) != nullptr);
+ return false;
+ }
}
//! \brief Cast the event pointer down in a type-safe way
@@ -339,7 +550,7 @@ inline bool isUnknown(const Event& e)
//! can be either "dumb" (BaseEventT*) or "smart" (`event_ptr_tt<>`). This
//! overload doesn't affect the event ownership - if the original pointer owns
//! the event it must outlive the downcast pointer to keep it from dangling.
-template <class EventT, typename BasePtrT>
+template <EventClass EventT, typename BasePtrT>
inline auto eventCast(const BasePtrT& eptr)
-> decltype(static_cast<EventT*>(&*eptr))
{
@@ -362,7 +573,7 @@ inline auto eventCast(const BasePtrT& eptr)
//! after calling this overload; if it is a temporary, this normally
//! leads to the event getting deleted along with the end of
//! the temporary's lifetime.
-template <class EventT, typename BaseEventT>
+template <EventClass EventT, typename BaseEventT>
inline auto eventCast(event_ptr_tt<BaseEventT>&& eptr)
{
return eptr && is<std::decay_t<EventT>>(*eptr)
@@ -371,12 +582,15 @@ inline auto eventCast(event_ptr_tt<BaseEventT>&& eptr)
}
namespace _impl {
- template <typename FnT, class BaseT>
- concept Invocable_With_Downcast =
+ template <typename FnT, typename BaseT>
+ concept Invocable_With_Downcast = requires
+ {
+ requires EventClass<BaseT>;
std::is_base_of_v<BaseT, std::remove_cvref_t<fn_arg_t<FnT>>>;
+ };
}
-template <class BaseT, typename TailT>
+template <EventClass BaseT, typename TailT>
inline auto switchOnType(const BaseT& event, TailT&& tail)
{
if constexpr (std::is_invocable_v<TailT, BaseT>) {
@@ -391,7 +605,7 @@ inline auto switchOnType(const BaseT& event, TailT&& tail)
}
}
-template <class BaseT, typename FnT1, typename... FnTs>
+template <EventClass BaseT, typename FnT1, typename... FnTs>
inline auto switchOnType(const BaseT& event, FnT1&& fn1, FnTs&&... fns)
{
using event_type1 = fn_arg_t<FnT1>;
@@ -400,7 +614,7 @@ inline auto switchOnType(const BaseT& event, FnT1&& fn1, FnTs&&... fns)
return switchOnType(event, std::forward<FnTs>(fns)...);
}
-template <class BaseT, typename... FnTs>
+template <EventClass BaseT, typename... FnTs>
[[deprecated("The new name for visit() is switchOnType()")]] //
inline auto visit(const BaseT& event, FnTs&&... fns)
{
diff --git a/lib/events/eventloader.h b/lib/events/eventloader.h
index 4c639efa..b4ac154c 100644
--- a/lib/events/eventloader.h
+++ b/lib/events/eventloader.h
@@ -6,40 +6,8 @@
#include "stateevent.h"
namespace Quotient {
-
-/*! Create an event with proper type from a JSON object
- *
- * Use this factory template to detect the type from the JSON object
- * contents (the detected event type should derive from the template
- * parameter type) and create an event object of that type.
- */
-template <typename BaseEventT>
-inline event_ptr_tt<BaseEventT> loadEvent(const QJsonObject& fullJson)
-{
- return doLoadEvent<BaseEventT>(fullJson, fullJson[TypeKeyL].toString());
-}
-
-//! \brief Create an event from a type string and content JSON
-//!
-//! Use this template to resolve the C++ type from the Matrix type string in
-//! \p matrixType and create an event of that type by passing all parameters
-//! to BaseEventT::basicJson().
-template <typename BaseEventT, typename... BasicJsonParamTs>
-inline event_ptr_tt<BaseEventT> loadEvent(
- const QString& matrixType, const BasicJsonParamTs&... basicJsonParams)
-{
- return doLoadEvent<BaseEventT>(
- BaseEventT::basicJson(matrixType, basicJsonParams...), matrixType);
+struct [[deprecated(
+ "This header is obsolete since libQuotient 0.7; include a header with"
+ " the respective event type definition instead")]] EventLoaderH;
+StateEventPtr eventLoaderH(EventLoaderH&);
}
-
-template <typename EventT>
-struct JsonConverter<event_ptr_tt<EventT>>
- : JsonObjectUnpacker<event_ptr_tt<EventT>> {
- using JsonObjectUnpacker<event_ptr_tt<EventT>>::load;
- static auto load(const QJsonObject& jo)
- {
- return loadEvent<EventT>(jo);
- }
-};
-
-} // namespace Quotient
diff --git a/lib/events/keyverificationevent.h b/lib/events/keyverificationevent.h
index 5b587522..0ffd8b2c 100644
--- a/lib/events/keyverificationevent.h
+++ b/lib/events/keyverificationevent.h
@@ -13,11 +13,9 @@ static constexpr auto SasV1Method = "m.sas.v1"_ls;
/// Typically sent as a to-device event.
class QUOTIENT_API KeyVerificationRequestEvent : public Event {
public:
- DEFINE_EVENT_TYPEID("m.key.verification.request", KeyVerificationRequestEvent)
+ QUO_EVENT(KeyVerificationRequestEvent, "m.key.verification.request")
- explicit KeyVerificationRequestEvent(const QJsonObject& obj)
- : Event(TypeId, obj)
- {}
+ using Event::Event;
KeyVerificationRequestEvent(const QString& transactionId,
const QString& fromDevice,
const QStringList& methods,
@@ -45,15 +43,12 @@ public:
/// by the receiver.
QUO_CONTENT_GETTER(QDateTime, timestamp)
};
-REGISTER_EVENT_TYPE(KeyVerificationRequestEvent)
class QUOTIENT_API KeyVerificationReadyEvent : public Event {
public:
- DEFINE_EVENT_TYPEID("m.key.verification.ready", KeyVerificationReadyEvent)
+ QUO_EVENT(KeyVerificationReadyEvent, "m.key.verification.ready")
- explicit KeyVerificationReadyEvent(const QJsonObject& obj)
- : Event(TypeId, obj)
- {}
+ using Event::Event;
KeyVerificationReadyEvent(const QString& transactionId,
const QString& fromDevice,
const QStringList& methods)
@@ -72,17 +67,13 @@ public:
/// The verification methods supported by the sender.
QUO_CONTENT_GETTER(QStringList, methods)
};
-REGISTER_EVENT_TYPE(KeyVerificationReadyEvent)
-
/// Begins a key verification process.
class QUOTIENT_API KeyVerificationStartEvent : public Event {
public:
- DEFINE_EVENT_TYPEID("m.key.verification.start", KeyVerificationStartEvent)
+ QUO_EVENT(KeyVerificationStartEvent, "m.key.verification.start")
- explicit KeyVerificationStartEvent(const QJsonObject& obj)
- : Event(TypeId, obj)
- {}
+ using Event::Event;
KeyVerificationStartEvent(const QString& transactionId,
const QString& fromDevice)
: KeyVerificationStartEvent(
@@ -146,17 +137,14 @@ public:
return contentPart<QString>("short_authentification_string"_ls);
}
};
-REGISTER_EVENT_TYPE(KeyVerificationStartEvent)
/// Accepts a previously sent m.key.verification.start message.
/// Typically sent as a to-device event.
class QUOTIENT_API KeyVerificationAcceptEvent : public Event {
public:
- DEFINE_EVENT_TYPEID("m.key.verification.accept", KeyVerificationAcceptEvent)
+ QUO_EVENT(KeyVerificationAcceptEvent, "m.key.verification.accept")
- explicit KeyVerificationAcceptEvent(const QJsonObject& obj)
- : Event(TypeId, obj)
- {}
+ using Event::Event;
KeyVerificationAcceptEvent(const QString& transactionId,
const QString& commitment)
: KeyVerificationAcceptEvent(basicJson(
@@ -199,15 +187,12 @@ public:
/// canonical JSON representation of the m.key.verification.start message.
QUO_CONTENT_GETTER(QString, commitment)
};
-REGISTER_EVENT_TYPE(KeyVerificationAcceptEvent)
class QUOTIENT_API KeyVerificationCancelEvent : public Event {
public:
- DEFINE_EVENT_TYPEID("m.key.verification.cancel", KeyVerificationCancelEvent)
+ QUO_EVENT(KeyVerificationCancelEvent, "m.key.verification.cancel")
- explicit KeyVerificationCancelEvent(const QJsonObject& obj)
- : Event(TypeId, obj)
- {}
+ using Event::Event;
KeyVerificationCancelEvent(const QString& transactionId,
const QString& reason)
: KeyVerificationCancelEvent(
@@ -228,17 +213,14 @@ public:
/// The error code for why the process/request was cancelled by the user.
QUO_CONTENT_GETTER(QString, code)
};
-REGISTER_EVENT_TYPE(KeyVerificationCancelEvent)
/// Sends the ephemeral public key for a device to the partner device.
/// Typically sent as a to-device event.
class QUOTIENT_API KeyVerificationKeyEvent : public Event {
public:
- DEFINE_EVENT_TYPEID("m.key.verification.key", KeyVerificationKeyEvent)
+ QUO_EVENT(KeyVerificationKeyEvent, "m.key.verification.key")
- explicit KeyVerificationKeyEvent(const QJsonObject& obj)
- : Event(TypeId, obj)
- {}
+ using Event::Event;
KeyVerificationKeyEvent(const QString& transactionId, const QString& key)
: KeyVerificationKeyEvent(
basicJson(TypeId, { { "transaction_id"_ls, transactionId },
@@ -251,16 +233,13 @@ public:
/// The device's ephemeral public key, encoded as unpadded base64.
QUO_CONTENT_GETTER(QString, key)
};
-REGISTER_EVENT_TYPE(KeyVerificationKeyEvent)
/// Sends the MAC of a device's key to the partner device.
class QUOTIENT_API KeyVerificationMacEvent : public Event {
public:
- DEFINE_EVENT_TYPEID("m.key.verification.mac", KeyVerificationMacEvent)
+ QUO_EVENT(KeyVerificationMacEvent, "m.key.verification.mac")
- explicit KeyVerificationMacEvent(const QJsonObject& obj)
- : Event(TypeId, obj)
- {}
+ using Event::Event;
KeyVerificationMacEvent(const QString& transactionId, const QString& keys,
const QJsonObject& mac)
: KeyVerificationMacEvent(
@@ -280,15 +259,12 @@ public:
return contentPart<QHash<QString, QString>>("mac"_ls);
}
};
-REGISTER_EVENT_TYPE(KeyVerificationMacEvent)
class QUOTIENT_API KeyVerificationDoneEvent : public Event {
public:
- DEFINE_EVENT_TYPEID("m.key.verification.done", KeyVerificationDoneEvent)
+ QUO_EVENT(KeyVerificationDoneEvent, "m.key.verification.done")
- explicit KeyVerificationDoneEvent(const QJsonObject& obj)
- : Event(TypeId, obj)
- {}
+ using Event::Event;
explicit KeyVerificationDoneEvent(const QString& transactionId)
: KeyVerificationDoneEvent(
basicJson(TypeId, { { "transaction_id"_ls, transactionId } }))
@@ -297,6 +273,4 @@ public:
/// The same transactionId as before
QUO_CONTENT_GETTER(QString, transactionId)
};
-REGISTER_EVENT_TYPE(KeyVerificationDoneEvent)
-
} // namespace Quotient
diff --git a/lib/events/reactionevent.h b/lib/events/reactionevent.h
index b3cb3ca7..8d873441 100644
--- a/lib/events/reactionevent.h
+++ b/lib/events/reactionevent.h
@@ -8,20 +8,7 @@
namespace Quotient {
-class QUOTIENT_API ReactionEvent : public RoomEvent {
-public:
- DEFINE_EVENT_TYPEID("m.reaction", ReactionEvent)
-
- explicit ReactionEvent(const EventRelation& value)
- : RoomEvent(typeId(), matrixTypeId(),
- { { QStringLiteral("m.relates_to"), toJson(value) } })
- {}
- explicit ReactionEvent(const QJsonObject& obj) : RoomEvent(typeId(), obj) {}
- EventRelation relation() const
- {
- return contentPart<EventRelation>(RelatesToKey);
- }
-};
-REGISTER_EVENT_TYPE(ReactionEvent)
+DEFINE_SIMPLE_EVENT(ReactionEvent, RoomEvent, "m.reaction", EventRelation,
+ relation, "m.relates_to")
} // namespace Quotient
diff --git a/lib/events/receiptevent.cpp b/lib/events/receiptevent.cpp
index 7f06d99f..d8f9fa0b 100644
--- a/lib/events/receiptevent.cpp
+++ b/lib/events/receiptevent.cpp
@@ -28,7 +28,7 @@ using namespace Quotient;
// map lookups are not used and vectors are massively faster. Same goes for
// de-/serialization of ReceiptsForEvent::receipts.
// (XXX: would this be generally preferred across CS API JSON maps?..)
-QJsonObject toJson(const EventsWithReceipts& ewrs)
+QJsonObject Quotient::toJson(const EventsWithReceipts& ewrs)
{
QJsonObject json;
for (const auto& e : ewrs) {
@@ -41,20 +41,16 @@ QJsonObject toJson(const EventsWithReceipts& ewrs)
return json;
}
-ReceiptEvent::ReceiptEvent(const EventsWithReceipts &ewrs)
- : Event(typeId(), matrixTypeId(), toJson(ewrs))
-{}
-
-EventsWithReceipts ReceiptEvent::eventsWithReceipts() const
+template<>
+EventsWithReceipts Quotient::fromJson(const QJsonObject& json)
{
EventsWithReceipts result;
- const auto& contents = contentJson();
- result.reserve(contents.size());
- for (auto eventIt = contents.begin(); eventIt != contents.end(); ++eventIt) {
+ result.reserve(json.size());
+ for (auto eventIt = json.begin(); eventIt != json.end(); ++eventIt) {
if (eventIt.key().isEmpty()) {
qCWarning(EPHEMERAL)
<< "ReceiptEvent has an empty event id, skipping";
- qCDebug(EPHEMERAL) << "ReceiptEvent content follows:\n" << contents;
+ qCDebug(EPHEMERAL) << "ReceiptEvent content follows:\n" << json;
continue;
}
const auto reads =
diff --git a/lib/events/receiptevent.h b/lib/events/receiptevent.h
index 5e077e47..b87e00f6 100644
--- a/lib/events/receiptevent.h
+++ b/lib/events/receiptevent.h
@@ -19,13 +19,17 @@ struct ReceiptsForEvent {
};
using EventsWithReceipts = QVector<ReceiptsForEvent>;
-class QUOTIENT_API ReceiptEvent : public Event {
+template <>
+QUOTIENT_API EventsWithReceipts fromJson(const QJsonObject& json);
+QUOTIENT_API QJsonObject toJson(const EventsWithReceipts& ewrs);
+
+class QUOTIENT_API ReceiptEvent
+ : public EventTemplate<ReceiptEvent, Event, EventsWithReceipts> {
public:
- DEFINE_EVENT_TYPEID("m.receipt", ReceiptEvent)
- explicit ReceiptEvent(const EventsWithReceipts& ewrs);
- explicit ReceiptEvent(const QJsonObject& obj) : Event(typeId(), obj) {}
+ QUO_EVENT(ReceiptEvent, "m.receipt")
+ using EventTemplate::EventTemplate;
- EventsWithReceipts eventsWithReceipts() const;
+ [[deprecated("Use content() instead")]]
+ EventsWithReceipts eventsWithReceipts() const { return content(); }
};
-REGISTER_EVENT_TYPE(ReceiptEvent)
} // namespace Quotient
diff --git a/lib/events/redactionevent.h b/lib/events/redactionevent.h
index 63617e54..a2e0b73b 100644
--- a/lib/events/redactionevent.h
+++ b/lib/events/redactionevent.h
@@ -8,10 +8,9 @@
namespace Quotient {
class QUOTIENT_API RedactionEvent : public RoomEvent {
public:
- DEFINE_EVENT_TYPEID("m.room.redaction", RedactionEvent)
+ QUO_EVENT(RedactionEvent, "m.room.redaction")
- explicit RedactionEvent(const QJsonObject& obj) : RoomEvent(typeId(), obj)
- {}
+ using RoomEvent::RoomEvent;
QString redactedEvent() const
{
@@ -19,5 +18,4 @@ public:
}
QUO_CONTENT_GETTER(QString, reason)
};
-REGISTER_EVENT_TYPE(RedactionEvent)
} // namespace Quotient
diff --git a/lib/events/roomavatarevent.h b/lib/events/roomavatarevent.h
index af291696..1986f852 100644
--- a/lib/events/roomavatarevent.h
+++ b/lib/events/roomavatarevent.h
@@ -8,28 +8,16 @@
namespace Quotient {
class QUOTIENT_API RoomAvatarEvent
- : public StateEvent<EventContent::ImageContent> {
+ : public KeylessStateEventBase<RoomAvatarEvent,
+ EventContent::ImageContent> {
// It's a bit of an overkill to use a full-fledged ImageContent
// because in reality m.room.avatar usually only has a single URL,
// without a thumbnail. But The Spec says there be thumbnails, and
- // we follow The Spec.
+ // we follow The Spec (and ImageContent is very convenient to reuse here).
public:
- DEFINE_EVENT_TYPEID("m.room.avatar", RoomAvatarEvent)
- explicit RoomAvatarEvent(const QJsonObject& obj) : StateEvent(typeId(), obj)
- {}
- explicit RoomAvatarEvent(const EventContent::ImageContent& avatar)
- : StateEvent(typeId(), matrixTypeId(), QString(), avatar)
- {}
- // A replica of EventContent::ImageInfo constructor
- explicit RoomAvatarEvent(const QUrl& mxcUrl, qint64 fileSize = -1,
- QMimeType mimeType = {},
- const QSize& imageSize = {},
- const QString& originalFilename = {})
- : RoomAvatarEvent(EventContent::ImageContent {
- mxcUrl, fileSize, mimeType, imageSize, originalFilename })
- {}
+ QUO_EVENT(RoomAvatarEvent, "m.room.avatar")
+ using KeylessStateEventBase::KeylessStateEventBase;
QUrl url() const { return content().url(); }
};
-REGISTER_EVENT_TYPE(RoomAvatarEvent)
} // namespace Quotient
diff --git a/lib/events/roomcanonicalaliasevent.h b/lib/events/roomcanonicalaliasevent.h
index 60ca68ac..c73bc92a 100644
--- a/lib/events/roomcanonicalaliasevent.h
+++ b/lib/events/roomcanonicalaliasevent.h
@@ -32,28 +32,13 @@ inline auto toJson(const EventContent::AliasesEventContent& c)
}
class QUOTIENT_API RoomCanonicalAliasEvent
- : public StateEvent<EventContent::AliasesEventContent> {
+ : public KeylessStateEventBase<RoomCanonicalAliasEvent,
+ EventContent::AliasesEventContent> {
public:
- DEFINE_EVENT_TYPEID("m.room.canonical_alias", RoomCanonicalAliasEvent)
-
- explicit RoomCanonicalAliasEvent(const QJsonObject& obj)
- : StateEvent(typeId(), obj)
- { }
-
- explicit RoomCanonicalAliasEvent(const QString& canonicalAlias,
- const QStringList& altAliases = {})
- : StateEvent(typeId(), matrixTypeId(), {},
- canonicalAlias, altAliases)
- { }
-
- explicit RoomCanonicalAliasEvent(QString&& canonicalAlias,
- QStringList&& altAliases = {})
- : StateEvent(typeId(), matrixTypeId(), {},
- std::move(canonicalAlias), std::move(altAliases))
- { }
+ QUO_EVENT(RoomCanonicalAliasEvent, "m.room.canonical_alias")
+ using KeylessStateEventBase::KeylessStateEventBase;
QString alias() const { return content().canonicalAlias; }
QStringList altAliases() const { return content().altAliases; }
};
-REGISTER_EVENT_TYPE(RoomCanonicalAliasEvent)
} // namespace Quotient
diff --git a/lib/events/roomcreateevent.h b/lib/events/roomcreateevent.h
index 989030ac..5968e187 100644
--- a/lib/events/roomcreateevent.h
+++ b/lib/events/roomcreateevent.h
@@ -7,13 +7,11 @@
#include "quotient_common.h"
namespace Quotient {
-class QUOTIENT_API RoomCreateEvent : public StateEventBase {
+class QUOTIENT_API RoomCreateEvent : public StateEvent {
public:
- DEFINE_EVENT_TYPEID("m.room.create", RoomCreateEvent)
+ QUO_EVENT(RoomCreateEvent, "m.room.create")
- explicit RoomCreateEvent(const QJsonObject& obj)
- : StateEventBase(typeId(), obj)
- {}
+ using StateEvent::StateEvent;
struct Predecessor {
QString roomId;
@@ -26,5 +24,4 @@ public:
bool isUpgrade() const;
RoomType roomType() const;
};
-REGISTER_EVENT_TYPE(RoomCreateEvent)
} // namespace Quotient
diff --git a/lib/events/roomevent.cpp b/lib/events/roomevent.cpp
index e695e0ec..e98cb591 100644
--- a/lib/events/roomevent.cpp
+++ b/lib/events/roomevent.cpp
@@ -8,16 +8,11 @@
using namespace Quotient;
-RoomEvent::RoomEvent(Type type, event_mtype_t matrixType,
- const QJsonObject& contentJson)
- : Event(type, matrixType, contentJson)
-{}
-
-RoomEvent::RoomEvent(Type type, const QJsonObject& json) : Event(type, json)
+RoomEvent::RoomEvent(const QJsonObject& json) : Event(json)
{
if (const auto redaction = unsignedPart<QJsonObject>(RedactedCauseKeyL);
!redaction.isEmpty())
- _redactedBecause = makeEvent<RedactionEvent>(redaction);
+ _redactedBecause = loadEvent<RedactionEvent>(redaction);
}
RoomEvent::~RoomEvent() = default; // Let the smart pointer do its job
@@ -101,28 +96,6 @@ void RoomEvent::dumpTo(QDebug dbg) const
dbg << " (made at " << originTimestamp().toString(Qt::ISODate) << ')';
}
-QJsonObject CallEventBase::basicJson(const QString& matrixType,
- const QString& callId, int version,
- QJsonObject contentJson)
-{
- contentJson.insert(QStringLiteral("call_id"), callId);
- contentJson.insert(QStringLiteral("version"), version);
- return RoomEvent::basicJson(matrixType, contentJson);
-}
-
-CallEventBase::CallEventBase(Type type, event_mtype_t matrixType,
- const QString& callId, int version,
- const QJsonObject& contentJson)
- : RoomEvent(type, basicJson(matrixType, callId, version, contentJson))
-{}
-
-CallEventBase::CallEventBase(Type type, const QJsonObject& json)
- : RoomEvent(type, json)
-{
- if (callId().isEmpty())
- qCWarning(EVENTS) << id() << "is a call event with an empty call id";
-}
-
#ifdef Quotient_E2EE_ENABLED
void RoomEvent::setOriginalEvent(event_ptr_tt<RoomEvent>&& originalEvent)
{
diff --git a/lib/events/roomevent.h b/lib/events/roomevent.h
index 9461340b..203434f6 100644
--- a/lib/events/roomevent.h
+++ b/lib/events/roomevent.h
@@ -10,17 +10,13 @@
namespace Quotient {
class RedactionEvent;
-/** This class corresponds to m.room.* events */
+// That check could look into Event and find most stuff already deleted...
+// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
class QUOTIENT_API RoomEvent : public Event {
public:
- static inline EventFactory<RoomEvent> factory { "RoomEvent" };
+ QUO_BASE_EVENT(RoomEvent, {}, Event::BaseMetaType)
- // RedactionEvent is an incomplete type here so we cannot inline
- // constructors and destructors and we cannot use 'using'.
- RoomEvent(Type type, event_mtype_t matrixType,
- const QJsonObject& contentJson = {});
- RoomEvent(Type type, const QJsonObject& json);
- ~RoomEvent() override;
+ ~RoomEvent() override; // Don't inline this - see the private section
QString id() const;
QDateTime originTimestamp() const;
@@ -67,9 +63,12 @@ public:
#endif
protected:
+ explicit RoomEvent(const QJsonObject& json);
void dumpTo(QDebug dbg) const override;
private:
+ // RedactionEvent is an incomplete type here so we cannot inline
+ // constructors using it and also destructors (with 'using', in particular).
event_ptr_tt<RedactionEvent> _redactedBecause;
#ifdef Quotient_E2EE_ENABLED
@@ -80,30 +79,6 @@ using RoomEventPtr = event_ptr_tt<RoomEvent>;
using RoomEvents = EventsArray<RoomEvent>;
using RoomEventsRange = Range<RoomEvents>;
-template <>
-inline EventPtr doLoadEvent(const QJsonObject& json, const QString& matrixType)
-{
- if (matrixType == "m.room.encrypted")
- return RoomEvent::factory.loadEvent(json, matrixType);
- return Event::factory.loadEvent(json, matrixType);
-}
-
-class QUOTIENT_API CallEventBase : public RoomEvent {
-public:
- CallEventBase(Type type, event_mtype_t matrixType, const QString& callId,
- int version, const QJsonObject& contentJson = {});
- CallEventBase(Type type, const QJsonObject& json);
- ~CallEventBase() override = default;
- bool isCallEvent() const override { return true; }
-
- QUO_CONTENT_GETTER(QString, callId)
- QUO_CONTENT_GETTER(int, version)
-
-protected:
- static QJsonObject basicJson(const QString& matrixType,
- const QString& callId, int version,
- QJsonObject contentJson = {});
-};
} // namespace Quotient
Q_DECLARE_METATYPE(Quotient::RoomEvent*)
Q_DECLARE_METATYPE(const Quotient::RoomEvent*)
diff --git a/lib/events/roomkeyevent.cpp b/lib/events/roomkeyevent.cpp
deleted file mode 100644
index 3a8601d1..00000000
--- a/lib/events/roomkeyevent.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-// SPDX-FileCopyrightText: 2019 Alexey Andreyev <aa13q@ya.ru>
-// SPDX-License-Identifier: LGPL-2.1-or-later
-
-#include "roomkeyevent.h"
-
-using namespace Quotient;
-
-RoomKeyEvent::RoomKeyEvent(const QJsonObject &obj) : Event(TypeId, obj)
-{
- if (roomId().isEmpty())
- qCWarning(E2EE) << "Room key event has empty room id";
-}
-
-RoomKeyEvent::RoomKeyEvent(const QString& algorithm, const QString& roomId,
- const QString& sessionId, const QString& sessionKey)
- : Event(TypeId, basicJson(TypeId, {
- { "algorithm", algorithm },
- { "room_id", roomId },
- { "session_id", sessionId },
- { "session_key", sessionKey },
- }))
-{}
diff --git a/lib/events/roomkeyevent.h b/lib/events/roomkeyevent.h
index 0dfdf383..dad5df8b 100644
--- a/lib/events/roomkeyevent.h
+++ b/lib/events/roomkeyevent.h
@@ -9,11 +9,18 @@ namespace Quotient {
class QUOTIENT_API RoomKeyEvent : public Event
{
public:
- DEFINE_EVENT_TYPEID("m.room_key", RoomKeyEvent)
+ QUO_EVENT(RoomKeyEvent, "m.room_key")
- explicit RoomKeyEvent(const QJsonObject& obj);
+ using Event::Event;
explicit RoomKeyEvent(const QString& algorithm, const QString& roomId,
- const QString& sessionId, const QString& sessionKey);
+ const QString& sessionId, const QString& sessionKey)
+ : Event(basicJson(TypeId, {
+ { "algorithm", algorithm },
+ { "room_id", roomId },
+ { "session_id", sessionId },
+ { "session_key", sessionKey },
+ }))
+ {}
QUO_CONTENT_GETTER(QString, algorithm)
QUO_CONTENT_GETTER(QString, roomId)
@@ -23,5 +30,4 @@ public:
return contentPart<QString>("session_key"_ls).toLatin1();
}
};
-REGISTER_EVENT_TYPE(RoomKeyEvent)
} // namespace Quotient
diff --git a/lib/events/roommemberevent.cpp b/lib/events/roommemberevent.cpp
index 953ff8ae..4e7eae1b 100644
--- a/lib/events/roommemberevent.cpp
+++ b/lib/events/roommemberevent.cpp
@@ -3,8 +3,7 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
#include "roommemberevent.h"
-
-#include <QtCore/QtAlgorithms>
+#include "logging.h"
namespace Quotient {
template <>
diff --git a/lib/events/roommemberevent.h b/lib/events/roommemberevent.h
index dd33ea6b..9f063136 100644
--- a/lib/events/roommemberevent.h
+++ b/lib/events/roommemberevent.h
@@ -28,32 +28,16 @@ public:
using MembershipType [[deprecated("Use Membership instead")]] = Membership;
-class QUOTIENT_API RoomMemberEvent : public StateEvent<MemberEventContent> {
+class QUOTIENT_API RoomMemberEvent
+ : public KeyedStateEventBase<RoomMemberEvent, MemberEventContent> {
Q_GADGET
public:
- DEFINE_EVENT_TYPEID("m.room.member", RoomMemberEvent)
+ QUO_EVENT(RoomMemberEvent, "m.room.member")
using MembershipType
[[deprecated("Use Quotient::Membership instead")]] = Membership;
- explicit RoomMemberEvent(const QJsonObject& obj) : StateEvent(typeId(), obj)
- {}
- RoomMemberEvent(const QString& userId, MemberEventContent&& content)
- : StateEvent(typeId(), matrixTypeId(), userId, std::move(content))
- {}
-
- //! \brief A special constructor to create unknown RoomMemberEvents
- //!
- //! This is needed in order to use RoomMemberEvent as a "base event class"
- //! in cases like GetMembersByRoomJob when RoomMemberEvents (rather than
- //! RoomEvents or StateEvents) are resolved from JSON. For such cases
- //! loadEvent\<> requires an underlying class to have a specialisation of
- //! EventFactory\<> and be constructible with unknownTypeId() instead of
- //! its genuine id. Don't use directly.
- //! \sa EventFactory, loadEvent, GetMembersByRoomJob
- RoomMemberEvent(Type type, const QJsonObject& fullJson)
- : StateEvent(type, fullJson)
- {}
+ using KeyedStateEventBase::KeyedStateEventBase;
Membership membership() const { return content().membership; }
QString userId() const { return stateKey(); }
@@ -79,14 +63,4 @@ public:
bool isRename() const;
bool isAvatarUpdate() const;
};
-
-template <>
-inline event_ptr_tt<RoomMemberEvent>
-doLoadEvent<RoomMemberEvent>(const QJsonObject& json, const QString& matrixType)
-{
- if (matrixType == QLatin1String(RoomMemberEvent::matrixTypeId()))
- return makeEvent<RoomMemberEvent>(json);
- return makeEvent<RoomMemberEvent>(unknownEventTypeId(), json);
-}
-REGISTER_EVENT_TYPE(RoomMemberEvent)
} // namespace Quotient
diff --git a/lib/events/roommessageevent.cpp b/lib/events/roommessageevent.cpp
index 2a6ae93c..df4840b3 100644
--- a/lib/events/roommessageevent.cpp
+++ b/lib/events/roommessageevent.cpp
@@ -128,8 +128,8 @@ QJsonObject RoomMessageEvent::assembleContentJson(const QString& plainBody,
RoomMessageEvent::RoomMessageEvent(const QString& plainBody,
const QString& jsonMsgType,
TypedBase* content)
- : RoomEvent(typeId(), matrixTypeId(),
- assembleContentJson(plainBody, jsonMsgType, content))
+ : RoomEvent(
+ basicJson(TypeId, assembleContentJson(plainBody, jsonMsgType, content)))
, _content(content)
{}
@@ -175,7 +175,7 @@ RoomMessageEvent::RoomMessageEvent(const QString& plainBody,
#endif
RoomMessageEvent::RoomMessageEvent(const QJsonObject& obj)
- : RoomEvent(typeId(), obj), _content(nullptr)
+ : RoomEvent(obj), _content(nullptr)
{
if (isRedacted())
return;
diff --git a/lib/events/roommessageevent.h b/lib/events/roommessageevent.h
index 6968ad70..889fc4dc 100644
--- a/lib/events/roommessageevent.h
+++ b/lib/events/roommessageevent.h
@@ -20,7 +20,7 @@ namespace MessageEventContent = EventContent; // Back-compatibility
class QUOTIENT_API RoomMessageEvent : public RoomEvent {
Q_GADGET
public:
- DEFINE_EVENT_TYPEID("m.room.message", RoomMessageEvent)
+ QUO_EVENT(RoomMessageEvent, "m.room.message")
enum class MsgType {
Text,
@@ -94,7 +94,7 @@ private:
Q_ENUM(MsgType)
};
-REGISTER_EVENT_TYPE(RoomMessageEvent)
+
using MessageEventType = RoomMessageEvent::MsgType;
namespace EventContent {
diff --git a/lib/events/roompowerlevelsevent.h b/lib/events/roompowerlevelsevent.h
index a1638a27..6150980a 100644
--- a/lib/events/roompowerlevelsevent.h
+++ b/lib/events/roompowerlevelsevent.h
@@ -31,16 +31,11 @@ struct QUOTIENT_API PowerLevelsEventContent {
};
class QUOTIENT_API RoomPowerLevelsEvent
- : public StateEvent<PowerLevelsEventContent> {
+ : public KeylessStateEventBase<RoomPowerLevelsEvent, PowerLevelsEventContent> {
public:
- DEFINE_EVENT_TYPEID("m.room.power_levels", RoomPowerLevelsEvent)
+ QUO_EVENT(RoomPowerLevelsEvent, "m.room.power_levels")
- explicit RoomPowerLevelsEvent(PowerLevelsEventContent&& content)
- : StateEvent(typeId(), matrixTypeId(), QString(), std::move(content))
- {}
- explicit RoomPowerLevelsEvent(const QJsonObject& obj)
- : StateEvent(typeId(), obj)
- {}
+ using KeylessStateEventBase::KeylessStateEventBase;
int invite() const { return content().invite; }
int kick() const { return content().kick; }
@@ -61,5 +56,4 @@ public:
int powerLevelForState(const QString& eventId) const;
int powerLevelForUser(const QString& userId) const;
};
-REGISTER_EVENT_TYPE(RoomPowerLevelsEvent)
} // namespace Quotient
diff --git a/lib/events/roomtombstoneevent.h b/lib/events/roomtombstoneevent.h
index 15d26923..c85b4dfd 100644
--- a/lib/events/roomtombstoneevent.h
+++ b/lib/events/roomtombstoneevent.h
@@ -6,16 +6,13 @@
#include "stateevent.h"
namespace Quotient {
-class QUOTIENT_API RoomTombstoneEvent : public StateEventBase {
+class QUOTIENT_API RoomTombstoneEvent : public StateEvent {
public:
- DEFINE_EVENT_TYPEID("m.room.tombstone", RoomTombstoneEvent)
+ QUO_EVENT(RoomTombstoneEvent, "m.room.tombstone")
- explicit RoomTombstoneEvent(const QJsonObject& obj)
- : StateEventBase(typeId(), obj)
- {}
+ using StateEvent::StateEvent;
QString serverMessage() const;
QString successorRoomId() const;
};
-REGISTER_EVENT_TYPE(RoomTombstoneEvent)
} // namespace Quotient
diff --git a/lib/events/simplestateevents.h b/lib/events/simplestateevents.h
index a8eaab56..2a0d3817 100644
--- a/lib/events/simplestateevents.h
+++ b/lib/events/simplestateevents.h
@@ -7,26 +7,18 @@
#include "single_key_value.h"
namespace Quotient {
-#define DEFINE_SIMPLE_STATE_EVENT(_Name, _TypeId, _ValueType, _ContentKey) \
- constexpr auto _Name##Key = #_ContentKey##_ls; \
- class QUOTIENT_API _Name \
- : public StateEvent< \
- EventContent::SingleKeyValue<_ValueType, &_Name##Key>> { \
- public: \
- using value_type = _ValueType; \
- DEFINE_EVENT_TYPEID(_TypeId, _Name) \
- template <typename T> \
- explicit _Name(T&& value) \
- : StateEvent(TypeId, matrixTypeId(), QString(), \
- std::forward<T>(value)) \
- {} \
- explicit _Name(QJsonObject obj) \
- : StateEvent(TypeId, std::move(obj)) \
- {} \
- auto _ContentKey() const { return content().value; } \
- }; \
- REGISTER_EVENT_TYPE(_Name) \
- // End of macro
+#define DEFINE_SIMPLE_STATE_EVENT(Name_, TypeId_, ValueType_, ContentKey_) \
+ constexpr auto Name_##Key = #ContentKey_##_ls; \
+ class QUOTIENT_API Name_ \
+ : public KeylessStateEventBase< \
+ Name_, EventContent::SingleKeyValue<ValueType_, Name_##Key>> { \
+ public: \
+ using value_type = ValueType_; \
+ QUO_EVENT(Name_, TypeId_) \
+ using KeylessStateEventBase::KeylessStateEventBase; \
+ auto ContentKey_() const { return content().value; } \
+ }; \
+// End of macro
DEFINE_SIMPLE_STATE_EVENT(RoomNameEvent, "m.room.name", QString, name)
DEFINE_SIMPLE_STATE_EVENT(RoomTopicEvent, "m.room.topic", QString, topic)
@@ -35,13 +27,14 @@ DEFINE_SIMPLE_STATE_EVENT(RoomPinnedEvent, "m.room.pinned_messages",
constexpr auto RoomAliasesEventKey = "aliases"_ls;
class QUOTIENT_API RoomAliasesEvent
- : public StateEvent<
- EventContent::SingleKeyValue<QStringList, &RoomAliasesEventKey>> {
+ : public KeyedStateEventBase<
+ RoomAliasesEvent,
+ EventContent::SingleKeyValue<QStringList, RoomAliasesEventKey>>
+{
public:
- DEFINE_EVENT_TYPEID("m.room.aliases", RoomAliasesEvent)
- explicit RoomAliasesEvent(const QJsonObject& obj)
- : StateEvent(typeId(), obj)
- {}
+ QUO_EVENT(RoomAliasesEvent, "m.room.aliases")
+ using KeyedStateEventBase::KeyedStateEventBase;
+
Q_DECL_DEPRECATED_X(
"m.room.aliases events are deprecated by the Matrix spec; use"
" RoomCanonicalAliasEvent::altAliases() to get non-authoritative aliases")
diff --git a/lib/events/single_key_value.h b/lib/events/single_key_value.h
index 75ca8cd2..ca2bd331 100644
--- a/lib/events/single_key_value.h
+++ b/lib/events/single_key_value.h
@@ -5,13 +5,22 @@
namespace Quotient {
namespace EventContent {
- template <typename T, const QLatin1String* KeyStr>
+ template <typename T, const QLatin1String& KeyStr>
struct SingleKeyValue {
+ // NOLINTBEGIN(google-explicit-constructor): that check should learn
+ // about explicit(false)
+ QUO_IMPLICIT SingleKeyValue(const T& v = {})
+ : value { v }
+ {}
+ QUO_IMPLICIT SingleKeyValue(T&& v)
+ : value { std::move(v) }
+ {}
+ // NOLINTEND(google-explicit-constructor)
T value;
};
} // namespace EventContent
-template <typename ValueT, const QLatin1String* KeyStr>
+template <typename ValueT, const QLatin1String& KeyStr>
struct JsonConverter<EventContent::SingleKeyValue<ValueT, KeyStr>> {
using content_type = EventContent::SingleKeyValue<ValueT, KeyStr>;
static content_type load(const QJsonValue& jv)
@@ -22,6 +31,6 @@ struct JsonConverter<EventContent::SingleKeyValue<ValueT, KeyStr>> {
{
return { { JsonKey, toJson(c.value) } };
}
- static inline const auto JsonKey = toSnakeCase(*KeyStr);
+ static inline const auto JsonKey = toSnakeCase(KeyStr);
};
} // namespace Quotient
diff --git a/lib/events/stateevent.cpp b/lib/events/stateevent.cpp
index 1df24df0..72ecd5ad 100644
--- a/lib/events/stateevent.cpp
+++ b/lib/events/stateevent.cpp
@@ -2,35 +2,33 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
#include "stateevent.h"
+#include "logging.h"
using namespace Quotient;
-StateEventBase::StateEventBase(Type type, const QJsonObject& json)
- : RoomEvent(json.contains(StateKeyKeyL) ? type : UnknownEventTypeId, json)
+StateEvent::StateEvent(const QJsonObject& json)
+ : RoomEvent(json)
{
- if (Event::type() == UnknownEventTypeId && !json.contains(StateKeyKeyL))
- qWarning(EVENTS) << "Attempt to create a state event with no stateKey -"
- "forcing the event type to unknown to avoid damage";
+ Q_ASSERT_X(json.contains(StateKeyKeyL), __FUNCTION__,
+ "Attempt to create a state event without state key");
}
-StateEventBase::StateEventBase(Event::Type type, event_mtype_t matrixType,
- const QString& stateKey,
+StateEvent::StateEvent(Event::Type type, const QString& stateKey,
const QJsonObject& contentJson)
- : RoomEvent(type, basicJson(type, stateKey, contentJson))
+ : RoomEvent(basicJson(type, stateKey, contentJson))
{}
-bool StateEventBase::repeatsState() const
+bool StateEvent::repeatsState() const
{
- const auto prevContentJson = unsignedPart<QJsonObject>(PrevContentKeyL);
- return fullJson().value(ContentKeyL) == prevContentJson;
+ return contentJson() == unsignedPart<QJsonObject>(PrevContentKeyL);
}
-QString StateEventBase::replacedState() const
+QString StateEvent::replacedState() const
{
return unsignedPart<QString>("replaces_state"_ls);
}
-void StateEventBase::dumpTo(QDebug dbg) const
+void StateEvent::dumpTo(QDebug dbg) const
{
if (!stateKey().isEmpty())
dbg << '<' << stateKey() << "> ";
diff --git a/lib/events/stateevent.h b/lib/events/stateevent.h
index 9f1d7118..992ec2e2 100644
--- a/lib/events/stateevent.h
+++ b/lib/events/stateevent.h
@@ -7,15 +7,25 @@
namespace Quotient {
-class QUOTIENT_API StateEventBase : public RoomEvent {
+class QUOTIENT_API StateEvent : public RoomEvent {
public:
- static inline EventFactory<StateEventBase> factory { "StateEvent" };
+ QUO_BASE_EVENT(StateEvent, "json.contains('state_key')"_ls,
+ RoomEvent::BaseMetaType)
+ static bool isValid(const QJsonObject& fullJson)
+ {
+ return fullJson.contains(StateKeyKeyL);
+ }
+
+ //! \brief Static setting of whether a given even type uses state keys
+ //!
+ //! Most event types don't use a state key; overriding this to `true`
+ //! for a given type changes the calls across Quotient to include state key
+ //! in their signatures; otherwise, state key is still accessible but
+ //! constructors and calls in, e.g., RoomStateView don't include it.
+ static constexpr auto needsStateKey = false;
- StateEventBase(Type type, const QJsonObject& json);
- StateEventBase(Type type, event_mtype_t matrixType,
- const QString& stateKey = {},
- const QJsonObject& contentJson = {});
- ~StateEventBase() override = default;
+ explicit StateEvent(Type type, const QString& stateKey = {},
+ const QJsonObject& contentJson = {});
//! Make a minimal correct Matrix state event JSON
static QJsonObject basicJson(const QString& matrixTypeId,
@@ -27,43 +37,24 @@ public:
{ ContentKey, contentJson } };
}
- bool isStateEvent() const override { return true; }
QString replacedState() const;
- void dumpTo(QDebug dbg) const override;
-
virtual bool repeatsState() const;
+
+protected:
+ explicit StateEvent(const QJsonObject& json);
+ void dumpTo(QDebug dbg) const override;
};
-using StateEventPtr = event_ptr_tt<StateEventBase>;
-using StateEvents = EventsArray<StateEventBase>;
+using StateEventBase
+ [[deprecated("StateEventBase is StateEvent now")]] = StateEvent;
+using StateEventPtr = event_ptr_tt<StateEvent>;
+using StateEvents = EventsArray<StateEvent>;
-[[deprecated("Use StateEventBase::basicJson() instead")]]
+[[deprecated("Use StateEvent::basicJson() instead")]]
inline QJsonObject basicStateEventJson(const QString& matrixTypeId,
const QJsonObject& content,
const QString& stateKey = {})
{
- return StateEventBase::basicJson(matrixTypeId, stateKey, content);
-}
-
-//! \brief Override RoomEvent factory with that from StateEventBase if JSON has
-//! stateKey
-//!
-//! This means in particular that an event with a type known to RoomEvent but
-//! having stateKey set (even to an empty value) will be treated as a state
-//! event and most likely end up as unknown (consider, e.g., m.room.message
-//! that has stateKey set).
-template <>
-inline RoomEventPtr doLoadEvent(const QJsonObject& json,
- const QString& matrixType)
-{
- if (json.contains(StateKeyKeyL))
- return StateEventBase::factory.loadEvent(json, matrixType);
- return RoomEvent::factory.loadEvent(json, matrixType);
-}
-
-template <>
-inline bool is<StateEventBase>(const Event& e)
-{
- return e.isStateEvent();
+ return StateEvent::basicJson(matrixTypeId, stateKey, content);
}
/**
@@ -74,64 +65,87 @@ inline bool is<StateEventBase>(const Event& e)
*/
using StateEventKey = std::pair<QString, QString>;
-template <typename ContentT>
-struct Prev {
- template <typename... ContentParamTs>
- explicit Prev(const QJsonObject& unsignedJson,
- ContentParamTs&&... contentParams)
- : senderId(unsignedJson.value("prev_sender"_ls).toString())
- , content(fromJson<ContentT>(unsignedJson.value(PrevContentKeyL)),
- std::forward<ContentParamTs>(contentParams)...)
- {}
-
- QString senderId;
- ContentT content;
-};
-
-template <typename ContentT>
-class StateEvent : public StateEventBase {
+template <typename EventT, typename ContentT>
+class EventTemplate<EventT, StateEvent, ContentT>
+ : public StateEvent {
public:
using content_type = ContentT;
+ struct Prev {
+ explicit Prev() = default;
+ explicit Prev(const QJsonObject& unsignedJson)
+ : senderId(fromJson<QString>(unsignedJson["prev_sender"_ls]))
+ , content(
+ fromJson<Omittable<ContentT>>(unsignedJson[PrevContentKeyL]))
+ {}
+
+ QString senderId;
+ Omittable<ContentT> content;
+ };
+
+ explicit EventTemplate(const QJsonObject& fullJson)
+ : StateEvent(fullJson)
+ , _content(fromJson<ContentT>(Event::contentJson()))
+ , _prev(unsignedJson())
+ {}
template <typename... ContentParamTs>
- explicit StateEvent(Type type, const QJsonObject& fullJson,
- ContentParamTs&&... contentParams)
- : StateEventBase(type, fullJson)
- , _content(fromJson<ContentT>(contentJson()),
- std::forward<ContentParamTs>(contentParams)...)
- {
- const auto& unsignedData = unsignedJson();
- if (unsignedData.contains(PrevContentKeyL))
- _prev = std::make_unique<Prev<ContentT>>(
- unsignedData, std::forward<ContentParamTs>(contentParams)...);
- }
- template <typename... ContentParamTs>
- explicit StateEvent(Type type, event_mtype_t matrixType,
- const QString& stateKey,
- ContentParamTs&&... contentParams)
- : StateEventBase(type, matrixType, stateKey)
- , _content{std::forward<ContentParamTs>(contentParams)...}
+ explicit EventTemplate(const QString& stateKey,
+ ContentParamTs&&... contentParams)
+ : StateEvent(EventT::TypeId, stateKey)
+ , _content { std::forward<ContentParamTs>(contentParams)... }
{
editJson().insert(ContentKey, toJson(_content));
}
const ContentT& content() const { return _content; }
+
template <typename VisitorT>
void editContent(VisitorT&& visitor)
{
visitor(_content);
editJson()[ContentKeyL] = toJson(_content);
}
- const ContentT* prevContent() const
- {
- return _prev ? &_prev->content : nullptr;
- }
- QString prevSenderId() const { return _prev ? _prev->senderId : QString(); }
+ const Omittable<ContentT>& prevContent() const { return _prev.content; }
+ QString prevSenderId() const { return _prev.senderId; }
private:
ContentT _content;
- std::unique_ptr<Prev<ContentT>> _prev;
+ Prev _prev;
+};
+
+template <typename EventT, typename ContentT>
+class KeyedStateEventBase
+ : public EventTemplate<EventT, StateEvent, ContentT> {
+public:
+ static constexpr auto needsStateKey = true;
+
+ using EventTemplate<EventT, StateEvent, ContentT>::EventTemplate;
+};
+
+template <typename EvT>
+concept Keyed_State_Event = EvT::needsStateKey;
+
+template <typename EventT, typename ContentT>
+class KeylessStateEventBase
+ : public EventTemplate<EventT, StateEvent, ContentT> {
+private:
+ using base_type = EventTemplate<EventT, StateEvent, ContentT>;
+
+public:
+ template <typename... ContentParamTs>
+ explicit KeylessStateEventBase(ContentParamTs&&... contentParams)
+ : base_type(QString(), std::forward<ContentParamTs>(contentParams)...)
+ {}
+
+protected:
+ explicit KeylessStateEventBase(const QJsonObject& fullJson)
+ : base_type(fullJson)
+ {}
};
+
+template <typename EvT>
+concept Keyless_State_Event = !EvT::needsStateKey;
+
} // namespace Quotient
-Q_DECLARE_METATYPE(Quotient::StateEventBase*)
-Q_DECLARE_METATYPE(const Quotient::StateEventBase*)
+Q_DECLARE_METATYPE(Quotient::StateEvent*)
+Q_DECLARE_METATYPE(const Quotient::StateEvent*)
diff --git a/lib/events/stickerevent.h b/lib/events/stickerevent.h
index e378422d..67905481 100644
--- a/lib/events/stickerevent.h
+++ b/lib/events/stickerevent.h
@@ -14,7 +14,7 @@ namespace Quotient {
class QUOTIENT_API StickerEvent : public RoomEvent
{
public:
- DEFINE_EVENT_TYPEID("m.sticker", StickerEvent)
+ QUO_EVENT(StickerEvent, "m.sticker")
explicit StickerEvent(const QJsonObject& obj)
: RoomEvent(TypeId, obj)
@@ -45,5 +45,4 @@ public:
private:
EventContent::ImageContent m_imageContent;
};
-REGISTER_EVENT_TYPE(StickerEvent)
} // namespace Quotient
diff --git a/lib/events/typingevent.cpp b/lib/events/typingevent.cpp
deleted file mode 100644
index 7e5d7ee6..00000000
--- a/lib/events/typingevent.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-FileCopyrightText: 2017 Kitsune Ral <Kitsune-Ral@users.sf.net>
-// SPDX-License-Identifier: LGPL-2.1-or-later
-
-#include "typingevent.h"
-
-using namespace Quotient;
-
-QStringList TypingEvent::users() const
-{
- return contentPart<QStringList>("user_ids"_ls);
-}
diff --git a/lib/events/typingevent.h b/lib/events/typingevent.h
index 522f7e42..b56475af 100644
--- a/lib/events/typingevent.h
+++ b/lib/events/typingevent.h
@@ -6,13 +6,5 @@
#include "event.h"
namespace Quotient {
-class QUOTIENT_API TypingEvent : public Event {
-public:
- DEFINE_EVENT_TYPEID("m.typing", TypingEvent)
-
- explicit TypingEvent(const QJsonObject& obj) : Event(typeId(), obj) {}
-
- QStringList users() const;
-};
-REGISTER_EVENT_TYPE(TypingEvent)
+DEFINE_SIMPLE_EVENT(TypingEvent, Event, "m.typing", QStringList, users, "user_ids")
} // namespace Quotient