Save account data and allow hiding events via account data

This commit is contained in:
Nicolas Werner 2020-08-27 21:49:05 +02:00
parent 8d14a058c6
commit c4e4938d35
4 changed files with 107 additions and 32 deletions

View file

@ -341,7 +341,7 @@ if(USE_BUNDLED_MTXCLIENT)
FetchContent_Declare( FetchContent_Declare(
MatrixClient MatrixClient
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
GIT_TAG d8666a3f1a5b709b78ccea2b545d540a8cb502ca GIT_TAG ac680e971d437eb2135ef994dcb58c0bbb5bdf61
) )
FetchContent_MakeAvailable(MatrixClient) FetchContent_MakeAvailable(MatrixClient)
else() else()

View file

@ -146,7 +146,7 @@
"name": "mtxclient", "name": "mtxclient",
"sources": [ "sources": [
{ {
"commit": "d8666a3f1a5b709b78ccea2b545d540a8cb502ca", "commit": "ac680e971d437eb2135ef994dcb58c0bbb5bdf61",
"type": "git", "type": "git",
"url": "https://github.com/Nheko-Reborn/mtxclient.git" "url": "https://github.com/Nheko-Reborn/mtxclient.git"
} }

View file

@ -94,8 +94,10 @@ namespace {
std::unique_ptr<Cache> instance_ = nullptr; std::unique_ptr<Cache> instance_ = nullptr;
} }
static bool bool
isHiddenEvent(mtx::events::collections::TimelineEvents e, const std::string &room_id) Cache::isHiddenEvent(lmdb::txn &txn,
mtx::events::collections::TimelineEvents e,
const std::string &room_id)
{ {
using namespace mtx::events; using namespace mtx::events;
if (auto encryptedEvent = std::get_if<EncryptedEvent<msg::Encrypted>>(&e)) { if (auto encryptedEvent = std::get_if<EncryptedEvent<msg::Encrypted>>(&e)) {
@ -109,13 +111,27 @@ isHiddenEvent(mtx::events::collections::TimelineEvents e, const std::string &roo
e = result.event.value(); e = result.event.value();
} }
static constexpr std::initializer_list<EventType> hiddenEvents = { mtx::events::account_data::nheko_extensions::HiddenEvents hiddenEvents;
hiddenEvents.hidden_event_types = {
EventType::Reaction, EventType::CallCandidates, EventType::Unsupported}; EventType::Reaction, EventType::CallCandidates, EventType::Unsupported};
if (auto temp = getAccountData(txn, mtx::events::EventType::NhekoHiddenEvents, ""))
hiddenEvents = std::move(
std::get<
mtx::events::Event<mtx::events::account_data::nheko_extensions::HiddenEvents>>(
*temp)
.content);
if (auto temp = getAccountData(txn, mtx::events::EventType::NhekoHiddenEvents, room_id))
hiddenEvents = std::move(
std::get<
mtx::events::Event<mtx::events::account_data::nheko_extensions::HiddenEvents>>(
*temp)
.content);
return std::visit( return std::visit(
[](const auto &ev) { [hiddenEvents](const auto &ev) {
return std::any_of(hiddenEvents.begin(), return std::any_of(hiddenEvents.hidden_event_types.begin(),
hiddenEvents.end(), hiddenEvents.hidden_event_types.end(),
[ev](EventType type) { return type == ev.type; }); [ev](EventType type) { return type == ev.type; });
}, },
e); 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_del(txn, roomsDb_, lmdb::val(roomid), nullptr);
lmdb::dbi_drop(txn, getStatesDb(txn, roomid), true); lmdb::dbi_drop(txn, getStatesDb(txn, roomid), true);
lmdb::dbi_drop(txn, getAccountDataDb(txn, roomid), true);
lmdb::dbi_drop(txn, getMembersDb(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); 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 // Save joined rooms
for (const auto &room : res.rooms.join) { for (const auto &room : res.rooms.join) {
auto statesdb = getStatesDb(txn, room.first); auto statesdb = getStatesDb(txn, room.first);
@ -1001,30 +1031,43 @@ Cache::saveState(const mtx::responses::Sync &res)
updatedInfo.version = getRoomVersion(txn, statesdb).toStdString(); updatedInfo.version = getRoomVersion(txn, statesdb).toStdString();
// Process the account_data associated with this room // Process the account_data associated with this room
bool has_new_tags = false; if (!res.account_data.events.empty()) {
for (const auto &evt : room.second.account_data.events) { auto accountDataDb = getAccountDataDb(txn, room.first);
// for now only fetch tag events
if (std::holds_alternative<Event<account_data::Tags>>(evt)) { bool has_new_tags = false;
auto tags_evt = std::get<Event<account_data::Tags>>(evt); for (const auto &evt : room.second.account_data.events) {
has_new_tags = true; std::visit(
for (const auto &tag : tags_evt.content.tags) { [&txn, &accountDataDb](const auto &event) {
updatedInfo.tags.push_back(tag.first); lmdb::dbi_put(txn,
accountDataDb,
lmdb::val(to_string(event.type)),
lmdb::val(json(event).dump()));
},
evt);
// for tag events
if (std::holds_alternative<Event<account_data::Tags>>(evt)) {
auto tags_evt = std::get<Event<account_data::Tags>>(evt);
has_new_tags = true;
for (const auto &tag : tags_evt.content.tags) {
updatedInfo.tags.push_back(tag.first);
}
} }
} }
} if (!has_new_tags) {
if (!has_new_tags) { // retrieve the old tags, they haven't changed
// retrieve the old tags, they haven't changed lmdb::val data;
lmdb::val data; if (lmdb::dbi_get(txn, roomsDb_, lmdb::val(room.first), data)) {
if (lmdb::dbi_get(txn, roomsDb_, lmdb::val(room.first), data)) { try {
try { RoomInfo tmp = json::parse(
RoomInfo tmp = std::string_view(data.data(), data.size()));
json::parse(std::string_view(data.data(), data.size())); updatedInfo.tags = tmp.tags;
updatedInfo.tags = tmp.tags; } catch (const json::exception &e) {
} catch (const json::exception &e) { nhlog::db()->warn(
nhlog::db()->warn( "failed to parse room info: room_id ({}), {}",
"failed to parse room info: room_id ({}), {}", room.first,
room.first, std::string(data.data(), data.size()));
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))); lmdb::dbi_put(txn, evToOrderDb, event_id, lmdb::val(&index, sizeof(index)));
// TODO(Nico): Allow blacklisting more event types in UI // TODO(Nico): Allow blacklisting more event types in UI
if (!isHiddenEvent(e, room_id)) { if (!isHiddenEvent(txn, e, room_id)) {
++msgIndex; ++msgIndex;
lmdb::cursor_put(msgCursor.handle(), lmdb::cursor_put(msgCursor.handle(),
lmdb::val(&msgIndex, sizeof(msgIndex)), 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))); lmdb::dbi_put(txn, evToOrderDb, event_id, lmdb::val(&index, sizeof(index)));
// TODO(Nico): Allow blacklisting more event types in UI // TODO(Nico): Allow blacklisting more event types in UI
if (!isHiddenEvent(e, room_id)) { if (!isHiddenEvent(txn, e, room_id)) {
--msgIndex; --msgIndex;
lmdb::dbi_put( lmdb::dbi_put(
txn, order2msgDb, lmdb::val(&msgIndex, sizeof(msgIndex)), event_id); txn, order2msgDb, lmdb::val(&msgIndex, sizeof(msgIndex)), event_id);
@ -2840,6 +2883,24 @@ Cache::deleteOldData() noexcept
} }
} }
std::optional<mtx::events::collections::RoomAccountDataEvents>
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 bool
Cache::hasEnoughPowerLevel(const std::vector<mtx::events::EventType> &eventTypes, Cache::hasEnoughPowerLevel(const std::vector<mtx::events::EventType> &eventTypes,
const std::string &room_id, const std::string &room_id,

View file

@ -289,6 +289,14 @@ private:
const std::string &room_id, const std::string &room_id,
const mtx::responses::Timeline &res); const mtx::responses::Timeline &res);
//! retrieve a specific event from account data
//! pass empty room_id for global account data
std::optional<mtx::events::collections::RoomAccountDataEvents>
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. //! Remove a room from the cache.
// void removeLeftRoom(lmdb::txn &txn, const std::string &room_id); // void removeLeftRoom(lmdb::txn &txn, const std::string &room_id);
template<class T> template<class T>
@ -498,6 +506,12 @@ private:
return lmdb::dbi::open(txn, std::string(room_id + "/state").c_str(), MDB_CREATE); 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) 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); return lmdb::dbi::open(txn, std::string(room_id + "/members").c_str(), MDB_CREATE);