libQuotient
A Qt library for building matrix clients
stateevent.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net>
2 // SPDX-License-Identifier: LGPL-2.1-or-later
3 
4 #pragma once
5 
6 #include "roomevent.h"
7 
8 namespace Quotient {
9 
10 class QUOTIENT_API StateEvent : public RoomEvent {
11 public:
12  QUO_BASE_EVENT(StateEvent, RoomEvent, "json.contains('state_key')")
13 
14  static bool isValid(const QJsonObject& fullJson)
15  {
16  return fullJson.contains(StateKeyKey);
17  }
18 
19  //! \brief Static setting of whether a given even type uses state keys
20  //!
21  //! Most event types don't use a state key; overriding this to `true`
22  //! for a given type changes the calls across Quotient to include state key
23  //! in their signatures; otherwise, state key is still accessible but
24  //! constructors and calls in, e.g., RoomStateView don't include it.
25  static constexpr auto needsStateKey = false;
26 
27  explicit StateEvent(event_type_t type, const QString& stateKey = {},
28  const QJsonObject& contentJson = {});
29 
30  //! Make a minimal correct Matrix state event JSON
31  static QJsonObject basicJson(const QString& matrixTypeId,
32  const QString& stateKey = {},
33  const QJsonObject& contentJson = {})
34  {
35  return { { TypeKey, matrixTypeId },
36  { StateKeyKey, stateKey },
37  { ContentKey, contentJson } };
38  }
39 
40  QString replacedState() const;
41  virtual bool repeatsState() const;
42 
43 protected:
44  explicit StateEvent(const QJsonObject& json);
45  void dumpTo(QDebug dbg) const override;
46 };
47 using StateEventPtr = event_ptr_tt<StateEvent>;
48 using StateEvents = EventsArray<StateEvent>;
49 
50 /**
51  * A combination of event type and state key uniquely identifies a piece
52  * of state in Matrix.
53  * \sa
54  * https://matrix.org/docs/spec/client_server/unstable.html#types-of-room-events
55  */
56 using StateEventKey = std::pair<QString, QString>;
57 
58 template <typename EventT, typename ContentT>
59 class EventTemplate<EventT, StateEvent, ContentT>
60  : public StateEvent {
61 public:
62  using content_type = ContentT;
63 
64  struct Prev {
65  explicit Prev() = default;
66  explicit Prev(const QJsonObject& unsignedJson)
67  : senderId(fromJson<QString>(unsignedJson["prev_sender"_ls]))
68  , content(fromJson<std::optional<ContentT>>(unsignedJson[PrevContentKey]))
69  {}
70 
71  QString senderId;
72  std::optional<ContentT> content;
73  };
74 
75  explicit EventTemplate(const QJsonObject& fullJson)
76  : StateEvent(fullJson)
77  , _content(fromJson<ContentT>(Event::contentJson()))
78  , _prev(unsignedJson())
79  {}
80  template <typename... ContentParamTs>
81  explicit EventTemplate(const QString& stateKey,
82  ContentParamTs&&... contentParams)
83  : StateEvent(EventT::TypeId, stateKey)
84  , _content { std::forward<ContentParamTs>(contentParams)... }
85  {
86  editJson().insert(ContentKey, toJson(_content));
87  }
88 
89  const ContentT& content() const { return _content; }
90 
91  template <typename VisitorT>
92  void editContent(VisitorT&& visitor)
93  {
94  visitor(_content);
95  editJson()[ContentKey] = toJson(_content);
96  }
97  const std::optional<ContentT>& prevContent() const { return _prev.content; }
98  QString prevSenderId() const { return _prev.senderId; }
99 
100 private:
101  ContentT _content;
102  Prev _prev;
103 };
104 
105 template <typename EventT, typename ContentT>
106 class KeyedStateEventBase
107  : public EventTemplate<EventT, StateEvent, ContentT> {
108 public:
109  static constexpr auto needsStateKey = true;
110 
111  using EventTemplate<EventT, StateEvent, ContentT>::EventTemplate;
112 };
113 
114 template <typename EvT>
115 concept Keyed_State_Event = EvT::needsStateKey;
116 
117 template <typename EventT, typename ContentT>
118 class KeylessStateEventBase
119  : public EventTemplate<EventT, StateEvent, ContentT> {
120 private:
121  using base_type = EventTemplate<EventT, StateEvent, ContentT>;
122 
123 public:
124  template <typename... ContentParamTs>
125  explicit KeylessStateEventBase(ContentParamTs&&... contentParams)
126  : base_type(QString(), std::forward<ContentParamTs>(contentParams)...)
127  {}
128 
129 protected:
130  explicit KeylessStateEventBase(const QJsonObject& fullJson)
131  : base_type(fullJson)
132  {}
133 };
134 
135 template <typename EvT>
136 concept Keyless_State_Event = !EvT::needsStateKey;
137 
138 } // namespace Quotient
139 Q_DECLARE_METATYPE(Quotient::StateEvent*)
140 Q_DECLARE_METATYPE(const Quotient::StateEvent*)
141 
142 // https://stackoverflow.com/questions/68320024/why-did-the-c-standards-committee-not-include-stdhash-for-pair-and-tuple
143 template <>
144 struct std::hash<Quotient::StateEventKey> {
145  size_t operator()(const Quotient::StateEventKey& k) const
146  {
147  return qHash(k, QHashSeed::globalSeed());
148  }
149 };