summary refs log tree commit diff
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2022-02-05 08:40:56 +0100
committerNicolas Werner <nicolas.werner@hotmail.de>2022-02-05 08:40:56 +0100
commitb3221b09d6e12cda47a4ebc8443cac43bb71d29c (patch)
tree39b14ca0d156bbef30beda6295f7c63374e1e74c
parentFix avatar url conversion for widgets (diff)
downloadnheko-b3221b09d6e12cda47a4ebc8443cac43bb71d29c.tar.xz
Add /reset-state command
-rw-r--r--man/nheko.1.adoc4
-rw-r--r--src/Cache.cpp38
-rw-r--r--src/Cache_p.h1
-rw-r--r--src/MatrixClient.cpp2
-rw-r--r--src/timeline/InputBar.cpp2
-rw-r--r--src/timeline/TimelineModel.cpp25
-rw-r--r--src/timeline/TimelineModel.h3
7 files changed, 73 insertions, 2 deletions
diff --git a/man/nheko.1.adoc b/man/nheko.1.adoc
index fe3ff3b3..9914ba93 100644
--- a/man/nheko.1.adoc
+++ b/man/nheko.1.adoc
@@ -195,6 +195,10 @@ Inserts `ノ┬─┬ノ ︵ ( \\o°o)\\`
 Removes all but the most recent messages from the currently rendered timeline
 and then refetches it from the server; can be used to fix some cache issues.
 
+*/reset-state*::
+Fetches all the state events in the current room again; can be used to fix some
+cache issues.
+
 */rotate-megolm-session*::
 Rotates the encryption key used to send encrypted messages in a room.
 
diff --git a/src/Cache.cpp b/src/Cache.cpp
index b55d53a6..9f3ada58 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -1461,6 +1461,44 @@ Cache::calculateRoomReadStatus(const std::string &room_id)
 }
 
 void
+Cache::updateState(const std::string &room, const mtx::responses::StateEvents &state)
+{
+    auto txn         = lmdb::txn::begin(env_);
+    auto statesdb    = getStatesDb(txn, room);
+    auto stateskeydb = getStatesKeyDb(txn, room);
+    auto membersdb   = getMembersDb(txn, room);
+    auto eventsDb    = getEventsDb(txn, room);
+
+    saveStateEvents(txn, statesdb, stateskeydb, membersdb, eventsDb, room, state.events);
+
+    RoomInfo updatedInfo;
+    updatedInfo.name       = getRoomName(txn, statesdb, membersdb).toStdString();
+    updatedInfo.topic      = getRoomTopic(txn, statesdb).toStdString();
+    updatedInfo.avatar_url = getRoomAvatarUrl(txn, statesdb, membersdb).toStdString();
+    updatedInfo.version    = getRoomVersion(txn, statesdb).toStdString();
+    updatedInfo.is_space   = getRoomIsSpace(txn, statesdb);
+
+    {
+        std::string_view data;
+        if (roomsDb_.get(txn, room, data)) {
+            try {
+                RoomInfo tmp     = json::parse(std::string_view(data.data(), data.size()));
+                updatedInfo.tags = tmp.tags;
+            } catch (const json::exception &e) {
+                nhlog::db()->warn("failed to parse room info: room_id ({}), {}: {}",
+                                  room,
+                                  std::string(data.data(), data.size()),
+                                  e.what());
+            }
+        }
+    }
+
+    roomsDb_.put(txn, room, json(updatedInfo).dump());
+    updateSpaces(txn, {room}, {room});
+    txn.commit();
+}
+
+void
 Cache::saveState(const mtx::responses::Sync &res)
 {
     using namespace mtx::events;
diff --git a/src/Cache_p.h b/src/Cache_p.h
index 160ba626..8e5fa547 100644
--- a/src/Cache_p.h
+++ b/src/Cache_p.h
@@ -118,6 +118,7 @@ public:
                                                  std::size_t len        = 30);
     size_t memberCount(const std::string &room_id);
 
+    void updateState(const std::string &room, const mtx::responses::StateEvents &state);
     void saveState(const mtx::responses::Sync &res);
     bool isInitialized();
     bool isDatabaseReady() { return databaseReady_ && isInitialized(); }
