Update spaces events automatically in the background

This commit is contained in:
Nicolas Werner 2023-03-14 03:02:54 +01:00
parent 9891b6bffe
commit 234ac79acc
No known key found for this signature in database
GPG key ID: C8D75E610773F2D9
7 changed files with 246 additions and 5 deletions

View file

@ -16,6 +16,7 @@
#include <QStringBuilder>
#include <QTextBoundaryFinder>
#include <QTextDocument>
#include <QTimer>
#include <QWindow>
#include <QXmlStreamReader>
@ -28,11 +29,13 @@
#include "Cache.h"
#include "Cache_p.h"
#include "ChatPage.h"
#include "Config.h"
#include "EventAccessors.h"
#include "Logging.h"
#include "MatrixClient.h"
#include "UserSettingsPage.h"
#include "timeline/Permissions.h"
using TimelineEvent = mtx::events::collections::TimelineEvents;
@ -1294,8 +1297,6 @@ utils::roomVias(const std::string &roomid)
deniedServers.reserve(acls->content.deny.size());
for (const auto &s : acls->content.deny)
allowedServers.push_back(globToRegexp(s));
nhlog::ui()->critical("ACL: {}", nlohmann::json(acls->content).dump(2));
}
auto isHostAllowed = [&acls, &allowedServers, &deniedServers](const std::string &host) {
@ -1423,3 +1424,178 @@ utils::roomVias(const std::string &roomid)
return vias;
}
void
utils::updateSpaceVias()
{
if (!UserSettings::instance()->updateSpaceVias())
return;
nhlog::net()->info("update space vias called");
auto rooms = cache::roomInfo(false);
auto us = http::client()->user_id().to_string();
auto weekAgo = (uint64_t)QDateTime::currentDateTime().addDays(-7).toMSecsSinceEpoch();
struct ApplySpaceUpdatesState
{
std::vector<mtx::events::StateEvent<mtx::events::state::space::Child>> childrenToUpdate;
std::vector<mtx::events::StateEvent<mtx::events::state::space::Parent>> parentsToUpdate;
static void next(std::shared_ptr<ApplySpaceUpdatesState> state)
{
if (!state->childrenToUpdate.empty()) {
const auto &child = state->childrenToUpdate.back();
http::client()->send_state_event(
child.room_id,
child.state_key,
child.content,
[state = std::move(state)](const mtx::responses::EventId &,
mtx::http::RequestErr e) mutable {
const auto &child_ = state->childrenToUpdate.back();
if (e) {
if (e->status_code == 429 && e->matrix_error.retry_after.count() != 0) {
ChatPage::instance()->callFunctionOnGuiThread(
[state = std::move(state),
interval = e->matrix_error.retry_after]() {
QTimer::singleShot(interval,
ChatPage::instance(),
[self = std::move(state)]() mutable {
next(std::move(self));
});
});
return;
}
nhlog::net()->error("Failed to update space child {} -> {}: {}",
child_.room_id,
child_.state_key,
*e);
}
nhlog::net()->info(
"Updated space child {} -> {}", child_.room_id, child_.state_key);
state->childrenToUpdate.pop_back();
next(std::move(state));
});
return;
} else if (!state->parentsToUpdate.empty()) {
const auto &parent = state->parentsToUpdate.back();
http::client()->send_state_event(
parent.room_id,
parent.state_key,
parent.content,
[state = std::move(state)](const mtx::responses::EventId &,
mtx::http::RequestErr e) mutable {
const auto &parent_ = state->parentsToUpdate.back();
if (e) {
if (e->status_code == 429 && e->matrix_error.retry_after.count() != 0) {
ChatPage::instance()->callFunctionOnGuiThread(
[state = std::move(state),
interval = e->matrix_error.retry_after]() {
QTimer::singleShot(interval,
ChatPage::instance(),
[self = std::move(state)]() mutable {
next(std::move(self));
});
});
return;
}
nhlog::net()->error("Failed to update space parent {} -> {}: {}",
parent_.room_id,
parent_.state_key,
*e);
}
nhlog::net()->info(
"Updated space parent {} -> {}", parent_.room_id, parent_.state_key);
state->parentsToUpdate.pop_back();
next(std::move(state));
});
return;
}
}
};
auto asus = std::make_shared<ApplySpaceUpdatesState>();
for (const auto &[roomid, info] : rooms.toStdMap()) {
if (!info.is_space)
continue;
auto spaceid = roomid.toStdString();
if (auto pl = cache::client()
->getStateEvent<mtx::events::state::PowerLevels>(spaceid)
.value_or(mtx::events::StateEvent<mtx::events::state::PowerLevels>{})
.content;
pl.user_level(us) < pl.state_level(to_string(mtx::events::EventType::SpaceChild)))
continue;
auto children = cache::client()->getChildRoomIds(spaceid);
for (const auto &childid : children) {
// only update children we are joined to
if (!rooms.contains(QString::fromStdString(childid)))
continue;
auto child =
cache::client()->getStateEvent<mtx::events::state::space::Child>(spaceid, childid);
if (child &&
// don't update too often
child->origin_server_ts < weekAgo &&
// ignore unset spaces
(child->content.via && !child->content.via->empty())) {
auto newVias = utils::roomVias(childid);
if (!newVias.empty() && newVias != child->content.via) {
nhlog::net()->info("Will update {} -> {} child relation from {} to {}",
spaceid,
childid,
fmt::join(*child->content.via, ","),
fmt::join(newVias, ","));
child->content.via = std::move(newVias);
child->room_id = spaceid;
asus->childrenToUpdate.push_back(*std::move(child));
}
}
auto parent =
cache::client()->getStateEvent<mtx::events::state::space::Parent>(childid, spaceid);
if (parent &&
// don't update too often
parent->origin_server_ts < weekAgo &&
// ignore unset spaces
(parent->content.via && !parent->content.via->empty())) {
if (auto pl =
cache::client()
->getStateEvent<mtx::events::state::PowerLevels>(childid)
.value_or(mtx::events::StateEvent<mtx::events::state::PowerLevels>{})
.content;
pl.user_level(us) <
pl.state_level(to_string(mtx::events::EventType::SpaceParent)))
continue;
auto newVias = utils::roomVias(spaceid);
if (!newVias.empty() && newVias != parent->content.via) {
nhlog::net()->info("Will update {} -> {} parent relation from {} to {}",
childid,
spaceid,
fmt::join(*parent->content.via, ","),
fmt::join(newVias, ","));
parent->content.via = std::move(newVias);
parent->room_id = childid;
asus->parentsToUpdate.push_back(*std::move(parent));
}
}
}
}
ApplySpaceUpdatesState::next(std::move(asus));
}