From c4e4938d3586ad1848671e86ab78025e249af399 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Thu, 27 Aug 2020 21:49:05 +0200 Subject: [PATCH] Save account data and allow hiding events via account data --- CMakeLists.txt | 2 +- io.github.NhekoReborn.Nheko.json | 2 +- src/Cache.cpp | 121 +++++++++++++++++++++++-------- src/Cache_p.h | 14 ++++ 4 files changed, 107 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7295cc5..f33dd8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -341,7 +341,7 @@ if(USE_BUNDLED_MTXCLIENT) FetchContent_Declare( MatrixClient GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git - GIT_TAG d8666a3f1a5b709b78ccea2b545d540a8cb502ca + GIT_TAG ac680e971d437eb2135ef994dcb58c0bbb5bdf61 ) FetchContent_MakeAvailable(MatrixClient) else() diff --git a/io.github.NhekoReborn.Nheko.json b/io.github.NhekoReborn.Nheko.json index b11e587..8ff8263 100644 --- a/io.github.NhekoReborn.Nheko.json +++ b/io.github.NhekoReborn.Nheko.json @@ -146,7 +146,7 @@ "name": "mtxclient", "sources": [ { - "commit": "d8666a3f1a5b709b78ccea2b545d540a8cb502ca", + "commit": "ac680e971d437eb2135ef994dcb58c0bbb5bdf61", "type": "git", "url": "https://github.com/Nheko-Reborn/mtxclient.git" } diff --git a/src/Cache.cpp b/src/Cache.cpp index 91cde9e..a518188 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -94,8 +94,10 @@ namespace { std::unique_ptr instance_ = nullptr; } -static bool -isHiddenEvent(mtx::events::collections::TimelineEvents e, const std::string &room_id) +bool +Cache::isHiddenEvent(lmdb::txn &txn, + mtx::events::collections::TimelineEvents e, + const std::string &room_id) { using namespace mtx::events; if (auto encryptedEvent = std::get_if>(&e)) { @@ -109,13 +111,27 @@ isHiddenEvent(mtx::events::collections::TimelineEvents e, const std::string &roo e = result.event.value(); } - static constexpr std::initializer_list hiddenEvents = { + mtx::events::account_data::nheko_extensions::HiddenEvents hiddenEvents; + hiddenEvents.hidden_event_types = { EventType::Reaction, EventType::CallCandidates, EventType::Unsupported}; + if (auto temp = getAccountData(txn, mtx::events::EventType::NhekoHiddenEvents, "")) + hiddenEvents = std::move( + std::get< + mtx::events::Event>( + *temp) + .content); + if (auto temp = getAccountData(txn, mtx::events::EventType::NhekoHiddenEvents, room_id)) + hiddenEvents = std::move( + std::get< + mtx::events::Event>( + *temp) + .content); + return std::visit( - [](const auto &ev) { - return std::any_of(hiddenEvents.begin(), - hiddenEvents.end(), + [hiddenEvents](const auto &ev) { + return std::any_of(hiddenEvents.hidden_event_types.begin(), + hiddenEvents.hidden_event_types.end(), [ev](EventType type) { return type == ev.type; }); }, e); @@ -624,6 +640,7 @@ Cache::removeRoom(lmdb::txn &txn, const std::string &roomid) { lmdb::dbi_del(txn, roomsDb_, lmdb::val(roomid), nullptr); lmdb::dbi_drop(txn, getStatesDb(txn, roomid), true); + lmdb::dbi_drop(txn, getAccountDataDb(txn, roomid), true); lmdb::dbi_drop(txn, getMembersDb(txn, roomid), true); } @@ -982,6 +999,19 @@ Cache::saveState(const mtx::responses::Sync &res) setNextBatchToken(txn, res.next_batch); + if (!res.account_data.events.empty()) { + auto accountDataDb = getAccountDataDb(txn, ""); + for (const auto &ev : res.account_data.events) + std::visit( + [&txn, &accountDataDb](const auto &event) { + lmdb::dbi_put(txn, + accountDataDb, + lmdb::val(to_string(event.type)), + lmdb::val(json(event).dump())); + }, + ev); + } + // Save joined rooms for (const auto &room : res.rooms.join) { auto statesdb = getStatesDb(txn, room.first); @@ -1001,30 +1031,43 @@ Cache::saveState(const mtx::responses::Sync &res) updatedInfo.version = getRoomVersion(txn, statesdb).toStdString(); // Process the account_data associated with this room - bool has_new_tags = false; - for (const auto &evt : room.second.account_data.events) { - // for now only fetch tag events - if (std::holds_alternative>(evt)) { - auto tags_evt = std::get>(evt); - has_new_tags = true; - for (const auto &tag : tags_evt.content.tags) { - updatedInfo.tags.push_back(tag.first); + if (!res.account_data.events.empty()) { + auto accountDataDb = getAccountDataDb(txn, room.first); + + bool has_new_tags = false; + for (const auto &evt : room.second.account_data.events) { + std::visit( + [&txn, &accountDataDb](const auto &event) { + lmdb::dbi_put(txn, + accountDataDb, + lmdb::val(to_string(event.type)), + lmdb::val(json(event).dump())); + }, + evt); + + // for tag events + if (std::holds_alternative>(evt)) { + auto tags_evt = std::get>(evt); + has_new_tags = true; + for (const auto &tag : tags_evt.content.tags) { + updatedInfo.tags.push_back(tag.first); + } } } - } - if (!has_new_tags) { - // retrieve the old tags, they haven't changed - lmdb::val data; - if (lmdb::dbi_get(txn, roomsDb_, lmdb::val(room.first), 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.first, - std::string(data.data(), data.size())); + if (!has_new_tags) { + // retrieve the old tags, they haven't changed + lmdb::val data; + if (lmdb::dbi_get(txn, roomsDb_, lmdb::val(room.first), 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.first, + std::string(data.data(), data.size())); + } } } } @@ -2439,7 +2482,7 @@ Cache::saveTimelineMessages(lmdb::txn &txn, lmdb::dbi_put(txn, evToOrderDb, event_id, lmdb::val(&index, sizeof(index))); // TODO(Nico): Allow blacklisting more event types in UI - if (!isHiddenEvent(e, room_id)) { + if (!isHiddenEvent(txn, e, room_id)) { ++msgIndex; lmdb::cursor_put(msgCursor.handle(), lmdb::val(&msgIndex, sizeof(msgIndex)), @@ -2522,7 +2565,7 @@ Cache::saveOldMessages(const std::string &room_id, const mtx::responses::Message lmdb::dbi_put(txn, evToOrderDb, event_id, lmdb::val(&index, sizeof(index))); // TODO(Nico): Allow blacklisting more event types in UI - if (!isHiddenEvent(e, room_id)) { + if (!isHiddenEvent(txn, e, room_id)) { --msgIndex; lmdb::dbi_put( txn, order2msgDb, lmdb::val(&msgIndex, sizeof(msgIndex)), event_id); @@ -2840,6 +2883,24 @@ Cache::deleteOldData() noexcept } } +std::optional +Cache::getAccountData(lmdb::txn &txn, mtx::events::EventType type, const std::string &room_id) +{ + try { + auto db = getAccountDataDb(txn, room_id); + + lmdb::val data; + if (lmdb::dbi_get(txn, db, lmdb::val(to_string(type)), data)) { + mtx::responses::utils::RoomAccountDataEvents events; + mtx::responses::utils::parse_room_account_data_events( + std::string_view(data.data(), data.size()), events); + return events.front(); + } + } catch (...) { + } + return std::nullopt; +} + bool Cache::hasEnoughPowerLevel(const std::vector &eventTypes, const std::string &room_id, diff --git a/src/Cache_p.h b/src/Cache_p.h index d3ec6ee..c57995a 100644 --- a/src/Cache_p.h +++ b/src/Cache_p.h @@ -289,6 +289,14 @@ private: const std::string &room_id, const mtx::responses::Timeline &res); + //! retrieve a specific event from account data + //! pass empty room_id for global account data + std::optional + getAccountData(lmdb::txn &txn, mtx::events::EventType type, const std::string &room_id); + bool isHiddenEvent(lmdb::txn &txn, + mtx::events::collections::TimelineEvents e, + const std::string &room_id); + //! Remove a room from the cache. // void removeLeftRoom(lmdb::txn &txn, const std::string &room_id); template @@ -498,6 +506,12 @@ private: return lmdb::dbi::open(txn, std::string(room_id + "/state").c_str(), MDB_CREATE); } + lmdb::dbi getAccountDataDb(lmdb::txn &txn, const std::string &room_id) + { + return lmdb::dbi::open( + txn, std::string(room_id + "/account_data").c_str(), MDB_CREATE); + } + lmdb::dbi getMembersDb(lmdb::txn &txn, const std::string &room_id) { return lmdb::dbi::open(txn, std::string(room_id + "/members").c_str(), MDB_CREATE);