aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--lib/connection.cpp1
-rw-r--r--lib/events/callanswerevent.cpp15
-rw-r--r--lib/events/callanswerevent.h5
-rw-r--r--lib/events/callcandidatesevent.h9
-rw-r--r--lib/events/callhangupevent.h12
-rw-r--r--lib/events/callinviteevent.cpp9
-rw-r--r--lib/events/callinviteevent.h5
-rw-r--r--lib/events/directchatevent.h2
-rw-r--r--lib/events/encryptedevent.cpp22
-rw-r--r--lib/events/encryptionevent.h10
-rw-r--r--lib/events/event.cpp7
-rw-r--r--lib/events/event.h174
-rw-r--r--lib/events/eventloader.h40
-rw-r--r--lib/events/keyverificationevent.h32
-rw-r--r--lib/events/receiptevent.cpp16
-rw-r--r--lib/events/receiptevent.h13
-rw-r--r--lib/events/redactionevent.h3
-rw-r--r--lib/events/roomavatarevent.h19
-rw-r--r--lib/events/roomcanonicalaliasevent.h20
-rw-r--r--lib/events/roomcreateevent.h4
-rw-r--r--lib/events/roomevent.cpp17
-rw-r--r--lib/events/roomevent.h22
-rw-r--r--lib/events/roomkeyevent.cpp22
-rw-r--r--lib/events/roomkeyevent.h11
-rw-r--r--lib/events/roommemberevent.h22
-rw-r--r--lib/events/roommessageevent.cpp7
-rw-r--r--lib/events/roompowerlevelsevent.h9
-rw-r--r--lib/events/roomtombstoneevent.h4
-rw-r--r--lib/events/simplestateevents.h42
-rw-r--r--lib/events/stateevent.cpp14
-rw-r--r--lib/events/stateevent.h115
-rw-r--r--lib/room.cpp2
-rw-r--r--lib/roomstateview.h114
-rw-r--r--lib/syncdata.cpp2
35 files changed, 405 insertions, 418 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9983f860..d4cf52d0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -165,7 +165,7 @@ list(APPEND lib_SRCS
lib/events/directchatevent.h lib/events/directchatevent.cpp
lib/events/encryptionevent.h lib/events/encryptionevent.cpp
lib/events/encryptedevent.h lib/events/encryptedevent.cpp
- lib/events/roomkeyevent.h lib/events/roomkeyevent.cpp
+ lib/events/roomkeyevent.h
lib/events/stickerevent.h
lib/events/filesourceinfo.h lib/events/filesourceinfo.cpp
lib/jobs/requestdata.h lib/jobs/requestdata.cpp
diff --git a/lib/connection.cpp b/lib/connection.cpp
index 722829e8..471dc20d 100644
--- a/lib/connection.cpp
+++ b/lib/connection.cpp
@@ -28,7 +28,6 @@
#include "csapi/whoami.h"
#include "events/directchatevent.h"
-#include "events/eventloader.h"
#include "jobs/downloadfilejob.h"
#include "jobs/mediathumbnailjob.h"
#include "jobs/syncjob.h"
diff --git a/lib/events/callanswerevent.cpp b/lib/events/callanswerevent.cpp
index f75f8ad3..89dcd7fd 100644
--- a/lib/events/callanswerevent.cpp
+++ b/lib/events/callanswerevent.cpp
@@ -26,16 +26,9 @@ 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 } } } })
+ : EventTemplate(callId, { { QStringLiteral("answer"),
+ QJsonObject { { QStringLiteral("type"),
+ QStringLiteral("answer") },
+ { QStringLiteral("sdp"), sdp } } } })
{}
diff --git a/lib/events/callanswerevent.h b/lib/events/callanswerevent.h
index 70ca1c7e..c5ad14df 100644
--- a/lib/events/callanswerevent.h
+++ b/lib/events/callanswerevent.h
@@ -7,11 +7,12 @@
#include "roomevent.h"
namespace Quotient {
-class QUOTIENT_API CallAnswerEvent : public CallEventBase {
+class QUOTIENT_API CallAnswerEvent
+ : public EventTemplate<CallAnswerEvent, CallEventBase> {
public:
QUO_EVENT(CallAnswerEvent, "m.call.answer")
- explicit CallAnswerEvent(const QJsonObject& obj);
+ using EventTemplate::EventTemplate;
explicit CallAnswerEvent(const QString& callId, const QString& sdp);
diff --git a/lib/events/callcandidatesevent.h b/lib/events/callcandidatesevent.h
index cb96f358..f5d2f815 100644
--- a/lib/events/callcandidatesevent.h
+++ b/lib/events/callcandidatesevent.h
@@ -9,18 +9,15 @@
#include "roomevent.h"
namespace Quotient {
-class CallCandidatesEvent : public CallEventBase {
+class CallCandidatesEvent : public EventTemplate<CallCandidatesEvent, CallEventBase> {
public:
QUO_EVENT(CallCandidatesEvent, "m.call.candidates")
- explicit CallCandidatesEvent(const QJsonObject& obj)
- : CallEventBase(typeId(), obj)
- {}
+ using EventTemplate::EventTemplate;
explicit CallCandidatesEvent(const QString& callId,
const QJsonArray& candidates)
- : CallEventBase(typeId(), matrixTypeId(), callId, 0,
- { { QStringLiteral("candidates"), candidates } })
+ : EventTemplate(callId, { { QStringLiteral("candidates"), candidates } })
{}
QUO_CONTENT_GETTER(QJsonArray, candidates)
diff --git a/lib/events/callhangupevent.h b/lib/events/callhangupevent.h
index e4d9bb78..f0b131b9 100644
--- a/lib/events/callhangupevent.h
+++ b/lib/events/callhangupevent.h
@@ -7,15 +7,11 @@
#include "roomevent.h"
namespace Quotient {
-class QUOTIENT_API CallHangupEvent : public CallEventBase {
+class QUOTIENT_API CallHangupEvent
+ : public EventTemplate<CallHangupEvent, CallEventBase> {
public:
QUO_EVENT(CallHangupEvent, "m.call.hangup")
-
- explicit CallHangupEvent(const QJsonObject& obj)
- : CallEventBase(typeId(), obj)
- {}
- explicit CallHangupEvent(const QString& callId)
- : CallEventBase(typeId(), matrixTypeId(), callId, 0)
- {}
+ using EventTemplate::EventTemplate;
};
+//REGISTER_EVENT_TYPE(CallHangupEvent)
} // namespace Quotient
diff --git a/lib/events/callinviteevent.cpp b/lib/events/callinviteevent.cpp
index 2f26a1cb..0232275b 100644
--- a/lib/events/callinviteevent.cpp
+++ b/lib/events/callinviteevent.cpp
@@ -27,16 +27,9 @@ 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,
+ : EventTemplate<CallInviteEvent, CallEventBase>(callId,
{ { QStringLiteral("lifetime"), lifetime },
{ QStringLiteral("offer"),
QJsonObject { { QStringLiteral("type"), QStringLiteral("offer") },
diff --git a/lib/events/callinviteevent.h b/lib/events/callinviteevent.h
index f96f416d..fc22f7e1 100644
--- a/lib/events/callinviteevent.h
+++ b/lib/events/callinviteevent.h
@@ -7,11 +7,12 @@
#include "roomevent.h"
namespace Quotient {
-class QUOTIENT_API CallInviteEvent : public CallEventBase {
+class QUOTIENT_API CallInviteEvent
+ : public EventTemplate<CallInviteEvent, CallEventBase> {
public:
QUO_EVENT(CallInviteEvent, "m.call.invite")
- explicit CallInviteEvent(const QJsonObject& obj);
+ using EventTemplate::EventTemplate;
explicit CallInviteEvent(const QString& callId, int lifetime,
const QString& sdp);
diff --git a/lib/events/directchatevent.h b/lib/events/directchatevent.h
index 942edba4..0756d816 100644
--- a/lib/events/directchatevent.h
+++ b/lib/events/directchatevent.h
@@ -10,7 +10,7 @@ class QUOTIENT_API DirectChatEvent : public Event {
public:
QUO_EVENT(DirectChatEvent, "m.direct")
- explicit DirectChatEvent(const QJsonObject& obj) : Event(typeId(), obj) {}
+ using Event::Event;
QMultiHash<QString, QString> usersToDirectChats() const;
};
diff --git a/lib/events/encryptedevent.cpp b/lib/events/encryptedevent.cpp
index ec00ad4c..c539d5b2 100644
--- a/lib/events/encryptedevent.cpp
+++ b/lib/events/encryptedevent.cpp
@@ -2,33 +2,29 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
#include "encryptedevent.h"
-#include "roommessageevent.h"
-#include "events/eventloader.h"
using namespace Quotient;
EncryptedEvent::EncryptedEvent(const QJsonObject& ciphertext,
const QString& senderKey)
- : RoomEvent(typeId(), matrixTypeId(),
- { { AlgorithmKeyL, OlmV1Curve25519AesSha2AlgoKey },
+ : RoomEvent({ { AlgorithmKeyL, OlmV1Curve25519AesSha2AlgoKey },
{ CiphertextKeyL, ciphertext },
{ SenderKeyKeyL, senderKey } })
{}
EncryptedEvent::EncryptedEvent(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/encryptionevent.h b/lib/events/encryptionevent.h
index 60e77451..4bf7459c 100644
--- a/lib/events/encryptionevent.h
+++ b/lib/events/encryptionevent.h
@@ -26,7 +26,8 @@ public:
int rotationPeriodMsgs = 100;
};
-class QUOTIENT_API EncryptionEvent : public StateEvent<EncryptionEventContent> {
+class QUOTIENT_API EncryptionEvent
+ : public KeylessStateEventBase<EncryptionEvent, EncryptionEventContent> {
public:
QUO_EVENT(EncryptionEvent, "m.room.encryption")
@@ -34,12 +35,7 @@ public:
[[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; }
diff --git a/lib/events/event.cpp b/lib/events/event.cpp
index 595e20a5..2843e1dc 100644
--- a/lib/events/event.cpp
+++ b/lib/events/event.cpp
@@ -46,7 +46,8 @@ void AbstractEventMetaType::addDerived(AbstractEventMetaType* newType)
<< 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)) {
@@ -55,10 +56,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(); }
diff --git a/lib/events/event.h b/lib/events/event.h
index ea827244..8a8d64b0 100644
--- a/lib/events/event.h
+++ b/lib/events/event.h
@@ -9,7 +9,7 @@
#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>;
@@ -49,42 +49,18 @@ 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;
-}
-
-constexpr event_type_t UnknownEventTypeId = "?"_ls;
-[[deprecated("Use UnknownEventTypeId")]]
-constexpr event_type_t unknownEventTypeId() { return UnknownEventTypeId; }
-
-// === Event creation facilities ===
-
-//! 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)...);
-}
-
// === EventMetaType ===
class Event;
@@ -195,7 +171,7 @@ public:
Event* event = nullptr;
const bool goodEnough = doLoadFrom(fullJson, type, event);
if (!event && goodEnough)
- return event_ptr_tt<EventT>{ makeEvent(fullJson) };
+ return event_ptr_tt<EventT>{ new EventT(fullJson) };
return event_ptr_tt<EventT>{ static_cast<EventT*>(event) };
}
@@ -220,18 +196,20 @@ private:
return false;
} else if constexpr (!requires { EventT::TypeId; })
return true; // Create a generic event object if on the top level
- event = makeEvent(fullJson);
+ event = new EventT(fullJson);
return false;
}
- static auto makeEvent(const QJsonObject& fullJson)
- {
- if constexpr (requires { EventT::TypeId; })
- return new EventT(fullJson);
- else
- return new EventT(UnknownEventTypeId, fullJson);
- }
};
+// === Event creation facilities ===
+
+//! \brief 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 <class EventT>
constexpr const auto& mostSpecificMetaType()
{
@@ -241,13 +219,43 @@ constexpr const auto& mostSpecificMetaType()
return EventT::BaseMetaType;
}
-template <class EventT>
-inline event_ptr_tt<EventT> doLoadEvent(const QJsonObject& json,
- const QString& matrixType)
+//! \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 <typename EventT>
+inline event_ptr_tt<EventT> loadEvent(const QJsonObject& fullJson)
{
- return mostSpecificMetaType<EventT>().loadFrom(json, matrixType);
+ 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 <typename EventT>
+inline event_ptr_tt<EventT> loadEvent(const QString& matrixType,
+ const auto&... otherBasicJsonParams)
+{
+ return mostSpecificMetaType<EventT>().loadFrom(
+ EventT::basicJson(matrixType, otherBasicJsonParams...), matrixType);
+}
+
+template <typename 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 {
@@ -259,10 +267,8 @@ public:
return BaseMetaType;
}
+ explicit Event(const QJsonObject& json);
- 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& operator=(Event&&) = delete;
@@ -312,6 +318,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
{
@@ -327,6 +338,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
{
@@ -353,7 +369,6 @@ protected:
virtual void dumpTo(QDebug dbg) const;
private:
- Type _type;
QJsonObject _json;
};
using EventPtr = event_ptr_tt<Event>;
@@ -364,6 +379,45 @@ 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<CallEventBase>, 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 <class EventT, class BaseEventT, typename ContentT = void>
+class EventTemplate : public BaseEventT {
+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 CallEventBase, 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
@@ -445,19 +499,19 @@ 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_, \
- JsonKey_) \
- class QUOTIENT_API Name_ : public Base_ { \
- public: \
- QUO_EVENT(Name_, TypeId_) \
- using value_type = ValueType_; \
- explicit Name_(const QJsonObject& obj) : Base_(TypeId, obj) {} \
- explicit Name_(const value_type& v) \
- : Name_(Base_::basicJson(TypeId, { { JsonKey, toJson(v) } })) \
- {} \
- QUO_CONTENT_GETTER_X(ValueType_, GetterName_, JsonKey) \
- static inline const auto JsonKey = toSnakeCase(#GetterName_##_ls); \
- }; \
+#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<>() ===
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 5b5a518f..0ffd8b2c 100644
--- a/lib/events/keyverificationevent.h
+++ b/lib/events/keyverificationevent.h
@@ -15,9 +15,7 @@ class QUOTIENT_API KeyVerificationRequestEvent : public Event {
public:
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,
@@ -50,9 +48,7 @@ class QUOTIENT_API KeyVerificationReadyEvent : public Event {
public:
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)
@@ -77,9 +73,7 @@ class QUOTIENT_API KeyVerificationStartEvent : public Event {
public:
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(
@@ -150,9 +144,7 @@ class QUOTIENT_API KeyVerificationAcceptEvent : public Event {
public:
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(
@@ -200,9 +192,7 @@ class QUOTIENT_API KeyVerificationCancelEvent : public Event {
public:
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(
@@ -230,9 +220,7 @@ class QUOTIENT_API KeyVerificationKeyEvent : public Event {
public:
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,9 +239,7 @@ class QUOTIENT_API KeyVerificationMacEvent : public Event {
public:
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(
@@ -278,9 +264,7 @@ class QUOTIENT_API KeyVerificationDoneEvent : public Event {
public:
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 } }))
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 a02f4592..b87e00f6 100644
--- a/lib/events/receiptevent.h
+++ b/lib/events/receiptevent.h
@@ -19,12 +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:
QUO_EVENT(ReceiptEvent, "m.receipt")
- explicit ReceiptEvent(const EventsWithReceipts& ewrs);
- explicit ReceiptEvent(const QJsonObject& obj) : Event(typeId(), obj) {}
+ using EventTemplate::EventTemplate;
- EventsWithReceipts eventsWithReceipts() const;
+ [[deprecated("Use content() instead")]]
+ EventsWithReceipts eventsWithReceipts() const { return content(); }
};
} // namespace Quotient
diff --git a/lib/events/redactionevent.h b/lib/events/redactionevent.h
index c193054a..a2e0b73b 100644
--- a/lib/events/redactionevent.h
+++ b/lib/events/redactionevent.h
@@ -10,8 +10,7 @@ class QUOTIENT_API RedactionEvent : public RoomEvent {
public:
QUO_EVENT(RedactionEvent, "m.room.redaction")
- explicit RedactionEvent(const QJsonObject& obj) : RoomEvent(typeId(), obj)
- {}
+ using RoomEvent::RoomEvent;
QString redactedEvent() const
{
diff --git a/lib/events/roomavatarevent.h b/lib/events/roomavatarevent.h
index 2ebe29bf..1986f852 100644
--- a/lib/events/roomavatarevent.h
+++ b/lib/events/roomavatarevent.h
@@ -8,26 +8,15 @@
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:
QUO_EVENT(RoomAvatarEvent, "m.room.avatar")
- 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 })
- {}
+ using KeylessStateEventBase::KeylessStateEventBase;
QUrl url() const { return content().url(); }
};
diff --git a/lib/events/roomcanonicalaliasevent.h b/lib/events/roomcanonicalaliasevent.h
index e1c7888e..c73bc92a 100644
--- a/lib/events/roomcanonicalaliasevent.h
+++ b/lib/events/roomcanonicalaliasevent.h
@@ -32,25 +32,11 @@ inline auto toJson(const EventContent::AliasesEventContent& c)
}
class QUOTIENT_API RoomCanonicalAliasEvent
- : public StateEvent<EventContent::AliasesEventContent> {
+ : public KeylessStateEventBase<RoomCanonicalAliasEvent,
+ EventContent::AliasesEventContent> {
public:
QUO_EVENT(RoomCanonicalAliasEvent, "m.room.canonical_alias")
-
- 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))
- { }
+ using KeylessStateEventBase::KeylessStateEventBase;
QString alias() const { return content().canonicalAlias; }
QStringList altAliases() const { return content().altAliases; }
diff --git a/lib/events/roomcreateevent.h b/lib/events/roomcreateevent.h
index f22752b4..2709258f 100644
--- a/lib/events/roomcreateevent.h
+++ b/lib/events/roomcreateevent.h
@@ -11,9 +11,7 @@ class QUOTIENT_API RoomCreateEvent : public StateEventBase {
public:
QUO_EVENT(RoomCreateEvent, "m.room.create")
- explicit RoomCreateEvent(const QJsonObject& obj)
- : StateEventBase(typeId(), obj)
- {}
+ using StateEventBase::StateEventBase;
struct Predecessor {
QString roomId;
diff --git a/lib/events/roomevent.cpp b/lib/events/roomevent.cpp
index e695e0ec..bd06f5c5 100644
--- a/lib/events/roomevent.cpp
+++ b/lib/events/roomevent.cpp
@@ -8,12 +8,7 @@
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())
@@ -110,14 +105,8 @@ QJsonObject CallEventBase::basicJson(const QString& matrixType,
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)
+CallEventBase::CallEventBase(const QJsonObject& json)
+ : RoomEvent(json)
{
if (callId().isEmpty())
qCWarning(EVENTS) << id() << "is a call event with an empty call id";
diff --git a/lib/events/roomevent.h b/lib/events/roomevent.h
index 532e72e2..830f1d30 100644
--- a/lib/events/roomevent.h
+++ b/lib/events/roomevent.h
@@ -17,10 +17,8 @@ public:
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);
+ // constructors using it and also destructors (with 'using', in particular).
+ explicit RoomEvent(const QJsonObject& json);
~RoomEvent() override;
QString id() const;
@@ -85,10 +83,7 @@ class QUOTIENT_API CallEventBase : public RoomEvent {
public:
QUO_BASE_EVENT(CallEventBase, "m.call.*"_ls, RoomEvent::BaseMetaType)
- CallEventBase(Type type, event_mtype_t matrixType, const QString& callId,
- int version, const QJsonObject& contentJson = {});
- CallEventBase(Type type, const QJsonObject& json);
- ~CallEventBase() override = default;
+ explicit CallEventBase(const QJsonObject& json);
QUO_CONTENT_GETTER(QString, callId)
QUO_CONTENT_GETTER(int, version)
@@ -98,6 +93,17 @@ protected:
const QString& callId, int version,
QJsonObject contentJson = {});
};
+
+template <typename EventT>
+class EventTemplate<EventT, CallEventBase, void> : public CallEventBase {
+public:
+ using CallEventBase::CallEventBase;
+ explicit EventTemplate(const QString& callId,
+ const QJsonObject& contentJson = {})
+ : EventTemplate(basicJson(EventT::TypeId, callId, 0, 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 6883a2a5..dad5df8b 100644
--- a/lib/events/roomkeyevent.h
+++ b/lib/events/roomkeyevent.h
@@ -11,9 +11,16 @@ class QUOTIENT_API RoomKeyEvent : public Event
public:
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)
diff --git a/lib/events/roommemberevent.h b/lib/events/roommemberevent.h
index c690586e..9f063136 100644
--- a/lib/events/roommemberevent.h
+++ b/lib/events/roommemberevent.h
@@ -28,7 +28,8 @@ 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:
QUO_EVENT(RoomMemberEvent, "m.room.member")
@@ -36,24 +37,7 @@ public:
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(); }
diff --git a/lib/events/roommessageevent.cpp b/lib/events/roommessageevent.cpp
index 2a6ae93c..db5afaf1 100644
--- a/lib/events/roommessageevent.cpp
+++ b/lib/events/roommessageevent.cpp
@@ -128,8 +128,9 @@ QJsonObject RoomMessageEvent::assembleContentJson(const QString& plainBody,
RoomMessageEvent::RoomMessageEvent(const QString& plainBody,
const QString& jsonMsgType,
TypedBase* content)
- : RoomEvent(typeId(), matrixTypeId(),
- assembleContentJson(plainBody, jsonMsgType, content))
+ : RoomEvent(RoomEvent::basicJson(TypeId,
+ assembleContentJson(plainBody, jsonMsgType,
+ content)))
, _content(content)
{}
@@ -175,7 +176,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/roompowerlevelsevent.h b/lib/events/roompowerlevelsevent.h
index 7ac12db0..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:
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; }
diff --git a/lib/events/roomtombstoneevent.h b/lib/events/roomtombstoneevent.h
index 97586587..95743e32 100644
--- a/lib/events/roomtombstoneevent.h
+++ b/lib/events/roomtombstoneevent.h
@@ -10,9 +10,7 @@ class QUOTIENT_API RoomTombstoneEvent : public StateEventBase {
public:
QUO_EVENT(RoomTombstoneEvent, "m.room.tombstone")
- explicit RoomTombstoneEvent(const QJsonObject& obj)
- : StateEventBase(typeId(), obj)
- {}
+ using StateEventBase::StateEventBase;
QString serverMessage() const;
QString successorRoomId() const;
diff --git a/lib/events/simplestateevents.h b/lib/events/simplestateevents.h
index c79d03b0..d84dc1b1 100644
--- a/lib/events/simplestateevents.h
+++ b/lib/events/simplestateevents.h
@@ -7,25 +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; \
- QUO_EVENT(_Name, _TypeId) \
- 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; } \
- }; \
- // 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)
@@ -34,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:
QUO_EVENT(RoomAliasesEvent, "m.room.aliases")
- explicit RoomAliasesEvent(const QJsonObject& obj)
- : StateEvent(typeId(), obj)
- {}
+ 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/stateevent.cpp b/lib/events/stateevent.cpp
index 1df24df0..e117f8a0 100644
--- a/lib/events/stateevent.cpp
+++ b/lib/events/stateevent.cpp
@@ -5,18 +5,16 @@
using namespace Quotient;
-StateEventBase::StateEventBase(Type type, const QJsonObject& json)
- : RoomEvent(json.contains(StateKeyKeyL) ? type : UnknownEventTypeId, json)
+StateEventBase::StateEventBase(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,
+StateEventBase::StateEventBase(Event::Type type, const QString& stateKey,
const QJsonObject& contentJson)
- : RoomEvent(type, basicJson(type, stateKey, contentJson))
+ : RoomEvent(basicJson(type, stateKey, contentJson))
{}
bool StateEventBase::repeatsState() const
diff --git a/lib/events/stateevent.h b/lib/events/stateevent.h
index 74876803..911972f2 100644
--- a/lib/events/stateevent.h
+++ b/lib/events/stateevent.h
@@ -16,11 +16,17 @@ public:
return fullJson.contains(StateKeyKeyL);
}
- StateEventBase(Type type, const QJsonObject& json);
- StateEventBase(Type type, event_mtype_t matrixType,
- const QString& stateKey = {},
- const QJsonObject& contentJson = {});
- ~StateEventBase() override = default;
+ //! \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;
+
+ explicit StateEventBase(const QJsonObject& json);
+ explicit StateEventBase(Type type, const QString& stateKey = {},
+ const QJsonObject& contentJson = {});
//! Make a minimal correct Matrix state event JSON
static QJsonObject basicJson(const QString& matrixTypeId,
@@ -56,64 +62,85 @@ inline QJsonObject basicStateEventJson(const QString& matrixTypeId,
*/
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, StateEventBase, ContentT>
+ : public StateEventBase {
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)
+ : StateEventBase(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)
+ : StateEventBase(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, StateEventBase, ContentT> {
+public:
+ static constexpr auto needsStateKey = true;
+
+ using EventTemplate<EventT, StateEventBase, ContentT>::EventTemplate;
+};
+
+template <typename EvT>
+concept Keyed_State_Event = EvT::needsStateKey;
+
+template <typename EventT, typename ContentT>
+class KeylessStateEventBase
+ : public EventTemplate<EventT, StateEventBase, ContentT> {
+private:
+ using base_type = EventTemplate<EventT, StateEventBase, ContentT>;
+
+public:
+ explicit KeylessStateEventBase(const QJsonObject& fullJson)
+ : base_type(fullJson)
+ {}
+ template <typename... ContentParamTs>
+ explicit KeylessStateEventBase(ContentParamTs&&... contentParams)
+ : base_type(QString(), std::forward<ContentParamTs>(contentParams)...)
+ {}
+};
+
+template <typename EvT>
+concept Keyless_State_Event = !EvT::needsStateKey;
+
} // namespace Quotient
Q_DECLARE_METATYPE(Quotient::StateEventBase*)
Q_DECLARE_METATYPE(const Quotient::StateEventBase*)
diff --git a/lib/room.cpp b/lib/room.cpp
index 4cae2333..f11b03e1 100644
--- a/lib/room.cpp
+++ b/lib/room.cpp
@@ -2321,7 +2321,7 @@ void Room::setTopic(const QString& newTopic)
bool isEchoEvent(const RoomEventPtr& le, const PendingEventItem& re)
{
- if (le->type() != re->type())
+ if (le->metaType() != re->metaType())
return false;
if (!re->id().isEmpty())
diff --git a/lib/roomstateview.h b/lib/roomstateview.h
index 29cce00e..13b375f2 100644
--- a/lib/roomstateview.h
+++ b/lib/roomstateview.h
@@ -11,6 +11,16 @@ namespace Quotient {
class Room;
+// NB: Both concepts below expect EvT::needsStateKey to exist so you can't
+// express one via negation of the other (there's still an invalid case of
+// a non-state event where needsStateKey is not even defined).
+
+template <typename FnT, class EvT = std::decay_t<fn_arg_t<FnT>>>
+concept Keyed_State_Fn = EvT::needsStateKey;
+
+template <typename FnT, class EvT = std::decay_t<fn_arg_t<FnT>>>
+concept Keyless_State_Fn = !EvT::needsStateKey;
+
class QUOTIENT_API RoomStateView
: private QHash<StateEventKey, const StateEventBase*> {
Q_GADGET
@@ -36,31 +46,48 @@ public:
//! \brief Get a state event with the given event type and state key
//!
//! This is a typesafe overload that accepts a C++ event type instead of
- //! its Matrix name.
- //! \warning In libQuotient 0.7 the return type changed to an Omittable with
- //! a reference wrapper inside - you have to check that it
- //! has_value() before using. Alternatively you can now use
- //! queryCurrentState() to access state safely.
- template <typename EvT>
+ //! its Matrix name. It is only defined for events with state key (i.e.,
+ //! derived from KeyedStateEvent).
+ template <Keyed_State_Event EvT>
const EvT* get(const QString& stateKey = {}) const
{
- static_assert(std::is_base_of_v<StateEventBase, EvT>);
- if (const auto* evt = get(EvT::matrixTypeId(), stateKey)) {
- Q_ASSERT(evt->matrixType() == EvT::matrixTypeId()
+ if (const auto* evt = get(EvT::TypeId, stateKey)) {
+ Q_ASSERT(evt->matrixType() == EvT::TypeId
&& evt->stateKey() == stateKey);
return eventCast<const EvT>(evt);
}
return nullptr;
}
+ //! \brief Get a state event with the given event type
+ //!
+ //! This is a typesafe overload that accepts a C++ event type instead of
+ //! its Matrix name. This overload only defined for events that do not use
+ //! state key (i.e., derived from KeylessStateEvent).
+ template <Keyless_State_Event EvT>
+ const EvT* get() const
+ {
+ if (const auto* evt = get(EvT::TypeId)) {
+ Q_ASSERT(evt->matrixType() == EvT::TypeId);
+ return eventCast<const EvT>(evt);
+ }
+ return nullptr;
+ }
+
using QHash::contains;
bool contains(const QString& evtType, const QString& stateKey = {}) const;
- template <typename EvT>
+ template <Keyed_State_Event EvT>
bool contains(const QString& stateKey = {}) const
{
- return contains(EvT::matrixTypeId(), stateKey);
+ return contains(EvT::TypeId, stateKey);
+ }
+
+ template <Keyless_State_Event EvT>
+ bool contains() const
+ {
+ return contains(EvT::TypeId);
}
//! \brief Get the content of the current state event with the given
@@ -78,48 +105,85 @@ public:
const QVector<const StateEventBase*>
eventsOfType(const QString& evtType) const;
+ //! \brief Run a function on a state event with the given type and key
+ //!
+ //! Use this overload when there's no predefined event type or the event
+ //! type is unknown at compile time.
+ //! \return an Omittable with either the result of the function call, or
+ //! with `none` if the event is not found or the function fails
template <typename FnT>
auto query(const QString& evtType, const QString& stateKey, FnT&& fn) const
{
return lift(std::forward<FnT>(fn), get(evtType, stateKey));
}
- template <typename FnT>
+ //! \brief Run a function on a state event with the given type and key
+ //!
+ //! This is an overload for keyed state events (those that have
+ //! `needsStateKey == true`) with type defined at compile time.
+ //! \return an Omittable with either the result of the function call, or
+ //! with `none` if the event is not found or the function fails
+ template <Keyed_State_Fn FnT>
auto query(const QString& stateKey, FnT&& fn) const
{
using EventT = std::decay_t<fn_arg_t<FnT>>;
- static_assert(std::is_base_of_v<StateEventBase, EventT>);
return lift(std::forward<FnT>(fn), get<EventT>(stateKey));
}
+ //! \brief Run a function on a keyless state event with the given type
+ //!
+ //! This is an overload for keyless state events (those having
+ //! `needsStateKey == false`) with type defined at compile time.
+ //! \return an Omittable with either the result of the function call, or
+ //! with `none` if the event is not found or the function fails
+ template <Keyless_State_Fn FnT>
+ auto query(FnT&& fn) const
+ {
+ using EventT = std::decay_t<fn_arg_t<FnT>>;
+ return lift(std::forward<FnT>(fn), get<EventT>());
+ }
+
+ //! \brief Same as query() but with a fallback value
+ //!
+ //! This is a shortcut for `query().value_or()`, passing respective
+ //! arguments to the respective functions. This is an overload for the case
+ //! when the event type cannot be fixed at compile time.
+ //! \return the result of \p fn execution, or \p fallback if the requested
+ //! event doesn't exist or the function fails
template <typename FnT, typename FallbackT>
auto queryOr(const QString& evtType, const QString& stateKey, FnT&& fn,
FallbackT&& fallback) const
{
- return lift(std::forward<FnT>(fn), get(evtType, stateKey))
+ return query(evtType, stateKey, std::forward<FnT>(fn))
.value_or(std::forward<FallbackT>(fallback));
}
- template <typename FnT>
- auto query(FnT&& fn) const
- {
- return query({}, std::forward<FnT>(fn));
- }
-
+ //! \brief Same as query() but with a fallback value
+ //!
+ //! This is a shortcut for `query().value_or()`, passing respective
+ //! arguments to the respective functions. This is an overload for the case
+ //! when the event type cannot be fixed at compile time.
+ //! \return the result of \p fn execution, or \p fallback if the requested
+ //! event doesn't exist or the function fails
template <typename FnT, typename FallbackT>
auto queryOr(const QString& stateKey, FnT&& fn, FallbackT&& fallback) const
{
- using EventT = std::decay_t<fn_arg_t<FnT>>;
- static_assert(std::is_base_of_v<StateEventBase, EventT>);
- return lift(std::forward<FnT>(fn), get<EventT>(stateKey))
+ return query(stateKey, std::forward<FnT>(fn))
.value_or(std::forward<FallbackT>(fallback));
}
+ //! \brief Same as query() but with a fallback value
+ //!
+ //! This is a shortcut for `query().value_or()`, passing respective
+ //! arguments to the respective functions. This is an overload for the case
+ //! when the event type cannot be fixed at compile time.
+ //! \return the result of \p fn execution, or \p fallback if the requested
+ //! event doesn't exist or the function fails
template <typename FnT, typename FallbackT>
auto queryOr(FnT&& fn, FallbackT&& fallback) const
{
- return queryOr({}, std::forward<FnT>(fn),
- std::forward<FallbackT>(fallback));
+ return query(std::forward<FnT>(fn))
+ .value_or(std::forward<FallbackT>(fallback));
}
private:
diff --git a/lib/syncdata.cpp b/lib/syncdata.cpp
index 93416bc4..eb6c932b 100644
--- a/lib/syncdata.cpp
+++ b/lib/syncdata.cpp
@@ -3,8 +3,6 @@
#include "syncdata.h"
-#include "events/eventloader.h"
-
#include <QtCore/QFile>
#include <QtCore/QFileInfo>