diff --git a/src/MatrixClient.cpp b/src/MatrixClient.cpp
index 1ef2bd3a..c565176e 100644
--- a/src/MatrixClient.cpp
+++ b/src/MatrixClient.cpp
@@ -20,6 +20,7 @@ Q_DECLARE_METATYPE(mtx::responses::Messages)
 Q_DECLARE_METATYPE(mtx::responses::Notifications)
 Q_DECLARE_METATYPE(mtx::responses::Rooms)
 Q_DECLARE_METATYPE(mtx::responses::Sync)
+Q_DECLARE_METATYPE(mtx::responses::StateEvents)
 Q_DECLARE_METATYPE(mtx::responses::JoinedGroups)
 Q_DECLARE_METATYPE(mtx::responses::GroupProfile)
 
@@ -52,6 +53,7 @@ init()
     qRegisterMetaType<mtx::responses::Notifications>();
     qRegisterMetaType<mtx::responses::Rooms>();
     qRegisterMetaType<mtx::responses::Sync>();
+    qRegisterMetaType<mtx::responses::StateEvents>();
     qRegisterMetaType<mtx::responses::JoinedGroups>();
     qRegisterMetaType<mtx::responses::GroupProfile>();
     qRegisterMetaType<std::string>();
diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp
index 18e224b2..cd7c4e0c 100644
--- a/src/timeline/InputBar.cpp
+++ b/src/timeline/InputBar.cpp
@@ -617,6 +617,8 @@ InputBar::command(const QString &command, QString args)
         message(QStringLiteral("ノ┬─┬ノ ︵ ( \\o°o)\\"));
     } else if (command == QLatin1String("clear-timeline")) {
         room->clearTimeline();
+    } else if (command == QLatin1String("reset-state")) {
+        room->resetState();
     } else if (command == QLatin1String("rotate-megolm-session")) {
         cache::dropOutboundMegolmSession(room->roomId().toStdString());
     } else if (command == QLatin1String("md")) {
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index 6fc10142..719c7be6 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -440,6 +440,11 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
       cache::client(), &Cache::verificationStatusChanged, this, &TimelineModel::trustlevelChanged);
 
     showEventTimer.callOnTimeout(this, &TimelineModel::scrollTimerEvent);
+
+    connect(this, &TimelineModel::newState, this, [this](mtx::responses::StateEvents events_) {
+        cache::client()->updateState(room_id_.toStdString(), events_);
+        this->syncState({std::move(events_.events)});
+    });
 }
 
 QHash<int, QByteArray>
@@ -2170,6 +2175,21 @@ TimelineModel::resetEdit()
     }
 }
 
+void
+TimelineModel::resetState()
+{
+    http::client()->get_state(
+      room_id_.toStdString(),
+      [this](const mtx::responses::StateEvents &events_, mtx::http::RequestErr e) {
+          if (e) {
+              nhlog::net()->error("Failed to retrive current room state: {}", *e);
+              return;
+          }
+
+          emit newState(events_);
+      });
+}
+
 QString
 TimelineModel::roomName() const
 {
@@ -2247,8 +2267,9 @@ TimelineModel::widgetLinks() const
 
     QStringList list;
 
-    auto user  = utils::localUser();
-    auto av    = QUrl::toPercentEncoding(QString::fromStdString(http::client()->mxc_to_download_url(avatarUrl(user).toStdString())));
+    auto user = utils::localUser();
+    auto av   = QUrl::toPercentEncoding(
+      QString::fromStdString(http::client()->mxc_to_download_url(avatarUrl(user).toStdString())));
     auto disp  = QUrl::toPercentEncoding(displayName(user));
     auto theme = UserSettings::instance()->theme();
     if (theme == QStringLiteral("system"))
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index b4267e8d..f6cc1e6b 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -359,6 +359,7 @@ public slots:
     void resetEdit();
     void setDecryptDescription(bool decrypt) { decryptDescription = decrypt; }
     void clearTimeline() { events.clearTimeline(); }
+    void resetState();
     void receivedSessionKey(const std::string &session_key)
     {
         events.receivedSessionKey(session_key);
@@ -401,6 +402,8 @@ signals:
     void lastMessageChanged();
     void notificationsChanged();
 
+    void newState(mtx::responses::StateEvents events);
+
     void newMessageToSend(mtx::events::collections::TimelineEvents event);
     void addPendingMessageToStore(mtx::events::collections::TimelineEvents event);
     void updateFlowEventId(std::string event_id);