From 3c950ce26ad0daefac16d106b0e369466ea25b97 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 11 Mar 2023 23:20:21 +0100 Subject: [PATCH] Make via implementation closer to the spec --- src/Utils.cpp | 108 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 82 insertions(+), 26 deletions(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index 63dcdd00..2a0c4673 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -1263,30 +1264,87 @@ utils::roomVias(const std::string &roomid) { std::vector vias; + // for joined rooms { - auto members = cache::getMembers(roomid, 0, 100); + // see https://spec.matrix.org/v1.6/appendices/#routing for the algorithm + + auto members = cache::roomMembers(roomid); if (!members.empty()) { - vias.push_back(http::client()->user_id().hostname()); + auto powerlevels = + cache::client()->getStateEvent(roomid).value_or( + mtx::events::StateEvent{}); + + std::unordered_set users_with_high_pl; + std::set users_with_high_pl_in_room; + // we should pick PL > 50, but imo that is broken, so we just pick users who have admins + // perm + for (const auto &user : powerlevels.content.users) { + if (user.second >= powerlevels.content.events_default && + user.second >= powerlevels.content.state_default) { + users_with_high_pl.insert(user.first); + } + } + + std::unordered_map usercount_by_server; for (const auto &m : members) { - if (vias.size() >= 4) + auto user_id = mtx::identifiers::parse(m); + usercount_by_server[user_id.hostname()] += 1; + + if (users_with_high_pl.count(m)) + users_with_high_pl_in_room.insert(m); + } + + // TODO(Nico): remove acled servers + + // add the highest powerlevel user + auto max_pl_user = std::max_element( + users_with_high_pl_in_room.begin(), + users_with_high_pl_in_room.end(), + [&pl_content = powerlevels.content](const std::string &a, const std::string &b) { + return pl_content.user_level(a) < pl_content.user_level(b); + }); + if (max_pl_user != users_with_high_pl_in_room.end()) { + auto host = + mtx::identifiers::parse(*max_pl_user).hostname(); + vias.push_back(host); + usercount_by_server.erase(host); + } + + // add up to 3 users, by usercount size from that server + std::vector> servers_sorted_by_usercount; + servers_sorted_by_usercount.reserve(usercount_by_server.size()); + for (const auto &[server, count] : usercount_by_server) + servers_sorted_by_usercount.emplace_back(count, server); + + std::sort(servers_sorted_by_usercount.begin(), + servers_sorted_by_usercount.end(), + [](const auto &a, const auto &b) { + if (a.first == b.first) + // same pl, sort lex smaller server first + return a.second < b.second; + + // sort high user count first + return a.first > b.first; + }); + + for (const auto &server : servers_sorted_by_usercount) { + if (vias.size() >= 3) 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); + vias.push_back(server.second); } + + return vias; } } - if (vias.empty()) { + // for invites + { 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) + if (vias.size() >= 3) break; auto user_id = @@ -1296,24 +1354,22 @@ utils::roomVias(const std::string &roomid) if (std::find(begin(vias), end(vias), server) == vias.end()) vias.push_back(server); } + + return vias; } } - 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)); + // for space previews + 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)); + return vias; }