aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/connection.cpp37
-rw-r--r--lib/connection.h16
-rw-r--r--lib/room.cpp64
-rw-r--r--lib/room.h1
4 files changed, 91 insertions, 27 deletions
diff --git a/lib/connection.cpp b/lib/connection.cpp
index 4c0fe6b8..998282d3 100644
--- a/lib/connection.cpp
+++ b/lib/connection.cpp
@@ -83,6 +83,8 @@ class Connection::Private
// separately so we should, e.g., keep objects for Invite and
// Leave state of the same room.
QHash<QPair<QString, bool>, Room*> roomMap;
+ // Mapping from aliases to room ids, as per the last sync
+ QHash<QString, QString> roomAliasMap;
QVector<QString> roomIdsToForget;
QVector<Room*> firstTimeRooms;
QVector<QString> pendingStateRoomIds;
@@ -802,6 +804,41 @@ Room* Connection::room(const QString& roomId, JoinStates states) const
return nullptr;
}
+Room* Connection::roomByAlias(const QString& roomAlias, JoinStates states) const
+{
+ const auto id = d->roomAliasMap.value(roomAlias);
+ if (!id.isEmpty())
+ return room(id, states);
+ qCWarning(MAIN) << "Room for alias" << roomAlias
+ << "is not found under account" << userId();
+ return nullptr;
+}
+
+void Connection::updateRoomAliases(const QString& roomId,
+ const QStringList& previousRoomAliases,
+ const QStringList& roomAliases)
+{
+ for (const auto& a: previousRoomAliases)
+ if (d->roomAliasMap.remove(a) == 0)
+ qCWarning(MAIN) << "Alias" << a << "is not found (already deleted?)";
+
+ for (const auto& a: roomAliases)
+ {
+ auto& mappedId = d->roomAliasMap[a];
+ if (!mappedId.isEmpty())
+ {
+ if (mappedId == roomId)
+ qCDebug(MAIN) << "Alias" << a << "is already mapped to room"
+ << roomId;
+ else
+ qCWarning(MAIN) << "Alias" << a
+ << "will be force-remapped from room"
+ << mappedId << "to" << roomId;
+ }
+ mappedId = roomId;
+ }
+}
+
Room* Connection::invitation(const QString& roomId) const
{
return d->roomMap.value({roomId, true}, nullptr);
diff --git a/lib/connection.h b/lib/connection.h
index 1a81c29e..b22d63da 100644
--- a/lib/connection.h
+++ b/lib/connection.h
@@ -231,8 +231,8 @@ namespace QMatrixClient
*/
void addToIgnoredUsers(const User* user);
- /** Remove the user from the ignore list
- * Similar to adding, the change signal is emitted synchronously.
+ /** Remove the user from the ignore list */
+ /** Similar to adding, the change signal is emitted synchronously.
*
* \sa ignoredUsersListChanged
*/
@@ -242,8 +242,18 @@ namespace QMatrixClient
QMap<QString, User*> users() const;
QUrl homeserver() const;
+ /** Find a room by its id and a mask of applicable states */
Q_INVOKABLE Room* room(const QString& roomId,
- JoinStates states = JoinState::Invite|JoinState::Join) const;
+ JoinStates states = JoinState::Invite|JoinState::Join) const;
+ /** Find a room by its alias and a mask of applicable states */
+ Q_INVOKABLE Room* roomByAlias(const QString& roomAlias,
+ JoinStates states = JoinState::Invite|JoinState::Join) const;
+ /** Update the internal map of room aliases to IDs */
+ /// This is used for internal bookkeeping of rooms. Do NOT use
+ /// it to try change aliases, use Room::setAliases instead
+ void updateRoomAliases(const QString& roomId,
+ const QStringList& previousRoomAliases,
+ const QStringList& roomAliases);
Q_INVOKABLE Room* invitation(const QString& roomId) const;
Q_INVOKABLE User* user(const QString& userId);
const User* user() const;
diff --git a/lib/room.cpp b/lib/room.cpp
index c6376a26..f9c899cb 100644
--- a/lib/room.cpp
+++ b/lib/room.cpp
@@ -209,6 +209,28 @@ class Room::Private
is<RoomMessageEvent>(*ti);
}
+ template <typename EventArrayT>
+ Changes updateStateFrom(EventArrayT&& events)
+ {
+ Changes changes = NoChange;
+ if (!events.empty())
+ {
+ QElapsedTimer et; et.start();
+ for (auto&& eptr: events)
+ {
+ const auto& evt = *eptr;
+ Q_ASSERT(evt.isStateEvent());
+ // Update baseState afterwards to make sure that the old state
+ // is valid and usable inside processStateEvent
+ changes |= q->processStateEvent(evt);
+ baseState[{evt.matrixType(),evt.stateKey()}] = move(eptr);
+ }
+ if (events.size() > 9 || et.nsecsElapsed() >= profilerMinNsecs())
+ qCDebug(PROFILER) << "*** Room::Private::updateStateFrom():"
+ << events.size() << "event(s)," << et;
+ }
+ return changes;
+ }
Changes addNewMessageEvents(RoomEvents&& events);
void addHistoricalMessageEvents(RoomEvents&& events);
@@ -684,13 +706,7 @@ void Room::Private::getAllMembers()
auto nextIndex = timeline.empty() ? 0 : timeline.back().index() + 1;
connect( allMembersJob, &BaseJob::success, q, [=] {
Q_ASSERT(timeline.empty() || nextIndex <= q->maxTimelineIndex() + 1);
- Changes roomChanges = NoChange;
- for (auto&& e: allMembersJob->chunk())
- {
- const auto& evt = *e;
- baseState[{evt.matrixType(),evt.stateKey()}] = move(e);
- roomChanges |= q->processStateEvent(evt);
- }
+ auto roomChanges = updateStateFrom(allMembersJob->chunk());
// Replay member events that arrived after the point for which
// the full members list was requested.
if (!timeline.empty() )
@@ -1296,21 +1312,8 @@ void Room::updateData(SyncRoomData&& data, bool fromCache)
for (auto&& event: data.accountData)
roomChanges |= processAccountDataEvent(move(event));
- if (!data.state.empty())
- {
- et.restart();
- for (auto&& eptr: data.state)
- {
- const auto& evt = *eptr;
- Q_ASSERT(evt.isStateEvent());
- d->baseState[{evt.matrixType(),evt.stateKey()}] = move(eptr);
- roomChanges |= processStateEvent(evt);
- }
+ roomChanges |= d->updateStateFrom(data.state);
- if (data.state.size() > 9 || et.nsecsElapsed() >= profilerMinNsecs())
- qCDebug(PROFILER) << "*** Room::processStateEvents():"
- << data.state.size() << "event(s)," << et;
- }
if (!data.timeline.empty())
{
et.restart();
@@ -1614,6 +1617,11 @@ void Room::setCanonicalAlias(const QString& newAlias)
d->requestSetState(RoomCanonicalAliasEvent(newAlias));
}
+void Room::setAliases(const QStringList& aliases)
+{
+ d->requestSetState(RoomAliasesEvent(aliases));
+}
+
void Room::setTopic(const QString& newTopic)
{
d->requestSetState(RoomTopicEvent(newTopic));
@@ -2148,8 +2156,12 @@ Room::Changes Room::processStateEvent(const RoomEvent& e)
if (!e.isStateEvent())
return Change::NoChange;
- d->currentState[{e.matrixType(),e.stateKey()}] =
- static_cast<const StateEventBase*>(&e);
+ const auto* oldStateEvent = std::exchange(
+ d->currentState[{e.matrixType(),e.stateKey()}],
+ static_cast<const StateEventBase*>(&e));
+ Q_ASSERT(!oldStateEvent ||
+ (oldStateEvent->matrixType() == e.matrixType() &&
+ oldStateEvent->stateKey() == e.stateKey()));
if (!is<RoomMemberEvent>(e))
qCDebug(EVENTS) << "Room state event:" << e;
@@ -2157,7 +2169,11 @@ Room::Changes Room::processStateEvent(const RoomEvent& e)
, [] (const RoomNameEvent&) {
return NameChange;
}
- , [] (const RoomAliasesEvent&) {
+ , [this,oldStateEvent] (const RoomAliasesEvent& ae) {
+ const auto previousAliases = oldStateEvent
+ ? static_cast<const RoomAliasesEvent*>(oldStateEvent)->aliases()
+ : QStringList();
+ connection()->updateRoomAliases(id(), previousAliases, ae.aliases());
return OtherChange;
}
, [this] (const RoomCanonicalAliasEvent& evt) {
diff --git a/lib/room.h b/lib/room.h
index 197926e7..808c6074 100644
--- a/lib/room.h
+++ b/lib/room.h
@@ -402,6 +402,7 @@ namespace QMatrixClient
void discardMessage(const QString& txnId);
void setName(const QString& newName);
void setCanonicalAlias(const QString& newAlias);
+ void setAliases(const QStringList& aliases);
void setTopic(const QString& newTopic);
void getPreviousContent(int limit = 10);