mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-25 20:48:52 +03:00
Show some spaces in the community sidebar
This commit is contained in:
parent
57a9a1d0e1
commit
12ce7686ce
6 changed files with 341 additions and 106 deletions
321
src/Cache.cpp
321
src/Cache.cpp
|
@ -55,6 +55,10 @@ constexpr auto BATCH_SIZE = 100;
|
|||
//! Format: room_id -> RoomInfo
|
||||
constexpr auto ROOMS_DB("rooms");
|
||||
constexpr auto INVITES_DB("invites");
|
||||
//! maps each room to its parent space (id->id)
|
||||
constexpr auto SPACES_PARENTS_DB("space_parents");
|
||||
//! maps each space to its current children (id->id)
|
||||
constexpr auto SPACES_CHILDREN_DB("space_children");
|
||||
//! Information that must be kept between sync requests.
|
||||
constexpr auto SYNC_STATE_DB("sync_state");
|
||||
//! Read receipts per room/event.
|
||||
|
@ -237,12 +241,14 @@ Cache::setup()
|
|||
env_.open(cacheDirectory_.toStdString().c_str());
|
||||
}
|
||||
|
||||
auto txn = lmdb::txn::begin(env_);
|
||||
syncStateDb_ = lmdb::dbi::open(txn, SYNC_STATE_DB, MDB_CREATE);
|
||||
roomsDb_ = lmdb::dbi::open(txn, ROOMS_DB, MDB_CREATE);
|
||||
invitesDb_ = lmdb::dbi::open(txn, INVITES_DB, MDB_CREATE);
|
||||
readReceiptsDb_ = lmdb::dbi::open(txn, READ_RECEIPTS_DB, MDB_CREATE);
|
||||
notificationsDb_ = lmdb::dbi::open(txn, NOTIFICATIONS_DB, MDB_CREATE);
|
||||
auto txn = lmdb::txn::begin(env_);
|
||||
syncStateDb_ = lmdb::dbi::open(txn, SYNC_STATE_DB, MDB_CREATE);
|
||||
roomsDb_ = lmdb::dbi::open(txn, ROOMS_DB, MDB_CREATE);
|
||||
spacesChildrenDb_ = lmdb::dbi::open(txn, SPACES_CHILDREN_DB, MDB_CREATE | MDB_DUPSORT);
|
||||
spacesParentsDb_ = lmdb::dbi::open(txn, SPACES_PARENTS_DB, MDB_CREATE | MDB_DUPSORT);
|
||||
invitesDb_ = lmdb::dbi::open(txn, INVITES_DB, MDB_CREATE);
|
||||
readReceiptsDb_ = lmdb::dbi::open(txn, READ_RECEIPTS_DB, MDB_CREATE);
|
||||
notificationsDb_ = lmdb::dbi::open(txn, NOTIFICATIONS_DB, MDB_CREATE);
|
||||
|
||||
// Device management
|
||||
devicesDb_ = lmdb::dbi::open(txn, DEVICES_DB, MDB_CREATE);
|
||||
|
@ -1194,6 +1200,9 @@ Cache::saveState(const mtx::responses::Sync &res)
|
|||
|
||||
auto userKeyCacheDb = getUserKeysDb(txn);
|
||||
|
||||
std::set<std::string> spaces_with_updates;
|
||||
std::set<std::string> rooms_with_space_updates;
|
||||
|
||||
// Save joined rooms
|
||||
for (const auto &room : res.rooms.join) {
|
||||
auto statesdb = getStatesDb(txn, room.first);
|
||||
|
@ -1212,6 +1221,41 @@ Cache::saveState(const mtx::responses::Sync &res)
|
|||
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);
|
||||
|
||||
if (updatedInfo.is_space) {
|
||||
bool space_updates = false;
|
||||
for (const auto &e : room.second.state.events)
|
||||
if (std::holds_alternative<StateEvent<state::space::Child>>(e) ||
|
||||
std::holds_alternative<StateEvent<state::PowerLevels>>(e))
|
||||
space_updates = true;
|
||||
for (const auto &e : room.second.timeline.events)
|
||||
if (std::holds_alternative<StateEvent<state::space::Child>>(e) ||
|
||||
std::holds_alternative<StateEvent<state::PowerLevels>>(e))
|
||||
space_updates = true;
|
||||
|
||||
if (space_updates)
|
||||
spaces_with_updates.insert(room.first);
|
||||
}
|
||||
|
||||
{
|
||||
bool room_has_space_update = false;
|
||||
for (const auto &e : room.second.state.events) {
|
||||
if (auto se = std::get_if<StateEvent<state::space::Parent>>(&e)) {
|
||||
spaces_with_updates.insert(se->state_key);
|
||||
room_has_space_update = true;
|
||||
}
|
||||
}
|
||||
for (const auto &e : room.second.timeline.events) {
|
||||
if (auto se = std::get_if<StateEvent<state::space::Parent>>(&e)) {
|
||||
spaces_with_updates.insert(se->state_key);
|
||||
room_has_space_update = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (room_has_space_update)
|
||||
rooms_with_space_updates.insert(room.first);
|
||||
}
|
||||
|
||||
bool has_new_tags = false;
|
||||
// Process the account_data associated with this room
|
||||
|
@ -1291,6 +1335,8 @@ Cache::saveState(const mtx::responses::Sync &res)
|
|||
|
||||
removeLeftRooms(txn, res.rooms.leave);
|
||||
|
||||
updateSpaces(txn, spaces_with_updates, std::move(rooms_with_space_updates));
|
||||
|
||||
txn.commit();
|
||||
|
||||
std::map<QString, bool> readStatus;
|
||||
|
@ -1339,6 +1385,7 @@ Cache::saveInvites(lmdb::txn &txn, const std::map<std::string, mtx::responses::I
|
|||
updatedInfo.topic = getInviteRoomTopic(txn, statesdb).toStdString();
|
||||
updatedInfo.avatar_url =
|
||||
getInviteRoomAvatarUrl(txn, statesdb, membersdb).toStdString();
|
||||
updatedInfo.is_space = getInviteRoomIsSpace(txn, statesdb);
|
||||
updatedInfo.is_invite = true;
|
||||
|
||||
invitesDb_.put(txn, room.first, json(updatedInfo).dump());
|
||||
|
@ -1427,27 +1474,6 @@ Cache::roomsWithStateUpdates(const mtx::responses::Sync &res)
|
|||
return rooms;
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
Cache::roomsWithTagUpdates(const mtx::responses::Sync &res)
|
||||
{
|
||||
using namespace mtx::events;
|
||||
|
||||
std::vector<std::string> rooms;
|
||||
for (const auto &room : res.rooms.join) {
|
||||
bool hasUpdates = false;
|
||||
for (const auto &evt : room.second.account_data.events) {
|
||||
if (std::holds_alternative<AccountDataEvent<account_data::Tags>>(evt)) {
|
||||
hasUpdates = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasUpdates)
|
||||
rooms.emplace_back(room.first);
|
||||
}
|
||||
|
||||
return rooms;
|
||||
}
|
||||
|
||||
RoomInfo
|
||||
Cache::singleRoomInfo(const std::string &room_id)
|
||||
{
|
||||
|
@ -2337,6 +2363,29 @@ Cache::getRoomVersion(lmdb::txn &txn, lmdb::dbi &statesdb)
|
|||
return QString("1");
|
||||
}
|
||||
|
||||
bool
|
||||
Cache::getRoomIsSpace(lmdb::txn &txn, lmdb::dbi &statesdb)
|
||||
{
|
||||
using namespace mtx::events;
|
||||
using namespace mtx::events::state;
|
||||
|
||||
std::string_view event;
|
||||
bool res = statesdb.get(txn, to_string(mtx::events::EventType::RoomCreate), event);
|
||||
|
||||
if (res) {
|
||||
try {
|
||||
StateEvent<Create> msg = json::parse(event);
|
||||
|
||||
return msg.content.type == mtx::events::state::room_type::space;
|
||||
} catch (const json::exception &e) {
|
||||
nhlog::db()->warn("failed to parse m.room.create event: {}", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
nhlog::db()->warn("m.room.create event is missing room version, assuming version \"1\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<mtx::events::state::CanonicalAlias>
|
||||
Cache::getRoomAliases(const std::string &roomid)
|
||||
{
|
||||
|
@ -2464,6 +2513,27 @@ Cache::getInviteRoomTopic(lmdb::txn &txn, lmdb::dbi &db)
|
|||
return QString();
|
||||
}
|
||||
|
||||
bool
|
||||
Cache::getInviteRoomIsSpace(lmdb::txn &txn, lmdb::dbi &db)
|
||||
{
|
||||
using namespace mtx::events;
|
||||
using namespace mtx::events::state;
|
||||
|
||||
std::string_view event;
|
||||
bool res = db.get(txn, to_string(mtx::events::EventType::RoomCreate), event);
|
||||
|
||||
if (res) {
|
||||
try {
|
||||
StrippedEvent<Create> msg = json::parse(event);
|
||||
return msg.content.type == mtx::events::state::room_type::space;
|
||||
} catch (const json::exception &e) {
|
||||
nhlog::db()->warn("failed to parse m.room.topic event: {}", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
Cache::joinedRooms()
|
||||
{
|
||||
|
@ -2506,42 +2576,6 @@ Cache::getMember(const std::string &room_id, const std::string &user_id)
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<RoomSearchResult>
|
||||
Cache::searchRooms(const std::string &query, std::uint8_t max_items)
|
||||
{
|
||||
std::multimap<int, std::pair<std::string, RoomInfo>> items;
|
||||
|
||||
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
|
||||
auto cursor = lmdb::cursor::open(txn, roomsDb_);
|
||||
|
||||
std::string_view room_id, room_data;
|
||||
while (cursor.get(room_id, room_data, MDB_NEXT)) {
|
||||
RoomInfo tmp = json::parse(room_data);
|
||||
|
||||
const int score = utils::levenshtein_distance(
|
||||
query, QString::fromStdString(tmp.name).toLower().toStdString());
|
||||
items.emplace(score, std::make_pair(room_id, tmp));
|
||||
}
|
||||
|
||||
cursor.close();
|
||||
|
||||
auto end = items.begin();
|
||||
|
||||
if (items.size() >= max_items)
|
||||
std::advance(end, max_items);
|
||||
else if (items.size() > 0)
|
||||
std::advance(end, items.size());
|
||||
|
||||
std::vector<RoomSearchResult> results;
|
||||
for (auto it = items.begin(); it != end; it++) {
|
||||
results.push_back(RoomSearchResult{it->second.first, it->second.second});
|
||||
}
|
||||
|
||||
txn.commit();
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
std::vector<RoomMember>
|
||||
Cache::getMembers(const std::string &room_id, std::size_t startIndex, std::size_t len)
|
||||
{
|
||||
|
@ -3203,6 +3237,147 @@ Cache::deleteOldData() noexcept
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Cache::updateSpaces(lmdb::txn &txn,
|
||||
const std::set<std::string> &spaces_with_updates,
|
||||
std::set<std::string> rooms_with_updates)
|
||||
{
|
||||
if (spaces_with_updates.empty() && rooms_with_updates.empty())
|
||||
return;
|
||||
|
||||
for (const auto &space : spaces_with_updates) {
|
||||
// delete old entries
|
||||
{
|
||||
auto cursor = lmdb::cursor::open(txn, spacesChildrenDb_);
|
||||
bool first = true;
|
||||
std::string_view sp = space, space_child = "";
|
||||
|
||||
if (cursor.get(sp, space_child, MDB_SET)) {
|
||||
while (cursor.get(
|
||||
sp, space_child, first ? MDB_FIRST_DUP : MDB_NEXT_DUP)) {
|
||||
first = false;
|
||||
spacesParentsDb_.del(txn, space_child, space);
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
spacesChildrenDb_.del(txn, space);
|
||||
}
|
||||
|
||||
for (const auto &event :
|
||||
getStateEventsWithType<mtx::events::state::space::Child>(txn, space)) {
|
||||
if (event.content.via.has_value() && event.state_key.size() > 3 &&
|
||||
event.state_key.at(0) == '!') {
|
||||
spacesChildrenDb_.put(txn, space, event.state_key);
|
||||
spacesParentsDb_.put(txn, event.state_key, space);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto space_event_type = to_string(mtx::events::EventType::RoomPowerLevels);
|
||||
|
||||
for (const auto &room : rooms_with_updates) {
|
||||
for (const auto &event :
|
||||
getStateEventsWithType<mtx::events::state::space::Parent>(txn, room)) {
|
||||
if (event.content.via.has_value() && event.state_key.size() > 3 &&
|
||||
event.state_key.at(0) == '!') {
|
||||
const std::string &space = event.state_key;
|
||||
|
||||
auto pls =
|
||||
getStateEvent<mtx::events::state::PowerLevels>(txn, space);
|
||||
|
||||
if (!pls)
|
||||
continue;
|
||||
|
||||
if (pls->content.user_level(event.sender) >=
|
||||
pls->content.state_level(space_event_type)) {
|
||||
spacesChildrenDb_.put(txn, space, room);
|
||||
spacesParentsDb_.put(txn, room, space);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QMap<QString, std::optional<RoomInfo>>
|
||||
Cache::spaces()
|
||||
{
|
||||
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
|
||||
|
||||
QMap<QString, std::optional<RoomInfo>> ret;
|
||||
{
|
||||
auto cursor = lmdb::cursor::open(txn, spacesChildrenDb_);
|
||||
bool first = true;
|
||||
std::string_view space_id, space_child;
|
||||
while (cursor.get(space_id, space_child, first ? MDB_FIRST : MDB_NEXT)) {
|
||||
first = false;
|
||||
|
||||
if (!space_child.empty()) {
|
||||
std::string_view room_data;
|
||||
if (roomsDb_.get(txn, space_id, room_data)) {
|
||||
RoomInfo tmp = json::parse(std::move(room_data));
|
||||
ret.insert(
|
||||
QString::fromUtf8(space_id.data(), space_id.size()), tmp);
|
||||
} else {
|
||||
ret.insert(
|
||||
QString::fromUtf8(space_id.data(), space_id.size()),
|
||||
std::nullopt);
|
||||
}
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
Cache::getParentRoomIds(const std::string &room_id)
|
||||
{
|
||||
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
|
||||
|
||||
std::vector<std::string> roomids;
|
||||
{
|
||||
auto cursor = lmdb::cursor::open(txn, spacesParentsDb_);
|
||||
bool first = true;
|
||||
std::string_view sp = room_id, space_parent;
|
||||
if (cursor.get(sp, space_parent, MDB_SET)) {
|
||||
while (cursor.get(sp, space_parent, first ? MDB_FIRST_DUP : MDB_NEXT_DUP)) {
|
||||
first = false;
|
||||
|
||||
if (!space_parent.empty())
|
||||
roomids.emplace_back(space_parent);
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
return roomids;
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
Cache::getChildRoomIds(const std::string &room_id)
|
||||
{
|
||||
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
|
||||
|
||||
std::vector<std::string> roomids;
|
||||
{
|
||||
auto cursor = lmdb::cursor::open(txn, spacesChildrenDb_);
|
||||
bool first = true;
|
||||
std::string_view sp = room_id, space_child;
|
||||
if (cursor.get(sp, space_child, MDB_SET)) {
|
||||
while (cursor.get(sp, space_child, first ? MDB_FIRST_DUP : MDB_NEXT_DUP)) {
|
||||
first = false;
|
||||
|
||||
if (!space_child.empty())
|
||||
roomids.emplace_back(space_child);
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
return roomids;
|
||||
}
|
||||
|
||||
std::optional<mtx::events::collections::RoomAccountDataEvents>
|
||||
Cache::getAccountData(lmdb::txn &txn, mtx::events::EventType type, const std::string &room_id)
|
||||
{
|
||||
|
@ -3884,6 +4059,7 @@ to_json(json &j, const RoomInfo &info)
|
|||
j["avatar_url"] = info.avatar_url;
|
||||
j["version"] = info.version;
|
||||
j["is_invite"] = info.is_invite;
|
||||
j["is_space"] = info.is_space;
|
||||
j["join_rule"] = info.join_rule;
|
||||
j["guest_access"] = info.guest_access;
|
||||
|
||||
|
@ -3903,6 +4079,7 @@ from_json(const json &j, RoomInfo &info)
|
|||
info.version = j.value(
|
||||
"version", QCoreApplication::translate("RoomInfo", "no version stored").toStdString());
|
||||
info.is_invite = j.at("is_invite");
|
||||
info.is_space = j.value("is_space", false);
|
||||
info.join_rule = j.at("join_rule");
|
||||
info.guest_access = j.at("guest_access");
|
||||
|
||||
|
@ -4158,12 +4335,6 @@ getRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb)
|
|||
return instance_->getRoomAvatarUrl(txn, statesdb, membersdb);
|
||||
}
|
||||
|
||||
QString
|
||||
getRoomVersion(lmdb::txn &txn, lmdb::dbi &statesdb)
|
||||
{
|
||||
return instance_->getRoomVersion(txn, statesdb);
|
||||
}
|
||||
|
||||
std::vector<RoomMember>
|
||||
getMembers(const std::string &room_id, std::size_t startIndex, std::size_t len)
|
||||
{
|
||||
|
@ -4305,11 +4476,7 @@ roomsWithStateUpdates(const mtx::responses::Sync &res)
|
|||
{
|
||||
return instance_->roomsWithStateUpdates(res);
|
||||
}
|
||||
std::vector<std::string>
|
||||
roomsWithTagUpdates(const mtx::responses::Sync &res)
|
||||
{
|
||||
return instance_->roomsWithTagUpdates(res);
|
||||
}
|
||||
|
||||
std::map<QString, RoomInfo>
|
||||
getRoomInfo(const std::vector<std::string> &rooms)
|
||||
{
|
||||
|
@ -4329,12 +4496,6 @@ calculateRoomReadStatus()
|
|||
instance_->calculateRoomReadStatus();
|
||||
}
|
||||
|
||||
std::vector<RoomSearchResult>
|
||||
searchRooms(const std::string &query, std::uint8_t max_items)
|
||||
{
|
||||
return instance_->searchRooms(query, max_items);
|
||||
}
|
||||
|
||||
void
|
||||
markSentNotification(const std::string &event_id)
|
||||
{
|
||||
|
|
|
@ -79,9 +79,6 @@ getRoomTopic(lmdb::txn &txn, lmdb::dbi &statesdb);
|
|||
//! Retrieve the room avatar's url if any.
|
||||
QString
|
||||
getRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
|
||||
//! Retrieve the version of the room if any.
|
||||
QString
|
||||
getRoomVersion(lmdb::txn &txn, lmdb::dbi &statesdb);
|
||||
|
||||
//! Retrieve member info from a room.
|
||||
std::vector<RoomMember>
|
||||
|
@ -166,9 +163,6 @@ calculateRoomReadStatus(const std::string &room_id);
|
|||
void
|
||||
calculateRoomReadStatus();
|
||||
|
||||
std::vector<RoomSearchResult>
|
||||
searchRooms(const std::string &query, std::uint8_t max_items = 5);
|
||||
|
||||
void
|
||||
markSentNotification(const std::string &event_id);
|
||||
//! Removes an event from the sent notifications.
|
||||
|
|
|
@ -76,6 +76,8 @@ struct RoomInfo
|
|||
std::string version;
|
||||
//! Whether or not the room is an invite.
|
||||
bool is_invite = false;
|
||||
//! Wheter or not the room is a space
|
||||
bool is_space = false;
|
||||
//! Total number of members in the room.
|
||||
size_t member_count = 0;
|
||||
//! Who can access to the room.
|
||||
|
|
|
@ -72,6 +72,7 @@ public:
|
|||
std::optional<mtx::events::state::CanonicalAlias> getRoomAliases(const std::string &roomid);
|
||||
QHash<QString, RoomInfo> invites();
|
||||
std::optional<RoomInfo> invite(std::string_view roomid);
|
||||
QMap<QString, std::optional<RoomInfo>> spaces();
|
||||
|
||||
//! Calculate & return the name of the room.
|
||||
QString getRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
|
||||
|
@ -84,6 +85,8 @@ public:
|
|||
QString getRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
|
||||
//! Retrieve the version of the room if any.
|
||||
QString getRoomVersion(lmdb::txn &txn, lmdb::dbi &statesdb);
|
||||
//! Retrieve if the room is a space
|
||||
bool getRoomIsSpace(lmdb::txn &txn, lmdb::dbi &statesdb);
|
||||
|
||||
//! Get a specific state event
|
||||
template<typename T>
|
||||
|
@ -146,7 +149,6 @@ public:
|
|||
|
||||
RoomInfo singleRoomInfo(const std::string &room_id);
|
||||
std::vector<std::string> roomsWithStateUpdates(const mtx::responses::Sync &res);
|
||||
std::vector<std::string> roomsWithTagUpdates(const mtx::responses::Sync &res);
|
||||
std::map<QString, RoomInfo> getRoomInfo(const std::vector<std::string> &rooms);
|
||||
|
||||
//! Calculates which the read status of a room.
|
||||
|
@ -154,9 +156,6 @@ public:
|
|||
bool calculateRoomReadStatus(const std::string &room_id);
|
||||
void calculateRoomReadStatus();
|
||||
|
||||
std::vector<RoomSearchResult> searchRooms(const std::string &query,
|
||||
std::uint8_t max_items = 5);
|
||||
|
||||
void markSentNotification(const std::string &event_id);
|
||||
//! Removes an event from the sent notifications.
|
||||
void removeReadNotification(const std::string &event_id);
|
||||
|
@ -222,6 +221,8 @@ public:
|
|||
void deleteOldData() noexcept;
|
||||
//! Retrieve all saved room ids.
|
||||
std::vector<std::string> getRoomIds(lmdb::txn &txn);
|
||||
std::vector<std::string> getParentRoomIds(const std::string &room_id);
|
||||
std::vector<std::string> getChildRoomIds(const std::string &room_id);
|
||||
|
||||
//! Mark a room that uses e2e encryption.
|
||||
void setEncryptedRoom(lmdb::txn &txn, const std::string &room_id);
|
||||
|
@ -327,6 +328,7 @@ private:
|
|||
QString getInviteRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
|
||||
QString getInviteRoomTopic(lmdb::txn &txn, lmdb::dbi &statesdb);
|
||||
QString getInviteRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
|
||||
bool getInviteRoomIsSpace(lmdb::txn &txn, lmdb::dbi &db);
|
||||
|
||||
std::optional<MemberInfo> getMember(const std::string &room_id, const std::string &user_id);
|
||||
|
||||
|
@ -430,20 +432,22 @@ private:
|
|||
|
||||
if (room_id.empty())
|
||||
return std::nullopt;
|
||||
const auto typeStr = to_string(type);
|
||||
|
||||
std::string_view value;
|
||||
if (state_key.empty()) {
|
||||
auto db = getStatesDb(txn, room_id);
|
||||
if (!db.get(txn, to_string(type), value)) {
|
||||
if (!db.get(txn, typeStr, value)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
} else {
|
||||
auto db = getStatesKeyDb(txn, room_id);
|
||||
std::string d = json::object({{"key", state_key}}).dump();
|
||||
std::string_view data = d;
|
||||
auto db = getStatesKeyDb(txn, room_id);
|
||||
std::string d = json::object({{"key", state_key}}).dump();
|
||||
std::string_view data = d;
|
||||
std::string_view typeStrV = typeStr;
|
||||
|
||||
auto cursor = lmdb::cursor::open(txn, db);
|
||||
if (!cursor.get(state_key, data, MDB_GET_BOTH))
|
||||
if (!cursor.get(typeStrV, data, MDB_GET_BOTH))
|
||||
return std::nullopt;
|
||||
|
||||
try {
|
||||
|
@ -463,6 +467,47 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::vector<mtx::events::StateEvent<T>> getStateEventsWithType(lmdb::txn &txn,
|
||||
const std::string &room_id)
|
||||
|
||||
{
|
||||
constexpr auto type = mtx::events::state_content_to_type<T>;
|
||||
static_assert(type != mtx::events::EventType::Unsupported,
|
||||
"Not a supported type in state events.");
|
||||
|
||||
if (room_id.empty())
|
||||
return {};
|
||||
|
||||
std::vector<mtx::events::StateEvent<T>> events;
|
||||
|
||||
{
|
||||
auto db = getStatesKeyDb(txn, room_id);
|
||||
auto eventsDb = getEventsDb(txn, room_id);
|
||||
const auto typeStr = to_string(type);
|
||||
std::string_view typeStrV = typeStr;
|
||||
std::string_view data;
|
||||
std::string_view value;
|
||||
|
||||
auto cursor = lmdb::cursor::open(txn, db);
|
||||
bool first = true;
|
||||
if (cursor.get(typeStrV, data, MDB_SET)) {
|
||||
while (cursor.get(
|
||||
typeStrV, data, first ? MDB_FIRST_DUP : MDB_NEXT_DUP)) {
|
||||
first = false;
|
||||
|
||||
if (eventsDb.get(txn,
|
||||
json::parse(data)["id"].get<std::string>(),
|
||||
value))
|
||||
events.push_back(
|
||||
json::parse(value)
|
||||
.get<mtx::events::StateEvent<T>>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return events;
|
||||
}
|
||||
void saveInvites(lmdb::txn &txn,
|
||||
const std::map<std::string, mtx::responses::InvitedRoom> &rooms);
|
||||
|
||||
|
@ -482,6 +527,10 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void updateSpaces(lmdb::txn &txn,
|
||||
const std::set<std::string> &spaces_with_updates,
|
||||
std::set<std::string> rooms_with_updates);
|
||||
|
||||
lmdb::dbi getPendingReceiptsDb(lmdb::txn &txn)
|
||||
{
|
||||
return lmdb::dbi::open(txn, "pending_receipts", MDB_CREATE);
|
||||
|
@ -548,8 +597,8 @@ private:
|
|||
|
||||
lmdb::dbi getStatesKeyDb(lmdb::txn &txn, const std::string &room_id)
|
||||
{
|
||||
auto db =
|
||||
lmdb::dbi::open(txn, std::string(room_id + "/state_by_key").c_str(), MDB_CREATE);
|
||||
auto db = lmdb::dbi::open(
|
||||
txn, std::string(room_id + "/state_by_key").c_str(), MDB_CREATE | MDB_DUPSORT);
|
||||
lmdb::dbi_set_dupsort(txn, db, compare_state_key);
|
||||
return db;
|
||||
}
|
||||
|
@ -611,6 +660,7 @@ private:
|
|||
lmdb::env env_;
|
||||
lmdb::dbi syncStateDb_;
|
||||
lmdb::dbi roomsDb_;
|
||||
lmdb::dbi spacesChildrenDb_, spacesParentsDb_;
|
||||
lmdb::dbi invitesDb_;
|
||||
lmdb::dbi readReceiptsDb_;
|
||||
lmdb::dbi notificationsDb_;
|
||||
|
|
|
@ -44,8 +44,23 @@ CommunitiesModel::data(const QModelIndex &index, int role) const
|
|||
case CommunitiesModel::Roles::Id:
|
||||
return "";
|
||||
}
|
||||
} else if (index.row() - 1 < tags_.size()) {
|
||||
auto tag = tags_.at(index.row() - 1);
|
||||
} else if (index.row() - 1 < spaceOrder_.size()) {
|
||||
auto id = spaceOrder_.at(index.row() - 1);
|
||||
switch (role) {
|
||||
case CommunitiesModel::Roles::AvatarUrl:
|
||||
return QString::fromStdString(spaces_.at(id).avatar_url);
|
||||
case CommunitiesModel::Roles::DisplayName:
|
||||
case CommunitiesModel::Roles::Tooltip:
|
||||
return QString::fromStdString(spaces_.at(id).name);
|
||||
case CommunitiesModel::Roles::ChildrenHidden:
|
||||
return true;
|
||||
case CommunitiesModel::Roles::Hidden:
|
||||
return hiddentTagIds_.contains("space:" + id);
|
||||
case CommunitiesModel::Roles::Id:
|
||||
return "space:" + id;
|
||||
}
|
||||
} else if (index.row() - 1 < tags_.size() + spaceOrder_.size()) {
|
||||
auto tag = tags_.at(index.row() - 1 - spaceOrder_.size());
|
||||
if (tag == "m.favourite") {
|
||||
switch (role) {
|
||||
case CommunitiesModel::Roles::AvatarUrl:
|
||||
|
@ -78,7 +93,6 @@ CommunitiesModel::data(const QModelIndex &index, int role) const
|
|||
case CommunitiesModel::Roles::AvatarUrl:
|
||||
return QString(":/icons/icons/ui/tag.png");
|
||||
case CommunitiesModel::Roles::DisplayName:
|
||||
return tag.mid(2);
|
||||
case CommunitiesModel::Roles::Tooltip:
|
||||
return tag.mid(2);
|
||||
}
|
||||
|
@ -99,17 +113,27 @@ CommunitiesModel::data(const QModelIndex &index, int role) const
|
|||
void
|
||||
CommunitiesModel::initializeSidebar()
|
||||
{
|
||||
beginResetModel();
|
||||
tags_.clear();
|
||||
spaceOrder_.clear();
|
||||
spaces_.clear();
|
||||
|
||||
std::set<std::string> ts;
|
||||
for (const auto &e : cache::roomInfo()) {
|
||||
for (const auto &t : e.tags) {
|
||||
if (t.find("u.") == 0 || t.find("m." == 0)) {
|
||||
ts.insert(t);
|
||||
std::vector<RoomInfo> tempSpaces;
|
||||
auto infos = cache::roomInfo();
|
||||
for (auto it = infos.begin(); it != infos.end(); it++) {
|
||||
if (it.value().is_space) {
|
||||
spaceOrder_.push_back(it.key());
|
||||
spaces_[it.key()] = it.value();
|
||||
} else {
|
||||
for (const auto &t : it.value().tags) {
|
||||
if (t.find("u.") == 0 || t.find("m." == 0)) {
|
||||
ts.insert(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
beginResetModel();
|
||||
tags_.clear();
|
||||
for (const auto &t : ts)
|
||||
tags_.push_back(QString::fromStdString(t));
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include <mtx/responses/sync.hpp>
|
||||
|
||||
#include "CacheStructs.h"
|
||||
|
||||
class CommunitiesModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -71,4 +73,6 @@ private:
|
|||
QStringList tags_;
|
||||
QString currentTagId_;
|
||||
QStringList hiddentTagIds_;
|
||||
QStringList spaceOrder_;
|
||||
std::map<QString, RoomInfo> spaces_;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue