libkazv
room-model.hpp
Go to the documentation of this file.
1 /*
2  * This file is part of libkazv.
3  * SPDX-FileCopyrightText: 2021-2023 tusooa <tusooa@kazv.moe>
4  * SPDX-License-Identifier: AGPL-3.0-or-later
5  */
6 
7 
8 #pragma once
9 #include <libkazv-config.hpp>
10 
11 #include <string>
12 #include <variant>
13 #include <immer/flex_vector.hpp>
14 #include <immer/map.hpp>
15 
20 
21 #include <csapi/sync.hpp>
22 #include <event.hpp>
23 
24 #include <crypto.hpp>
25 #include "push-rules-desc.hpp"
26 #include "local-echo.hpp"
27 #include "clientutil.hpp"
28 
29 namespace Kazv
30 {
32  {
33  std::string txnId;
34  immer::map<std::string, immer::map<std::string, Event>> messages;
35  };
36 
37  PendingRoomKeyEvent makePendingRoomKeyEventV0(std::string txnId, Event event, immer::map<std::string, immer::flex_vector<std::string>> devices);
38 
39  struct ReadReceipt
40  {
41  std::string eventId;
43  };
44 
45  template<class Archive>
46  void serialize(Archive &ar, ReadReceipt &r, std::uint32_t const /* version */)
47  {
48  ar & r.eventId & r.timestamp;
49  }
50 
51  bool operator==(const ReadReceipt &a, const ReadReceipt &b);
52  bool operator!=(const ReadReceipt &a, const ReadReceipt &b);
53 
54  struct EventReader
55  {
56  std::string userId;
58  };
59 
60  bool operator==(const EventReader &a, const EventReader &b);
61  bool operator!=(const EventReader &a, const EventReader &b);
62 
64  {
65  immer::flex_vector<Event> stateEvents;
66  };
67 
72  {
73  immer::flex_vector<Event> stateEvents;
74  };
75 
77  {
79  immer::flex_vector<Event> events;
80  std::optional<std::string> prevBatch;
81  std::optional<bool> limited;
82  std::optional<std::string> gapEventId;
83  };
84 
86  {
87  immer::flex_vector<Event> events;
88  };
89 
91  {
93  };
94 
96  {
97  immer::flex_vector<Event> events;
98  };
99 
101  {
103  };
104 
106  {
107  std::string localDraft;
108  };
109 
111  {
112  };
113 
115  {
116  };
117 
119  {
120  immer::flex_vector<std::string> heroIds;
121  };
122 
124  {
126  };
127 
129  {
130  std::string txnId;
131  };
132 
134  {
136  };
137 
139  {
140  std::string txnId;
141  };
142 
144  {
145  std::size_t joinedMemberCount;
146  };
147 
149  {
150  std::size_t invitedMemberCount;
151  };
152 
157  {
160  std::string myUserId;
161  };
162 
165  {
166  std::string myUserId;
167  };
168 
171  {
172  std::string localReadMarker;
173  std::string myUserId;
174  };
175 
176  inline bool operator==(const PendingRoomKeyEvent &a, const PendingRoomKeyEvent &b)
177  {
178  return a.txnId == b.txnId && a.messages == b.messages;
179  }
180 
181  inline bool operator!=(const PendingRoomKeyEvent &a, const PendingRoomKeyEvent &b)
182  {
183  return !(a == b);
184  }
185 
186  inline const double ROOM_TAG_DEFAULT_ORDER = 2;
187 
188  template<class Archive>
189  void serialize(Archive &ar, PendingRoomKeyEvent &e, std::uint32_t const version)
190  {
191  if (version < 1) {
192  // loading an older version where there is only one event
193  std::string txnId;
194  Event event;
195  immer::map<std::string, immer::flex_vector<std::string>> devices;
196  ar & txnId & event & devices;
198  std::move(txnId), std::move(event), std::move(devices));
199  } else {
200  ar & e.txnId & e.messages;
201  }
202  }
203 
214  auto sortKeyForTimelineEvent(Event e) -> std::tuple<Timestamp, std::string>;
215 
216  struct RoomModel
217  {
219  using ReverseEventRelationshipMap = immer::map<
220  std::string /* related event id */,
221  immer::map<std::string /* relation type */, immer::flex_vector<std::string /* relater event id */>>>;
222 
223  std::string roomId;
224  immer::map<KeyOfState, Event> stateEvents;
225  immer::map<KeyOfState, Event> inviteState;
226  // Smaller indices mean earlier events
227  // (oldest) 0 --------> n (latest)
228  immer::flex_vector<std::string> timeline;
229  immer::map<std::string, Event> messages;
230  immer::map<std::string, Event> accountData;
232  std::string paginateBackToken;
234  bool canPaginateBack{true};
235 
236  immer::map<std::string /* eventId */, std::string /* prevBatch */> timelineGaps;
237 
238  immer::map<std::string, Event> ephemeral;
239 
240  std::string localDraft;
241 
242  bool encrypted{false};
248 
249  bool membersFullyLoaded{false};
250  immer::flex_vector<std::string> heroIds;
251 
252  immer::flex_vector<LocalEchoDesc> localEchoes;
253 
254  immer::flex_vector<PendingRoomKeyEvent> pendingRoomKeyEvents;
255 
257 
258  std::size_t joinedMemberCount{0};
259  std::size_t invitedMemberCount{0};
260 
263  std::string localReadMarker;
265  std::size_t localUnreadCount{0};
268  std::size_t localNotificationCount{0};
270  immer::map<std::string /* userId */, ReadReceipt> readReceipts;
273  immer::map<
274  std::string /* eventId */,
275  immer::flex_vector<std::string /* userId */>> eventReadUsers;
276 
279  immer::map<
280  std::string /* sessionId */,
281  immer::flex_vector<std::string /* eventId */>> undecryptedEvents;
282 
283  immer::flex_vector<std::string> unreadNotificationEventIds;
284 
285  immer::flex_vector<std::string> joinedMemberIds() const;
286  immer::flex_vector<std::string> invitedMemberIds() const;
287  immer::flex_vector<std::string> knockedMemberIds() const;
288  immer::flex_vector<std::string> leftMemberIds() const;
289  immer::flex_vector<std::string> bannedMemberIds() const;
290 
294  EventList leftMemberEvents() const;
296  EventList heroMemberEvents() const;
297 
299 
300  bool hasUser(std::string userId) const;
301 
302  std::optional<LocalEchoDesc> getLocalEchoByTxnId(std::string txnId) const;
303  std::optional<PendingRoomKeyEvent> getPendingRoomKeyEventByTxnId(std::string txnId) const;
304 
305  immer::map<std::string, double> tags() const;
306 
307  Event makeAddTagEvent(std::string tagId, std::optional<double> order) const;
308  Event makeRemoveTagEvent(std::string tagId) const;
309 
317  void generateRelationships(EventList newEvents);
318 
320 
327  void addToUndecryptedEvents(EventList newEvents);
328 
330 
331  using Action = std::variant<
352  >;
353 
354  static RoomModel update(RoomModel r, Action a);
355  };
356 
358 
359  inline bool operator==(const RoomModel &a, const RoomModel &b)
360  {
361  return a.roomId == b.roomId
362  && a.stateEvents == b.stateEvents
363  && a.inviteState == b.inviteState
364  && a.timeline == b.timeline
365  && a.messages == b.messages
366  && a.accountData == b.accountData
367  && a.membership == b.membership
370  && a.timelineGaps == b.timelineGaps
371  && a.ephemeral == b.ephemeral
372  && a.localDraft == b.localDraft
373  && a.encrypted == b.encrypted
376  && a.heroIds == b.heroIds
377  && a.localEchoes == b.localEchoes
384  && a.readReceipts == b.readReceipts
388  ;
389  }
390 
392  {
393  std::string roomId;
395  };
396 
398  {
399  immer::map<std::string, RoomModel> rooms;
400 
401  inline auto at(std::string id) const { return rooms.at(id); }
402  inline auto operator[](std::string id) const { return rooms[id]; }
403  inline bool has(std::string id) const { return rooms.find(id); }
404 
405  using Action = std::variant<
407  >;
409  };
410 
412 
413  inline bool operator==(const RoomListModel &a, const RoomListModel &b)
414  {
415  return a.rooms == b.rooms;
416  }
417 
418  template<class Archive>
419  void serialize(Archive &ar, RoomModel &r, std::uint32_t const version)
420  {
421  ar
422  & r.roomId
423  & r.stateEvents
424  & r.inviteState
425 
426  & r.timeline
427  & r.messages
428  & r.accountData
429  & r.membership
431  & r.canPaginateBack
432 
433  & r.timelineGaps
434  & r.ephemeral
435 
436  & r.localDraft
437 
438  & r.encrypted
440 
442  ;
443 
444  if (version >= 1) {
445  ar
446  & r.heroIds
447  ;
448  }
449  if (version >= 2) {
450  ar & r.localEchoes;
451  }
452  if (version >= 3) {
453  ar & r.pendingRoomKeyEvents;
454  }
455  if (version >= 4) {
457  } else { // must be reading from an older version
458  if constexpr (typename Archive::is_loading()) {
460  }
461  }
462  if (version >= 5) {
464  }
465  if (version >= 6) {
466  ar
467  & r.localReadMarker
468  & r.localUnreadCount
470  & r.readReceipts
471  & r.eventReadUsers;
472  }
473  if (version >= 7) {
474  ar & r.undecryptedEvents;
475  } else {
476  if constexpr (typename Archive::is_loading()) {
478  }
479  }
480  if (version >= 8) {
482  }
483  }
484 
485  template<class Archive>
486  void serialize(Archive &ar, RoomListModel &l, std::uint32_t const /*version*/)
487  {
488  ar & l.rooms;
489  }
490 }
491 
492 BOOST_CLASS_VERSION(Kazv::PendingRoomKeyEvent, 1)
493 BOOST_CLASS_VERSION(Kazv::ReadReceipt, 0)
494 BOOST_CLASS_VERSION(Kazv::RoomModel, 8)
495 BOOST_CLASS_VERSION(Kazv::RoomListModel, 0)
Definition: event.hpp:21
Definition: push-rules-desc.hpp:38
Definition: location.hpp:10
bool operator!=(BaseJob a, BaseJob b)
Definition: basejob.cpp:292
RoomModel::Action RoomAction
Definition: room-model.hpp:357
const double ROOM_TAG_DEFAULT_ORDER
Definition: room-model.hpp:186
std::int_fast64_t Timestamp
Definition: event.hpp:18
PendingRoomKeyEvent makePendingRoomKeyEventV0(std::string txnId, Event event, immer::map< std::string, immer::flex_vector< std::string >> devices)
Definition: room-model.cpp:40
auto sortKeyForTimelineEvent(Event e) -> std::tuple< Timestamp, std::string >
Get the sort key for a timeline event.
Definition: room-model.cpp:76
bool operator==(BaseJob a, BaseJob b)
Definition: basejob.cpp:280
RoomMembership
Definition: types.hpp:128
immer::flex_vector< Event > EventList
Definition: types.hpp:107
void serialize(Archive &ar, ClientModel &m, std::uint32_t const version)
Definition: client-model.hpp:582
RoomListModel::Action RoomListAction
Definition: room-model.hpp:411
Definition: room-model.hpp:86
immer::flex_vector< Event > events
Definition: room-model.hpp:87
Definition: room-model.hpp:101
EventList events
Definition: room-model.hpp:102
Definition: room-model.hpp:124
LocalEchoDesc localEcho
Definition: room-model.hpp:125
Update local notifications to include the new events.
Definition: room-model.hpp:157
std::string myUserId
Definition: room-model.hpp:160
EventList newEvents
Definition: room-model.hpp:158
PushRulesDesc pushRulesDesc
Definition: room-model.hpp:159
Definition: room-model.hpp:134
PendingRoomKeyEvent pendingRoomKeyEvent
Definition: room-model.hpp:135
Definition: room-model.hpp:64
immer::flex_vector< Event > stateEvents
Definition: room-model.hpp:65
Definition: room-model.hpp:77
std::optional< std::string > prevBatch
Definition: room-model.hpp:80
std::optional< std::string > gapEventId
Definition: room-model.hpp:82
std::optional< bool > limited
Definition: room-model.hpp:81
immer::flex_vector< Event > events
Events from oldest to latest.
Definition: room-model.hpp:79
Definition: room-model.hpp:96
immer::flex_vector< Event > events
Definition: room-model.hpp:97
Definition: room-model.hpp:91
RoomMembership membership
Definition: room-model.hpp:92
Definition: room-model.hpp:55
std::string userId
Definition: room-model.hpp:56
Timestamp timestamp
Definition: room-model.hpp:57
Describes a local echo.
Definition: local-echo.hpp:19
Definition: room-model.hpp:115
Go from the back of stateEvents to the beginning, adding the event to room state only if the room has...
Definition: room-model.hpp:72
immer::flex_vector< Event > stateEvents
Definition: room-model.hpp:73
Definition: crypto.hpp:27
Definition: room-model.hpp:32
immer::map< std::string, immer::map< std::string, Event > > messages
Definition: room-model.hpp:34
std::string txnId
Definition: room-model.hpp:33
Definition: room-model.hpp:40
Timestamp timestamp
Definition: room-model.hpp:42
std::string eventId
Definition: room-model.hpp:41
Definition: room-model.hpp:129
std::string txnId
Definition: room-model.hpp:130
Definition: room-model.hpp:139
std::string txnId
Definition: room-model.hpp:140
Remove local notifications that are already read.
Definition: room-model.hpp:165
std::string myUserId
Definition: room-model.hpp:166
Definition: room-model.hpp:398
std::variant< UpdateRoomAction > Action
Definition: room-model.hpp:407
auto at(std::string id) const
Definition: room-model.hpp:401
static RoomListModel update(RoomListModel l, Action a)
Definition: room-model.cpp:415
bool has(std::string id) const
Definition: room-model.hpp:403
immer::map< std::string, RoomModel > rooms
Definition: room-model.hpp:399
auto operator[](std::string id) const
Definition: room-model.hpp:402
Definition: room-model.hpp:217
immer::flex_vector< std::string > unreadNotificationEventIds
Definition: room-model.hpp:283
immer::map< KeyOfState, Event > stateEvents
Definition: room-model.hpp:224
EventList invitedMemberEvents() const
Definition: room-model.cpp:503
EventList knockedMemberEvents() const
Definition: room-model.cpp:508
Event makeRemoveTagEvent(std::string tagId) const
Definition: room-model.cpp:643
bool canPaginateBack
whether this room has earlier events to be fetched
Definition: room-model.hpp:234
immer::map< std::string, std::string > timelineGaps
Definition: room-model.hpp:236
immer::map< std::string, Event > ephemeral
Definition: room-model.hpp:238
bool encrypted
Definition: room-model.hpp:242
immer::map< std::string, double > tags() const
Definition: room-model.cpp:602
immer::flex_vector< std::string > timeline
Definition: room-model.hpp:228
std::string paginateBackToken
Definition: room-model.hpp:232
immer::map< std::string, immer::map< std::string, immer::flex_vector< std::string > >> ReverseEventRelationshipMap
Definition: room-model.hpp:221
Event makeAddTagEvent(std::string tagId, std::optional< double > order) const
Definition: room-model.cpp:631
MegOlmSessionRotateDesc sessionRotateDesc() const
Definition: room-model.cpp:543
EventList heroMemberEvents() const
Definition: room-model.cpp:523
void regenerateRelationships()
Definition: room-model.cpp:662
EventList bannedMemberEvents() const
Definition: room-model.cpp:518
immer::map< std::string, Event > messages
Definition: room-model.hpp:229
void generateRelationships(EventList newEvents)
Fill in reverseEventRelationships by gathering the relationships specified in newEvents
Definition: room-model.cpp:650
std::size_t localNotificationCount
The local unread notification count for this room.
Definition: room-model.hpp:268
std::size_t joinedMemberCount
Definition: room-model.hpp:258
void addToUndecryptedEvents(EventList newEvents)
Fill in undecryptedEvents by gathering the session ids specified in newEvents.
Definition: room-model.cpp:669
std::size_t localUnreadCount
The local unread count for this room.
Definition: room-model.hpp:265
std::string localDraft
Definition: room-model.hpp:240
immer::flex_vector< std::string > knockedMemberIds() const
Definition: room-model.cpp:483
immer::map< std::string, immer::flex_vector< std::string > > eventReadUsers
A map from event id to a list of users that has read receipt at that point.
Definition: room-model.hpp:275
EventList leftMemberEvents() const
Definition: room-model.cpp:513
immer::flex_vector< std::string > heroIds
Definition: room-model.hpp:250
std::optional< PendingRoomKeyEvent > getPendingRoomKeyEventByTxnId(std::string txnId) const
Definition: room-model.cpp:581
std::variant< AddStateEventsAction, MaybeAddStateEventsAction, AddToTimelineAction, AddAccountDataAction, ChangeMembershipAction, ChangeInviteStateAction, AddEphemeralAction, SetLocalDraftAction, SetRoomEncryptionAction, MarkMembersFullyLoadedAction, SetHeroIdsAction, AddLocalEchoAction, RemoveLocalEchoAction, AddPendingRoomKeyAction, RemovePendingRoomKeyAction, UpdateJoinedMemberCountAction, UpdateInvitedMemberCountAction, AddLocalNotificationsAction, RemoveReadLocalNotificationsAction, UpdateLocalReadMarkerAction > Action
Definition: room-model.hpp:352
immer::flex_vector< LocalEchoDesc > localEchoes
Definition: room-model.hpp:252
std::optional< LocalEchoDesc > getLocalEchoByTxnId(std::string txnId) const
Definition: room-model.cpp:569
std::string roomId
Definition: room-model.hpp:223
EventList joinedMemberEvents() const
Definition: room-model.cpp:498
bool membersFullyLoaded
Definition: room-model.hpp:249
std::size_t invitedMemberCount
Definition: room-model.hpp:259
immer::flex_vector< std::string > invitedMemberIds() const
Definition: room-model.cpp:478
ReverseEventRelationshipMap reverseEventRelationships
Definition: room-model.hpp:256
bool hasUser(std::string userId) const
Definition: room-model.cpp:556
immer::map< std::string, immer::flex_vector< std::string > > undecryptedEvents
A map from the session id to a list of event ids of events that cannot (yet) be decrypted.
Definition: room-model.hpp:281
immer::flex_vector< std::string > bannedMemberIds() const
Definition: room-model.cpp:493
immer::flex_vector< PendingRoomKeyEvent > pendingRoomKeyEvents
Definition: room-model.hpp:254
immer::map< std::string, Event > accountData
Definition: room-model.hpp:230
void recalculateUndecryptedEvents()
Definition: room-model.cpp:693
immer::map< std::string, ReadReceipt > readReceipts
Read receipts for all users.
Definition: room-model.hpp:270
bool shouldRotateSessionKey
a marker to indicate whether we need to rotate the session key earlier than it expires (e....
Definition: room-model.hpp:247
immer::flex_vector< std::string > joinedMemberIds() const
Definition: room-model.cpp:473
Membership membership
Definition: room-model.hpp:231
std::string localReadMarker
The local read marker for this room.
Definition: room-model.hpp:263
immer::map< KeyOfState, Event > inviteState
Definition: room-model.hpp:225
immer::flex_vector< std::string > leftMemberIds() const
Definition: room-model.cpp:488
static RoomModel update(RoomModel r, Action a)
Definition: room-model.cpp:81
Definition: room-model.hpp:119
immer::flex_vector< std::string > heroIds
Definition: room-model.hpp:120
Definition: room-model.hpp:106
std::string localDraft
Definition: room-model.hpp:107
Definition: room-model.hpp:111
Definition: room-model.hpp:149
std::size_t invitedMemberCount
Definition: room-model.hpp:150
Definition: room-model.hpp:144
std::size_t joinedMemberCount
Definition: room-model.hpp:145
Update the local read marker, removing any read notifications before it.
Definition: room-model.hpp:171
std::string myUserId
Definition: room-model.hpp:173
std::string localReadMarker
Definition: room-model.hpp:172
Definition: room-model.hpp:392
RoomAction roomAction
Definition: room-model.hpp:394
std::string roomId
Definition: room-model.hpp:393