From e9ace5cbe8a930a8aa3cc81df1a4f73d51c5fa90 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Tue, 5 Feb 2019 19:14:55 +0900 Subject: Connection::createRoom: support passing a room version On the path to address #233. --- lib/connection.cpp | 7 ++++--- lib/connection.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/connection.cpp b/lib/connection.cpp index c582cf94..88fb547f 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -537,7 +537,8 @@ DownloadFileJob* Connection::downloadFile(const QUrl& url, CreateRoomJob* Connection::createRoom(RoomVisibility visibility, const QString& alias, const QString& name, const QString& topic, - QStringList invites, const QString& presetName, bool isDirect, + QStringList invites, const QString& presetName, + const QString& roomVersion, bool isDirect, const QVector& initialState, const QVector& invite3pids, const QJsonObject& creationContent) @@ -546,7 +547,7 @@ CreateRoomJob* Connection::createRoom(RoomVisibility visibility, auto job = callApi( visibility == PublishRoom ? QStringLiteral("public") : QStringLiteral("private"), - alias, name, topic, invites, invite3pids, QString(/*TODO: #233*/), + alias, name, topic, invites, invite3pids, roomVersion, creationContent, initialState, presetName, isDirect); connect(job, &BaseJob::success, this, [this,job] { emit createdRoom(provideRoom(job->roomId(), JoinState::Join)); @@ -648,7 +649,7 @@ CreateRoomJob* Connection::createDirectChat(const QString& userId, const QString& topic, const QString& name) { return createRoom(UnpublishRoom, "", name, topic, {userId}, - "trusted_private_chat", true); + "trusted_private_chat", {}, true); } ForgetRoomJob* Connection::forgetRoom(const QString& id) diff --git a/lib/connection.h b/lib/connection.h index 9e4121f4..9e4c1a26 100644 --- a/lib/connection.h +++ b/lib/connection.h @@ -402,7 +402,7 @@ namespace QMatrixClient CreateRoomJob* createRoom(RoomVisibility visibility, const QString& alias, const QString& name, const QString& topic, QStringList invites, const QString& presetName = {}, - bool isDirect = false, + const QString& roomVersion = {}, bool isDirect = false, const QVector& initialState = {}, const QVector& invite3pids = {}, const QJsonObject& creationContent = {}); -- cgit v1.2.3 From 01230c16ef8b529ec07d429617247ee383e5c2bb Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Fri, 8 Feb 2019 07:18:36 +0900 Subject: RoomCreateEvent Closes #234. --- CMakeLists.txt | 1 + lib/events/roomcreateevent.cpp | 38 +++++++++++++++++++++++++++++++ lib/events/roomcreateevent.h | 51 ++++++++++++++++++++++++++++++++++++++++++ libqmatrixclient.pri | 2 ++ 4 files changed, 92 insertions(+) create mode 100644 lib/events/roomcreateevent.cpp create mode 100644 lib/events/roomcreateevent.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9729811b..c7f1012a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,6 +90,7 @@ set(libqmatrixclient_SRCS lib/events/roomevent.cpp lib/events/stateevent.cpp lib/events/eventcontent.cpp + lib/events/roomcreateevent.cpp lib/events/roommessageevent.cpp lib/events/roommemberevent.cpp lib/events/typingevent.cpp diff --git a/lib/events/roomcreateevent.cpp b/lib/events/roomcreateevent.cpp new file mode 100644 index 00000000..635efb92 --- /dev/null +++ b/lib/events/roomcreateevent.cpp @@ -0,0 +1,38 @@ +/****************************************************************************** +* Copyright (C) 2019 QMatrixClient project +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "roomcreateevent.h" + +using namespace QMatrixClient; + +RoomCreateDetails::RoomCreateDetails(const QJsonObject& json) + : federated(fromJson(json["m.federate"_ls])) + , version(fromJson(json["room_version"_ls])) +{ + const auto predecessorJson = json["predecessor"_ls].toObject(); + if (!predecessorJson.isEmpty()) + { + fromJson(predecessorJson["room_id"_ls], predRoomId); + fromJson(predecessorJson["event_id"_ls], predEventId); + } +} + +std::pair RoomCreateEvent::predecessor() const +{ + return { content().predRoomId, content().predEventId }; +} diff --git a/lib/events/roomcreateevent.h b/lib/events/roomcreateevent.h new file mode 100644 index 00000000..d93668f9 --- /dev/null +++ b/lib/events/roomcreateevent.h @@ -0,0 +1,51 @@ +/****************************************************************************** +* Copyright (C) 2019 QMatrixClient project +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#include "stateevent.h" + +namespace QMatrixClient +{ + class RoomCreateDetails + { + public: + explicit RoomCreateDetails(const QJsonObject& json); + + bool federated; + QString version; + QString predRoomId; + QString predEventId; + }; + + class RoomCreateEvent : public StateEvent + { + public: + DEFINE_EVENT_TYPEID("m.room.create", RoomCreateEvent) + + explicit RoomCreateEvent(const QJsonObject& obj) + : StateEvent(typeId(), obj) + { } + + bool isFederated() const { return content().federated; } + QString version() const { return content().version; } + std::pair predecessor() const; + bool isUpgrade() const { return !content().predRoomId.isEmpty(); } + }; + REGISTER_EVENT_TYPE(RoomCreateEvent) +} diff --git a/libqmatrixclient.pri b/libqmatrixclient.pri index f523f3a2..598a86d6 100644 --- a/libqmatrixclient.pri +++ b/libqmatrixclient.pri @@ -26,6 +26,7 @@ HEADERS += \ $$SRCPATH/events/eventcontent.h \ $$SRCPATH/events/roommessageevent.h \ $$SRCPATH/events/simplestateevents.h \ + $$SRCPATH/events/roomcreateevent.h \ $$SRCPATH/events/roommemberevent.h \ $$SRCPATH/events/roomavatarevent.h \ $$SRCPATH/events/typingevent.h \ @@ -68,6 +69,7 @@ SOURCES += \ $$SRCPATH/events/roomevent.cpp \ $$SRCPATH/events/stateevent.cpp \ $$SRCPATH/events/eventcontent.cpp \ + $$SRCPATH/events/roomcreateevent.cpp \ $$SRCPATH/events/roommessageevent.cpp \ $$SRCPATH/events/roommemberevent.cpp \ $$SRCPATH/events/typingevent.cpp \ -- cgit v1.2.3 From e12fc32b94c3840249676b2e0656c174846f1c6e Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Tue, 12 Feb 2019 22:11:23 +0900 Subject: Connection: load supported room versions A part of #236. --- lib/connection.cpp | 58 +++++++++++++++++++++++++++++++++++++++++++++++++----- lib/connection.h | 8 ++++++++ 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/lib/connection.cpp b/lib/connection.cpp index 2a2d4822..6d1763ee 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -24,6 +24,7 @@ #include "room.h" #include "settings.h" #include "csapi/login.h" +#include "csapi/capabilities.h" #include "csapi/logout.h" #include "csapi/receipts.h" #include "csapi/leaving.h" @@ -92,6 +93,9 @@ class Connection::Private QString userId; int syncLoopTimeout = -1; + GetCapabilitiesJob* capabilitiesJob = nullptr; + GetCapabilitiesJob::Capabilities capabilities; + SyncJob* syncJob = nullptr; bool cacheState = true; @@ -244,6 +248,29 @@ void Connection::connectWithToken(const QString& userId, [=] { d->connectWithToken(userId, accessToken, deviceId); }); } +void Connection::reloadCapabilities() +{ + d->capabilitiesJob = callApi(BackgroundRequest); + connect(d->capabilitiesJob, &BaseJob::finished, this, [this] { + if (d->capabilitiesJob->error() == BaseJob::Success) + d->capabilities = d->capabilitiesJob->capabilities(); + else if (d->capabilitiesJob->error() == BaseJob::IncorrectRequestError) + qCDebug(MAIN) << "Server doesn't support /capabilities"; + + if (d->capabilities.roomVersions.omitted()) + { + qCWarning(MAIN) << "Pinning supported room version to 1"; + d->capabilities.roomVersions = { "1", {{ "1", "stable" }} }; + } else { + qCDebug(MAIN) << "Room versions:" + << defaultRoomVersion() << "is default, full list:" + << availableRoomVersions(); + } + Q_ASSERT(!d->capabilities.roomVersions.omitted()); + emit capabilitiesLoaded(); + }); +} + void Connection::Private::connectWithToken(const QString& user, const QString& accessToken, const QString& deviceId) @@ -256,7 +283,7 @@ void Connection::Private::connectWithToken(const QString& user, << "by user" << userId << "from device" << deviceId; emit q->stateChanged(); emit q->connected(); - + q->reloadCapabilities(); } void Connection::checkAndConnect(const QString& userId, @@ -1259,9 +1286,30 @@ void QMatrixClient::Connection::setLazyLoading(bool newValue) void Connection::getTurnServers() { - auto job = callApi(); - connect( job, &GetTurnServerJob::success, [=] { - emit turnServersChanged(job->data()); - }); + auto job = callApi(); + connect(job, &GetTurnServerJob::success, + this, [=] { emit turnServersChanged(job->data()); }); +} + +QString Connection::defaultRoomVersion() const +{ + Q_ASSERT(!d->capabilities.roomVersions.omitted()); + return d->capabilities.roomVersions->defaultVersion; +} +QStringList Connection::stableRoomVersions() const +{ + Q_ASSERT(!d->capabilities.roomVersions.omitted()); + QStringList l; + const auto& allVersions = d->capabilities.roomVersions->available; + for (auto it = allVersions.begin(); it != allVersions.end(); ++it) + if (it.value() == "stable") + l.push_back(it.key()); + return l; +} + +const QHash& Connection::availableRoomVersions() const +{ + Q_ASSERT(!d->capabilities.roomVersions.omitted()); + return d->capabilities.roomVersions->available; } diff --git a/lib/connection.h b/lib/connection.h index 8c938df2..e5bce52e 100644 --- a/lib/connection.h +++ b/lib/connection.h @@ -102,6 +102,7 @@ namespace QMatrixClient Q_PROPERTY(QString localUserId READ userId NOTIFY stateChanged) Q_PROPERTY(QString deviceId READ deviceId NOTIFY stateChanged) Q_PROPERTY(QByteArray accessToken READ accessToken NOTIFY stateChanged) + Q_PROPERTY(QString defaultRoomVersion READ defaultRoomVersion NOTIFY capabilitiesLoaded) Q_PROPERTY(QUrl homeserver READ homeserver WRITE setHomeserver NOTIFY homeserverChanged) Q_PROPERTY(bool cacheState READ cacheState WRITE setCacheState NOTIFY cacheStateChanged) Q_PROPERTY(bool lazyLoading READ lazyLoading WRITE setLazyLoading NOTIFY lazyLoadingChanged) @@ -257,6 +258,10 @@ namespace QMatrixClient Q_INVOKABLE QString token() const; Q_INVOKABLE void getTurnServers(); + QString defaultRoomVersion() const; + QStringList stableRoomVersions() const; + const QHash& availableRoomVersions() const; + /** * Call this before first sync to load from previously saved file. * @@ -365,6 +370,8 @@ namespace QMatrixClient const QString& deviceId = {}); void connectWithToken(const QString& userId, const QString& accessToken, const QString& deviceId); + /** Explicitly request capabilities from the server */ + void reloadCapabilities(); /** @deprecated Use stopSync() instead */ void disconnectFromServer() { stopSync(); } @@ -501,6 +508,7 @@ namespace QMatrixClient void resolveError(QString error); void homeserverChanged(QUrl baseUrl); + void capabilitiesLoaded(); void connected(); void reconnected(); //< \deprecated Use connected() instead -- cgit v1.2.3 From a8adbc1d3c8ba787321ebd558062a9c12b12324a Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Fri, 15 Feb 2019 11:10:39 +0900 Subject: RoomTombstoneEvent --- CMakeLists.txt | 1 + lib/events/roomtombstoneevent.cpp | 31 +++++++++++++++++++++++++++++ lib/events/roomtombstoneevent.h | 41 +++++++++++++++++++++++++++++++++++++++ libqmatrixclient.pri | 2 ++ 4 files changed, 75 insertions(+) create mode 100644 lib/events/roomtombstoneevent.cpp create mode 100644 lib/events/roomtombstoneevent.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c7f1012a..d2d8c218 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,6 +91,7 @@ set(libqmatrixclient_SRCS lib/events/stateevent.cpp lib/events/eventcontent.cpp lib/events/roomcreateevent.cpp + lib/events/roomtombstoneevent.cpp lib/events/roommessageevent.cpp lib/events/roommemberevent.cpp lib/events/typingevent.cpp diff --git a/lib/events/roomtombstoneevent.cpp b/lib/events/roomtombstoneevent.cpp new file mode 100644 index 00000000..9c3bafd4 --- /dev/null +++ b/lib/events/roomtombstoneevent.cpp @@ -0,0 +1,31 @@ +/****************************************************************************** +* Copyright (C) 2019 QMatrixClient project +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "roomtombstoneevent.h" + +using namespace QMatrixClient; + +QString RoomTombstoneEvent::serverMessage() const +{ + return fromJson(contentJson()["body"_ls]); +} + +QString RoomTombstoneEvent::successorRoomId() const +{ + return fromJson(contentJson()["replacement_room"_ls]); +} diff --git a/lib/events/roomtombstoneevent.h b/lib/events/roomtombstoneevent.h new file mode 100644 index 00000000..c7008ec4 --- /dev/null +++ b/lib/events/roomtombstoneevent.h @@ -0,0 +1,41 @@ +/****************************************************************************** +* Copyright (C) 2019 QMatrixClient project +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#include "stateevent.h" + +namespace QMatrixClient +{ + class RoomTombstoneEvent : public StateEventBase + { + public: + DEFINE_EVENT_TYPEID("m.room.tombstone", RoomTombstoneEvent) + + explicit RoomTombstoneEvent() + : StateEventBase(typeId(), matrixTypeId()) + { } + explicit RoomTombstoneEvent(const QJsonObject& obj) + : StateEventBase(typeId(), obj) + { } + + QString serverMessage() const; + QString successorRoomId() const; + }; + REGISTER_EVENT_TYPE(RoomTombstoneEvent) +} diff --git a/libqmatrixclient.pri b/libqmatrixclient.pri index 598a86d6..be568bd2 100644 --- a/libqmatrixclient.pri +++ b/libqmatrixclient.pri @@ -27,6 +27,7 @@ HEADERS += \ $$SRCPATH/events/roommessageevent.h \ $$SRCPATH/events/simplestateevents.h \ $$SRCPATH/events/roomcreateevent.h \ + $$SRCPATH/events/roomtombstoneevent.h \ $$SRCPATH/events/roommemberevent.h \ $$SRCPATH/events/roomavatarevent.h \ $$SRCPATH/events/typingevent.h \ @@ -70,6 +71,7 @@ SOURCES += \ $$SRCPATH/events/stateevent.cpp \ $$SRCPATH/events/eventcontent.cpp \ $$SRCPATH/events/roomcreateevent.cpp \ + $$SRCPATH/events/roomtombstoneevent.cpp \ $$SRCPATH/events/roommessageevent.cpp \ $$SRCPATH/events/roommemberevent.cpp \ $$SRCPATH/events/typingevent.cpp \ -- cgit v1.2.3 From 6af5e93134065cd97644d2eee43b2852df549553 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Fri, 15 Feb 2019 11:11:47 +0900 Subject: Simplify RoomCreateEvent --- lib/events/roomcreateevent.cpp | 29 ++++++++++++++++++----------- lib/events/roomcreateevent.h | 32 +++++++++++++++----------------- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/lib/events/roomcreateevent.cpp b/lib/events/roomcreateevent.cpp index 635efb92..8fd0f1de 100644 --- a/lib/events/roomcreateevent.cpp +++ b/lib/events/roomcreateevent.cpp @@ -20,19 +20,26 @@ using namespace QMatrixClient; -RoomCreateDetails::RoomCreateDetails(const QJsonObject& json) - : federated(fromJson(json["m.federate"_ls])) - , version(fromJson(json["room_version"_ls])) +bool RoomCreateEvent::isFederated() const { - const auto predecessorJson = json["predecessor"_ls].toObject(); - if (!predecessorJson.isEmpty()) - { - fromJson(predecessorJson["room_id"_ls], predRoomId); - fromJson(predecessorJson["event_id"_ls], predEventId); - } + return fromJson(contentJson()["m.federate"_ls]); } -std::pair RoomCreateEvent::predecessor() const +QString RoomCreateEvent::version() const { - return { content().predRoomId, content().predEventId }; + return fromJson(contentJson()["room_version"_ls]); +} + +RoomCreateEvent::Predecessor RoomCreateEvent::predecessor() const +{ + const auto predJson = contentJson()["predecessor"_ls].toObject(); + return { + fromJson(predJson["room_id"_ls]), + fromJson(predJson["event_id"_ls]) + }; +} + +bool RoomCreateEvent::isUpgrade() const +{ + return contentJson().contains("predecessor"_ls); } diff --git a/lib/events/roomcreateevent.h b/lib/events/roomcreateevent.h index d93668f9..0a8f27cc 100644 --- a/lib/events/roomcreateevent.h +++ b/lib/events/roomcreateevent.h @@ -22,30 +22,28 @@ namespace QMatrixClient { - class RoomCreateDetails - { - public: - explicit RoomCreateDetails(const QJsonObject& json); - - bool federated; - QString version; - QString predRoomId; - QString predEventId; - }; - - class RoomCreateEvent : public StateEvent + class RoomCreateEvent : public StateEventBase { public: DEFINE_EVENT_TYPEID("m.room.create", RoomCreateEvent) + explicit RoomCreateEvent() + : StateEventBase(typeId(), matrixTypeId()) + { } explicit RoomCreateEvent(const QJsonObject& obj) - : StateEvent(typeId(), obj) + : StateEventBase(typeId(), obj) { } - bool isFederated() const { return content().federated; } - QString version() const { return content().version; } - std::pair predecessor() const; - bool isUpgrade() const { return !content().predRoomId.isEmpty(); } + struct Predecessor + { + QString roomId; + QString eventId; + }; + + bool isFederated() const; + QString version() const; + Predecessor predecessor() const; + bool isUpgrade() const; }; REGISTER_EVENT_TYPE(RoomCreateEvent) } -- cgit v1.2.3 From 87018c0a180248df4a2f61665efbfb3af84bbfea Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Fri, 15 Feb 2019 11:44:29 +0900 Subject: Room::baseStateLoaded Mirroring Connection::loadedRoomState but for each single room (will be used as a NOTIFY signal for one-time-set events). --- lib/room.cpp | 6 ++++++ lib/room.h | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/room.cpp b/lib/room.cpp index d806183f..663f6037 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -296,6 +296,12 @@ Room::Room(Connection* connection, QString id, JoinState initialJoinState) // https://marcmutz.wordpress.com/translated-articles/pimp-my-pimpl-%E2%80%94-reloaded/ d->q = this; d->displayname = d->calculateDisplayname(); // Set initial "Empty room" name + connectUntil(connection, &Connection::loadedRoomState, this, + [this] (Room* r) { + if (this == r) + emit baseStateLoaded(); + return this == r; // loadedRoomState fires only once per room + }); qCDebug(MAIN) << "New" << toCString(initialJoinState) << "Room:" << id; } diff --git a/lib/room.h b/lib/room.h index 029f87b7..7e30a671 100644 --- a/lib/room.h +++ b/lib/room.h @@ -416,6 +416,15 @@ namespace QMatrixClient void markAllMessagesAsRead(); signals: + /// Initial set of state events has been loaded + /** + * The initial set is what comes from the initial sync for the room. + * This includes all basic things like RoomCreateEvent, + * RoomNameEvent, a (lazy-loaded, not full) set of RoomMemberEvents + * etc. This is a per-room reflection of Connection::loadedRoomState + * \sa Connection::loadedRoomState + */ + void baseStateLoaded(); void eventsHistoryJobChanged(); void aboutToAddHistoricalMessages(RoomEventsRange events); void aboutToAddNewMessages(RoomEventsRange events); -- cgit v1.2.3 From 173cfceab7da61e85467658a2c320609485b1139 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Fri, 15 Feb 2019 11:45:23 +0900 Subject: Add a FIXME upon the recent failure under Valgrind --- lib/room.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/room.cpp b/lib/room.cpp index 663f6037..60c61f2b 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -1306,6 +1306,8 @@ RoomEvent* Room::Private::addAsPending(RoomEventPtr&& event) event->setTransactionId(connection->generateTxnId()); auto* pEvent = rawPtr(event); emit q->pendingEventAboutToAdd(pEvent); + // FIXME: This sometimes causes a bad read: + // https://travis-ci.org/QMatrixClient/libqmatrixclient/jobs/492156899#L2596 unsyncedEvents.emplace_back(move(event)); emit q->pendingEventAdded(); return pEvent; -- cgit v1.2.3 From f3ec748689db531df787d19bcfe76b0a40665b67 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Fri, 15 Feb 2019 11:49:40 +0900 Subject: Room: version(), predecessorId(), successorId() Use RoomCreateEvent and RoomTombstoneEvent in the backend, covering most of #235. --- lib/room.cpp | 19 ++++++++++++++++++- lib/room.h | 6 ++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/room.cpp b/lib/room.cpp index 60c61f2b..e1625478 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -30,6 +30,8 @@ #include "csapi/rooms.h" #include "csapi/tags.h" #include "events/simplestateevents.h" +#include "events/roomcreateevent.h" +#include "events/roomtombstoneevent.h" #include "events/roomavatarevent.h" #include "events/roommemberevent.h" #include "events/typingevent.h" @@ -315,6 +317,21 @@ const QString& Room::id() const return d->id; } +QString Room::version() const +{ + return d->getCurrentState()->version(); +} + +QString Room::predecessorId() const +{ + return d->getCurrentState()->predecessor().roomId; +} + +QString Room::successorId() const +{ + return d->getCurrentState()->successorRoomId(); +} + const Room::Timeline& Room::messageEvents() const { return d->timeline; @@ -1807,7 +1824,7 @@ RoomEventPtr makeRedacted(const RoomEvent& target, std::vector> keepContentKeysMap { { RoomMemberEvent::typeId(), { QStringLiteral("membership") } } -// , { RoomCreateEvent::typeId(), { QStringLiteral("creator") } } + , { RoomCreateEvent::typeId(), { QStringLiteral("creator") } } // , { RoomJoinRules::typeId(), { QStringLiteral("join_rule") } } // , { RoomPowerLevels::typeId(), // { QStringLiteral("ban"), QStringLiteral("events"), diff --git a/lib/room.h b/lib/room.h index 7e30a671..ef832d1a 100644 --- a/lib/room.h +++ b/lib/room.h @@ -80,6 +80,9 @@ namespace QMatrixClient Q_PROPERTY(Connection* connection READ connection CONSTANT) Q_PROPERTY(User* localUser READ localUser CONSTANT) Q_PROPERTY(QString id READ id CONSTANT) + Q_PROPERTY(QString version READ version NOTIFY baseStateLoaded) + Q_PROPERTY(QString predecessorId READ predecessorId NOTIFY baseStateLoaded) + Q_PROPERTY(QString successorId READ successorId NOTIFY upgraded) Q_PROPERTY(QString name READ name NOTIFY namesChanged) Q_PROPERTY(QStringList aliases READ aliases NOTIFY namesChanged) Q_PROPERTY(QString canonicalAlias READ canonicalAlias NOTIFY namesChanged) @@ -143,6 +146,9 @@ namespace QMatrixClient Connection* connection() const; User* localUser() const; const QString& id() const; + QString version() const; + QString predecessorId() const; + QString successorId() const; QString name() const; QStringList aliases() const; QString canonicalAlias() const; -- cgit v1.2.3 From 0f4368a19e344c8e3d74d97d4c9de171e723a9a1 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Fri, 15 Feb 2019 12:19:38 +0900 Subject: Disallow sending events to rooms that have been upgraded This concludes the mandatory part of #235. --- lib/room.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/room.cpp b/lib/room.cpp index e1625478..6b9702cd 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -252,11 +252,17 @@ class Room::Private const QString& txnId, BaseJob* call = nullptr); template - auto requestSetState(const QString& stateKey, const EvT& event) + SetRoomStateWithKeyJob* requestSetState(const QString& stateKey, + const EvT& event) { - // TODO: Queue up state events sending (see #133). - return connection->callApi( + if (q->successorId().isEmpty()) + { + // TODO: Queue up state events sending (see #133). + return connection->callApi( id, EvT::matrixTypeId(), stateKey, event.contentJson()); + } + qCWarning(MAIN) << q << "has been upgraded, state won't be set"; + return nullptr; } template @@ -1332,7 +1338,11 @@ RoomEvent* Room::Private::addAsPending(RoomEventPtr&& event) QString Room::Private::sendEvent(RoomEventPtr&& event) { - return doSendEvent(addAsPending(std::move(event))); + if (q->successorId().isEmpty()) + return doSendEvent(addAsPending(std::move(event))); + + qCWarning(MAIN) << q << "has been upgraded, event won't be sent"; + return {}; } QString Room::Private::doSendEvent(const RoomEvent* pEvent) -- cgit v1.2.3 From 5ac901775c5ebd39338ae7854d2c3391cf9084fa Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Fri, 15 Feb 2019 12:24:41 +0900 Subject: Room::upgraded() A signal emitted when the room receives a tombstone event from the server. --- lib/room.cpp | 3 +++ lib/room.h | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/lib/room.cpp b/lib/room.cpp index 6b9702cd..af97dc11 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -2160,6 +2160,9 @@ Room::Changes Room::processStateEvent(const RoomEvent& e) emit encryption(); // It can only be done once, so emit it here. return EncryptionOn; } + , [this] (const RoomTombstoneEvent& evt) { + emit upgraded(evt.serverMessage(), evt.successorRoomId()); + } ); } diff --git a/lib/room.h b/lib/room.h index ef832d1a..137b383d 100644 --- a/lib/room.h +++ b/lib/room.h @@ -528,6 +528,10 @@ namespace QMatrixClient void fileTransferCancelled(QString id); void callEvent(Room* room, const RoomEvent* event); + + /// This room has been upgraded and won't receive updates anymore + void upgraded(QString serverMessage, QString successorId); + /// The room is about to be deleted void beforeDestruction(Room*); -- cgit v1.2.3 From ac7d2ad8b0942cc465c0d340f159cb0b343008ab Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Fri, 15 Feb 2019 12:29:02 +0900 Subject: Room::checkVersion() and Room::unstableVersion() Initial (sans power levels checking) implementation of the check that room should be upgraded. Closes most of #236. --- lib/connection.cpp | 9 +++++++++ lib/room.cpp | 17 ++++++++++++++++- lib/room.h | 6 ++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/connection.cpp b/lib/connection.cpp index 6d1763ee..22fa2f15 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -268,6 +268,9 @@ void Connection::reloadCapabilities() } Q_ASSERT(!d->capabilities.roomVersions.omitted()); emit capabilitiesLoaded(); + for (auto* r: d->roomMap) + if (r->joinState() == JoinState::Join && r->successorId().isEmpty()) + r->checkVersion(); }); } @@ -383,8 +386,14 @@ void Connection::onSyncSuccess(SyncData &&data, bool fromCache) { d->pendingStateRoomIds.removeOne(roomData.roomId); r->updateData(std::move(roomData), fromCache); if (d->firstTimeRooms.removeOne(r)) + { emit loadedRoomState(r); + if (!d->capabilities.roomVersions.omitted()) + r->checkVersion(); + // Otherwise, the version will be checked in reloadCapabilities() + } } + // Let UI update itself after updating each room QCoreApplication::processEvents(); } for (auto&& accountEvent: data.takeAccountData()) diff --git a/lib/room.cpp b/lib/room.cpp index af97dc11..580d04b8 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -1604,7 +1604,22 @@ bool isEchoEvent(const RoomEventPtr& le, const PendingEventItem& re) bool Room::supportsCalls() const { - return joinedCount() == 2; + return joinedCount() == 2; +} + +void Room::checkVersion() +{ + const auto defaultVersion = connection()->defaultRoomVersion(); + const auto stableVersions = connection()->stableRoomVersions(); + Q_ASSERT(!defaultVersion.isEmpty() && successorId().isEmpty()); + if (!stableVersions.contains(version())) + { + qCDebug(MAIN) << this << "version is" << version() + << "which the server doesn't count as stable"; + // TODO: m.room.power_levels + qCDebug(MAIN) << "The current user has enough privileges to fix it"; + emit unstableVersion(defaultVersion, stableVersions); + } } void Room::inviteCall(const QString& callId, const int lifetime, diff --git a/lib/room.h b/lib/room.h index 137b383d..246206d4 100644 --- a/lib/room.h +++ b/lib/room.h @@ -377,6 +377,9 @@ namespace QMatrixClient Q_INVOKABLE bool supportsCalls() const; public slots: + /** Check whether the room should be upgraded */ + void checkVersion(); + QString postMessage(const QString& plainText, MessageEventType type); QString postPlainText(const QString& plainText); QString postHtmlMessage(const QString& plainText, @@ -529,6 +532,9 @@ namespace QMatrixClient void callEvent(Room* room, const RoomEvent* event); + /// The room's version is considered unstable; upgrade recommended + void unstableVersion(QString recommendedDefault, + QStringList stableVersions); /// This room has been upgraded and won't receive updates anymore void upgraded(QString serverMessage, QString successorId); -- cgit v1.2.3 From 5460bf4024999b78fb3837ffc14ca818a71dd4dc Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Fri, 15 Feb 2019 15:45:18 +0900 Subject: Use Changes enum properly Don't use distinct items for each type of event; only for repeated/ combinable ones. --- lib/room.cpp | 3 ++- lib/room.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/room.cpp b/lib/room.cpp index 580d04b8..23fb19db 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -2173,10 +2173,11 @@ Room::Changes Room::processStateEvent(const RoomEvent& e) } , [this] (const EncryptionEvent&) { emit encryption(); // It can only be done once, so emit it here. - return EncryptionOn; + return OtherChange; } , [this] (const RoomTombstoneEvent& evt) { emit upgraded(evt.serverMessage(), evt.successorRoomId()); + return OtherChange; } ); } diff --git a/lib/room.h b/lib/room.h index 246206d4..0569a0c0 100644 --- a/lib/room.h +++ b/lib/room.h @@ -128,7 +128,7 @@ namespace QMatrixClient JoinStateChange = 0x20, TagsChange = 0x40, MembersChange = 0x80, - EncryptionOn = 0x100, + /*blank*/ = 0x100, AccountDataChange = 0x200, SummaryChange = 0x400, ReadMarkerChange = 0x800, -- cgit v1.2.3 From 0130d9646af5530180158854dbedc35d7c01fd4f Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Fri, 15 Feb 2019 16:46:53 +0900 Subject: Fix FTBFS --- lib/room.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/room.h b/lib/room.h index 0569a0c0..0636ba17 100644 --- a/lib/room.h +++ b/lib/room.h @@ -128,7 +128,7 @@ namespace QMatrixClient JoinStateChange = 0x20, TagsChange = 0x40, MembersChange = 0x80, - /*blank*/ = 0x100, + /* = 0x100, */ AccountDataChange = 0x200, SummaryChange = 0x400, ReadMarkerChange = 0x800, -- cgit v1.2.3 From 11b1bfe8f3640bfb1e2dd1710624c67aedb4f98b Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Sat, 16 Feb 2019 17:27:39 +0900 Subject: Room::switchVersion() Closes #236. --- lib/room.cpp | 6 ++++++ lib/room.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/lib/room.cpp b/lib/room.cpp index 23fb19db..aa835860 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -29,6 +29,7 @@ #include "csapi/room_send.h" #include "csapi/rooms.h" #include "csapi/tags.h" +#include "csapi/room_upgrades.h" #include "events/simplestateevents.h" #include "events/roomcreateevent.h" #include "events/roomtombstoneevent.h" @@ -791,6 +792,11 @@ void Room::resetHighlightCount() emit highlightCountChanged(this); } +void Room::switchVersion(QString newVersion) +{ + connection()->callApi(id(), newVersion); +} + bool Room::hasAccountData(const QString& type) const { return d->accountData.find(type) != d->accountData.end(); diff --git a/lib/room.h b/lib/room.h index 0636ba17..e09da94c 100644 --- a/lib/room.h +++ b/lib/room.h @@ -424,6 +424,9 @@ namespace QMatrixClient /// Mark all messages in the room as read void markAllMessagesAsRead(); + /// Switch the room's version (aka upgrade) + void switchVersion(QString newVersion); + signals: /// Initial set of state events has been loaded /** -- cgit v1.2.3 From 4e2de22c7d327836d2fe44764f8c7855a51f6206 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Sat, 16 Feb 2019 17:29:15 +0900 Subject: Room::checkVersion(): check power levels This is a flimsy implementation without proper RoomPowerLevelEvent definition, just to enable upgrades without causing noise to each and every user of a room on an unstable version. --- lib/room.cpp | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/room.cpp b/lib/room.cpp index aa835860..3a37053d 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -1622,9 +1622,25 @@ void Room::checkVersion() { qCDebug(MAIN) << this << "version is" << version() << "which the server doesn't count as stable"; - // TODO: m.room.power_levels - qCDebug(MAIN) << "The current user has enough privileges to fix it"; - emit unstableVersion(defaultVersion, stableVersions); + // TODO, #276: m.room.power_levels + if (const auto* plEvt = + d->currentState.value({"m.room.power_levels", ""})) + { + const auto plJson = plEvt->contentJson(); + const auto currentUserLevel = + plJson.value("users"_ls).toObject() + .value(localUser()->id()).toInt( + plJson.value("users_default"_ls).toInt()); + const auto tombstonePowerLevel = + plJson.value("events").toObject() + .value("m.room.tombstone"_ls).toInt( + plJson.value("state_default"_ls).toInt()); + if (currentUserLevel >= tombstonePowerLevel) + { + qCDebug(MAIN) << "The current user has enough privileges to fix it"; + emit unstableVersion(defaultVersion, stableVersions); + } + } } } -- cgit v1.2.3 From 7e9bf3911e0457bf5af21672d4325882584b78ad Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Sat, 16 Feb 2019 20:00:46 +0900 Subject: Room::canSwitchVersions() --- lib/room.cpp | 40 +++++++++++++++++++++++----------------- lib/room.h | 3 +++ 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/lib/room.cpp b/lib/room.cpp index 3a37053d..538c1562 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -573,6 +573,26 @@ void Room::markAllMessagesAsRead() d->markMessagesAsRead(d->timeline.crbegin()); } +bool Room::canSwitchVersions() const +{ + // TODO, #276: m.room.power_levels + const auto* plEvt = + d->currentState.value({"m.room.power_levels", ""}); + if (!plEvt) + return true; + + const auto plJson = plEvt->contentJson(); + const auto currentUserLevel = + plJson.value("users"_ls).toObject() + .value(localUser()->id()).toInt( + plJson.value("users_default"_ls).toInt()); + const auto tombstonePowerLevel = + plJson.value("events").toObject() + .value("m.room.tombstone"_ls).toInt( + plJson.value("state_default"_ls).toInt()); + return currentUserLevel >= tombstonePowerLevel; +} + bool Room::hasUnreadMessages() const { return unreadCount() >= 0; @@ -1622,24 +1642,10 @@ void Room::checkVersion() { qCDebug(MAIN) << this << "version is" << version() << "which the server doesn't count as stable"; - // TODO, #276: m.room.power_levels - if (const auto* plEvt = - d->currentState.value({"m.room.power_levels", ""})) + if (canSwitchVersions()) { - const auto plJson = plEvt->contentJson(); - const auto currentUserLevel = - plJson.value("users"_ls).toObject() - .value(localUser()->id()).toInt( - plJson.value("users_default"_ls).toInt()); - const auto tombstonePowerLevel = - plJson.value("events").toObject() - .value("m.room.tombstone"_ls).toInt( - plJson.value("state_default"_ls).toInt()); - if (currentUserLevel >= tombstonePowerLevel) - { - qCDebug(MAIN) << "The current user has enough privileges to fix it"; - emit unstableVersion(defaultVersion, stableVersions); - } + qCDebug(MAIN) << "The current user has enough privileges to fix it"; + emit unstableVersion(defaultVersion, stableVersions); } } } diff --git a/lib/room.h b/lib/room.h index e09da94c..f12627f3 100644 --- a/lib/room.h +++ b/lib/room.h @@ -424,6 +424,9 @@ namespace QMatrixClient /// Mark all messages in the room as read void markAllMessagesAsRead(); + /// Whether the current user is allowed to upgrade the room + bool canSwitchVersions() const; + /// Switch the room's version (aka upgrade) void switchVersion(QString newVersion); -- cgit v1.2.3 From 73e6bd47f4bafa7e65f8d826d8c6527c59aeb865 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Sat, 16 Feb 2019 20:22:01 +0900 Subject: Room::version(): Fallback an empty version to "1" --- lib/room.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/room.cpp b/lib/room.cpp index 538c1562..14e60f51 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -326,7 +326,8 @@ const QString& Room::id() const QString Room::version() const { - return d->getCurrentState()->version(); + const auto v = d->getCurrentState()->version(); + return v.isEmpty() ? "1" : v; } QString Room::predecessorId() const -- cgit v1.2.3 From ac5daf2ed495a932aba23606f5b3d0dca5aaf676 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Sun, 17 Feb 2019 17:41:47 +0900 Subject: Connection: loadingCapabilities(); sort availableRoomVersions --- lib/connection.cpp | 37 ++++++++++++++++++++++++++++++++++--- lib/connection.h | 41 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 5 deletions(-) diff --git a/lib/connection.cpp b/lib/connection.cpp index 22fa2f15..4c0fe6b8 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -274,6 +274,13 @@ void Connection::reloadCapabilities() }); } +bool Connection::loadingCapabilities() const +{ + // (Ab)use the fact that room versions cannot be omitted after + // the capabilities have been loaded (see reloadCapabilities() above). + return d->capabilities.roomVersions.omitted(); +} + void Connection::Private::connectWithToken(const QString& user, const QString& accessToken, const QString& deviceId) @@ -1300,6 +1307,9 @@ void Connection::getTurnServers() this, [=] { emit turnServersChanged(job->data()); }); } +const QString Connection::SupportedRoomVersion::StableTag = + QStringLiteral("stable"); + QString Connection::defaultRoomVersion() const { Q_ASSERT(!d->capabilities.roomVersions.omitted()); @@ -1312,13 +1322,34 @@ QStringList Connection::stableRoomVersions() const QStringList l; const auto& allVersions = d->capabilities.roomVersions->available; for (auto it = allVersions.begin(); it != allVersions.end(); ++it) - if (it.value() == "stable") + if (it.value() == SupportedRoomVersion::StableTag) l.push_back(it.key()); return l; } -const QHash& Connection::availableRoomVersions() const +inline bool roomVersionLess(const Connection::SupportedRoomVersion& v1, + const Connection::SupportedRoomVersion& v2) +{ + bool ok1 = false, ok2 = false; + const auto vNum1 = v1.id.toFloat(&ok1); + const auto vNum2 = v2.id.toFloat(&ok2); + return ok1 && ok2 ? vNum1 < vNum2 : v1.id < v2.id; +} + +QVector Connection::availableRoomVersions() const { Q_ASSERT(!d->capabilities.roomVersions.omitted()); - return d->capabilities.roomVersions->available; + QVector result; + result.reserve(d->capabilities.roomVersions->available.size()); + for (auto it = d->capabilities.roomVersions->available.begin(); + it != d->capabilities.roomVersions->available.end(); ++it) + result.push_back({ it.key(), it.value() }); + // Put stable versions over unstable; within each group, + // sort numeric versions as numbers, the rest as strings. + const auto mid = std::partition(result.begin(), result.end(), + std::mem_fn(&SupportedRoomVersion::isStable)); + std::sort(result.begin(), mid, roomVersionLess); + std::sort(mid, result.end(), roomVersionLess); + + return result; } diff --git a/lib/connection.h b/lib/connection.h index e5bce52e..1faee255 100644 --- a/lib/connection.h +++ b/lib/connection.h @@ -258,9 +258,43 @@ namespace QMatrixClient Q_INVOKABLE QString token() const; Q_INVOKABLE void getTurnServers(); + struct SupportedRoomVersion + { + QString id; + QString status; + + static const QString StableTag; // "stable", as of CS API 0.5 + bool isStable() const { return status == StableTag; } + + // Pretty-printing + + friend QDebug operator<<(QDebug dbg, + const SupportedRoomVersion& v) + { + QDebugStateSaver _(dbg); + return dbg.nospace() << v.id << '/' << v.status; + } + + friend QDebug operator<<(QDebug dbg, + const QVector& vs) + { + return QtPrivate::printSequentialContainer( + dbg, "", vs); + } + }; + + /// Get the room version recommended by the server + /** Only works after server capabilities have been loaded. + * \sa loadingCapabilities */ QString defaultRoomVersion() const; + /// Get the room version considered stable by the server + /** Only works after server capabilities have been loaded. + * \sa loadingCapabilities */ QStringList stableRoomVersions() const; - const QHash& availableRoomVersions() const; + /// Get all room versions supported by the server + /** Only works after server capabilities have been loaded. + * \sa loadingCapabilities */ + QVector availableRoomVersions() const; /** * Call this before first sync to load from previously saved file. @@ -370,9 +404,12 @@ namespace QMatrixClient const QString& deviceId = {}); void connectWithToken(const QString& userId, const QString& accessToken, const QString& deviceId); - /** Explicitly request capabilities from the server */ + /// Explicitly request capabilities from the server void reloadCapabilities(); + /// Find out if capabilites are still loading from the server + bool loadingCapabilities() const; + /** @deprecated Use stopSync() instead */ void disconnectFromServer() { stopSync(); } void logout(); -- cgit v1.2.3 From 061c6a69fd55696e7dd82854ace9aa67915628d7 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Sun, 17 Feb 2019 17:46:26 +0900 Subject: Room: emit room, not id in upgraded(); add upgradeFailed() --- lib/room.cpp | 19 +++++++++++++++++-- lib/room.h | 4 +++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/lib/room.cpp b/lib/room.cpp index 14e60f51..9c923de7 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -815,7 +815,10 @@ void Room::resetHighlightCount() void Room::switchVersion(QString newVersion) { - connection()->callApi(id(), newVersion); + auto* job = connection()->callApi(id(), newVersion); + connect(job, &BaseJob::failure, this, [this,job] { + emit upgradeFailed(job->errorString()); + }); } bool Room::hasAccountData(const QString& type) const @@ -2205,7 +2208,19 @@ Room::Changes Room::processStateEvent(const RoomEvent& e) return OtherChange; } , [this] (const RoomTombstoneEvent& evt) { - emit upgraded(evt.serverMessage(), evt.successorRoomId()); + const auto newRoomId = evt.successorRoomId(); + if (auto* newRoom = connection()->room(newRoomId)) + emit upgraded(evt.serverMessage(), newRoom); + else + connectUntil(connection(), &Connection::loadedRoomState, this, + [this,newRoomId,serverMsg=evt.serverMessage()] + (Room* newRoom) { + if (newRoom->id() != newRoomId) + return false; + emit upgraded(serverMsg, newRoom); + return true; + }); + return OtherChange; } ); diff --git a/lib/room.h b/lib/room.h index f12627f3..933a8dd9 100644 --- a/lib/room.h +++ b/lib/room.h @@ -542,7 +542,9 @@ namespace QMatrixClient void unstableVersion(QString recommendedDefault, QStringList stableVersions); /// This room has been upgraded and won't receive updates anymore - void upgraded(QString serverMessage, QString successorId); + void upgraded(QString serverMessage, Room* successor); + /// An attempted room upgrade has failed + void upgradeFailed(QString errorMessage); /// The room is about to be deleted void beforeDestruction(Room*); -- cgit v1.2.3 From ad5d44f31b3ab7e582b84ab05161c97cbc7eefc8 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Sun, 17 Feb 2019 18:54:52 +0900 Subject: Room: add isUnstable(); unstableVersion() -> stabilityUpdated() --- lib/room.cpp | 12 +++++++++--- lib/room.h | 8 +++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/room.cpp b/lib/room.cpp index 9c923de7..b13e7873 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -330,6 +330,12 @@ QString Room::version() const return v.isEmpty() ? "1" : v; } +bool Room::isUnstable() const +{ + return !connection()->loadingCapabilities() && + !connection()->stableRoomVersions().contains(version()); +} + QString Room::predecessorId() const { return d->getCurrentState()->predecessor().roomId; @@ -1642,15 +1648,15 @@ void Room::checkVersion() const auto defaultVersion = connection()->defaultRoomVersion(); const auto stableVersions = connection()->stableRoomVersions(); Q_ASSERT(!defaultVersion.isEmpty() && successorId().isEmpty()); + // This method is only called after the base state has been loaded + // or the server capabilities have been loaded. + emit stabilityUpdated(defaultVersion, stableVersions); if (!stableVersions.contains(version())) { qCDebug(MAIN) << this << "version is" << version() << "which the server doesn't count as stable"; if (canSwitchVersions()) - { qCDebug(MAIN) << "The current user has enough privileges to fix it"; - emit unstableVersion(defaultVersion, stableVersions); - } } } diff --git a/lib/room.h b/lib/room.h index 933a8dd9..197926e7 100644 --- a/lib/room.h +++ b/lib/room.h @@ -81,6 +81,7 @@ namespace QMatrixClient Q_PROPERTY(User* localUser READ localUser CONSTANT) Q_PROPERTY(QString id READ id CONSTANT) Q_PROPERTY(QString version READ version NOTIFY baseStateLoaded) + Q_PROPERTY(bool isUnstable READ isUnstable NOTIFY stabilityUpdated) Q_PROPERTY(QString predecessorId READ predecessorId NOTIFY baseStateLoaded) Q_PROPERTY(QString successorId READ successorId NOTIFY upgraded) Q_PROPERTY(QString name READ name NOTIFY namesChanged) @@ -147,6 +148,7 @@ namespace QMatrixClient User* localUser() const; const QString& id() const; QString version() const; + bool isUnstable() const; QString predecessorId() const; QString successorId() const; QString name() const; @@ -538,9 +540,9 @@ namespace QMatrixClient void callEvent(Room* room, const RoomEvent* event); - /// The room's version is considered unstable; upgrade recommended - void unstableVersion(QString recommendedDefault, - QStringList stableVersions); + /// The room's version stability may have changed + void stabilityUpdated(QString recommendedDefault, + QStringList stableVersions); /// This room has been upgraded and won't receive updates anymore void upgraded(QString serverMessage, Room* successor); /// An attempted room upgrade has failed -- cgit v1.2.3 From 9ef28a3b43dc576716ace005e300b43c3af74b9f Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Mon, 18 Feb 2019 07:00:28 +0900 Subject: Room: fix building with MSVC --- lib/room.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/room.cpp b/lib/room.cpp index b13e7873..f6956d82 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -2214,14 +2214,14 @@ Room::Changes Room::processStateEvent(const RoomEvent& e) return OtherChange; } , [this] (const RoomTombstoneEvent& evt) { - const auto newRoomId = evt.successorRoomId(); - if (auto* newRoom = connection()->room(newRoomId)) - emit upgraded(evt.serverMessage(), newRoom); + const auto successorId = evt.successorRoomId(); + if (auto* successor = connection()->room(successorId)) + emit upgraded(evt.serverMessage(), successor); else connectUntil(connection(), &Connection::loadedRoomState, this, - [this,newRoomId,serverMsg=evt.serverMessage()] + [this,successorId,serverMsg=evt.serverMessage()] (Room* newRoom) { - if (newRoom->id() != newRoomId) + if (newRoom->id() != successorId) return false; emit upgraded(serverMsg, newRoom); return true; -- cgit v1.2.3