From 07bb95fbcdbbb3da9bf1162792e16f8c4e928949 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Tue, 19 Jul 2022 18:57:08 +0200 Subject: [PATCH] Fix crash when creating link to room preview --- src/Cache.cpp | 91 +++++++++++++++++++--------------- src/Utils.cpp | 60 ++++++++++++++++++++++ src/Utils.h | 3 ++ src/timeline/RoomlistModel.cpp | 11 +--- src/timeline/TimelineModel.cpp | 10 ++-- 5 files changed, 119 insertions(+), 56 deletions(-) diff --git a/src/Cache.cpp b/src/Cache.cpp index 79a5ea04..4213e901 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -3006,49 +3006,54 @@ Cache::getMember(const std::string &room_id, const std::string &user_id) std::vector Cache::getMembers(const std::string &room_id, std::size_t startIndex, std::size_t len) { - auto txn = ro_txn(env_); - auto db = getMembersDb(txn, room_id); - auto cursor = lmdb::cursor::open(txn, db); + try { + auto txn = ro_txn(env_); + auto db = getMembersDb(txn, room_id); + auto cursor = lmdb::cursor::open(txn, db); - std::size_t currentIndex = 0; + std::size_t currentIndex = 0; - const auto endIndex = std::min(startIndex + len, db.size(txn)); + const auto endIndex = std::min(startIndex + len, db.size(txn)); - std::vector members; + std::vector members; + + std::string_view user_id, user_data; + while (cursor.get(user_id, user_data, MDB_NEXT)) { + if (currentIndex < startIndex) { + currentIndex += 1; + continue; + } + + if (currentIndex >= endIndex) + break; + + try { + MemberInfo tmp = nlohmann::json::parse(user_data).get(); + members.emplace_back(RoomMember{QString::fromStdString(std::string(user_id)), + QString::fromStdString(tmp.name)}); + } catch (const nlohmann::json::exception &e) { + nhlog::db()->warn("{}", e.what()); + } - std::string_view user_id, user_data; - while (cursor.get(user_id, user_data, MDB_NEXT)) { - if (currentIndex < startIndex) { currentIndex += 1; - continue; } - if (currentIndex >= endIndex) - break; + cursor.close(); - try { - MemberInfo tmp = nlohmann::json::parse(user_data).get(); - members.emplace_back(RoomMember{QString::fromStdString(std::string(user_id)), - QString::fromStdString(tmp.name)}); - } catch (const nlohmann::json::exception &e) { - nhlog::db()->warn("{}", e.what()); - } - - currentIndex += 1; + return members; + } catch (const lmdb::error &e) { + nhlog::db()->error("Failed to retrieve members from db in room {}: {}", room_id, e.what()); + return {}; } - - cursor.close(); - - return members; } std::vector Cache::getMembersFromInvite(const std::string &room_id, std::size_t startIndex, std::size_t len) { - auto txn = ro_txn(env_); - std::vector members; - try { + auto txn = ro_txn(env_); + std::vector members; + auto db = getInviteMembersDb(txn, room_id); auto cursor = lmdb::cursor::open(txn, db); @@ -3079,11 +3084,12 @@ Cache::getMembersFromInvite(const std::string &room_id, std::size_t startIndex, } cursor.close(); - } catch (const lmdb::error &e) { - nhlog::db()->warn("Failed to retrieve members {}", e.what()); - } - return members; + return members; + } catch (const lmdb::error &e) { + nhlog::db()->error("Failed to retrieve members from db in room {}: {}", room_id, e.what()); + return {}; + } } bool @@ -4033,17 +4039,22 @@ Cache::roomMembers(const std::string &room_id) { auto txn = ro_txn(env_); - std::vector members; - std::string_view user_id, unused; + try { + std::vector members; + std::string_view user_id, unused; - auto db = getMembersDb(txn, room_id); + auto db = getMembersDb(txn, room_id); - auto cursor = lmdb::cursor::open(txn, db); - while (cursor.get(user_id, unused, MDB_NEXT)) - members.emplace_back(user_id); - cursor.close(); + auto cursor = lmdb::cursor::open(txn, db); + while (cursor.get(user_id, unused, MDB_NEXT)) + members.emplace_back(user_id); + cursor.close(); - return members; + return members; + } catch (const lmdb::error &e) { + nhlog::db()->error("Failed to retrieve members from db in room {}: {}", room_id, e.what()); + return {}; + } } crypto::Trust diff --git a/src/Utils.cpp b/src/Utils.cpp index b85d7916..ffbaecab 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -881,3 +881,63 @@ utils::markRoomAsDirect(QString roomid, std::vector members) }); }); } + +std::vector +utils::roomVias(const std::string &roomid) +{ + std::vector vias; + + { + auto members = cache::getMembers(roomid, 0, 100); + if (!members.empty()) { + vias.push_back(http::client()->user_id().hostname()); + for (const auto &m : members) { + if (vias.size() >= 4) + break; + + auto user_id = + mtx::identifiers::parse(m.user_id.toStdString()); + + auto server = user_id.hostname(); + if (std::find(begin(vias), end(vias), server) == vias.end()) + vias.push_back(server); + } + } + } + + if (vias.empty()) { + auto members = cache::getMembersFromInvite(roomid, 0, 100); + if (!members.empty()) { + vias.push_back(http::client()->user_id().hostname()); + for (const auto &m : members) { + if (vias.size() >= 4) + break; + + auto user_id = + mtx::identifiers::parse(m.user_id.toStdString()); + + auto server = user_id.hostname(); + if (std::find(begin(vias), end(vias), server) == vias.end()) + vias.push_back(server); + } + } + } + + if (vias.empty()) { + auto parents = cache::client()->getParentRoomIds(roomid); + for (const auto &p : parents) { + auto child = + cache::client()->getStateEvent(p, roomid); + if (child && child->content.via) + vias.insert(vias.end(), child->content.via->begin(), child->content.via->end()); + } + + std::sort(begin(vias), end(vias)); + auto last = std::unique(begin(vias), end(vias)); + vias.erase(last, end(vias)); + + // if (vias.size()> 3) + // vias.erase(begin(vias)+3, end(vias)); + } + return vias; +} diff --git a/src/Utils.h b/src/Utils.h index 96acd993..8f8b9cad 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -311,4 +311,7 @@ removeDirectFromRoom(QString roomid); void markRoomAsDirect(QString roomid, std::vector members); + +std::vector +roomVias(const std::string &roomid); } diff --git a/src/timeline/RoomlistModel.cpp b/src/timeline/RoomlistModel.cpp index 1869d2e0..fe4e7850 100644 --- a/src/timeline/RoomlistModel.cpp +++ b/src/timeline/RoomlistModel.cpp @@ -645,15 +645,8 @@ void RoomlistModel::joinPreview(QString roomid) { if (previewedRooms.contains(roomid)) { - std::vector vias; - auto parents = cache::client()->getParentRoomIds(roomid.toStdString()); - for (const auto &p : parents) { - auto child = cache::client()->getStateEvent( - p, roomid.toStdString()); - if (child && child->content.via) - vias.insert(vias.end(), child->content.via->begin(), child->content.via->end()); - } - ChatPage::instance()->joinRoomVia(roomid.toStdString(), vias, false); + ChatPage::instance()->joinRoomVia( + roomid.toStdString(), utils::roomVias(roomid.toStdString()), false); } } void diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index 5818d9d8..c60940a7 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -1813,16 +1813,12 @@ TimelineModel::getRoomVias(const QString &roomId) { QStringList vias; - vias.push_back(QStringLiteral("via=%1").arg(QString( - QUrl::toPercentEncoding(QString::fromStdString(http::client()->user_id().hostname()))))); - auto members = cache::getMembers(roomId.toStdString(), 0, 100); - for (const auto &m : members) { + for (const auto &m : utils::roomVias(roomId.toStdString())) { if (vias.size() >= 4) break; - auto user_id = mtx::identifiers::parse(m.user_id.toStdString()); - QString server = QStringLiteral("via=%1").arg( - QString(QUrl::toPercentEncoding(QString::fromStdString(user_id.hostname())))); + QString server = + QStringLiteral("via=%1").arg(QString(QUrl::toPercentEncoding(QString::fromStdString(m)))); if (!vias.contains(server)) vias.push_back(server);