Add /clear-timeline command
This commit is contained in:
parent
1e9efa3072
commit
14a0aac748
108
src/Cache.cpp
108
src/Cache.cpp
@ -2304,6 +2304,11 @@ Cache::saveTimelineMessages(lmdb::txn &txn,
|
|||||||
|
|
||||||
lmdb::val event_id = event_id_val;
|
lmdb::val event_id = event_id_val;
|
||||||
|
|
||||||
|
json orderEntry = json::object();
|
||||||
|
orderEntry["event_id"] = event_id_val;
|
||||||
|
if (first && !res.prev_batch.empty())
|
||||||
|
orderEntry["prev_batch"] = res.prev_batch;
|
||||||
|
|
||||||
lmdb::val txn_order;
|
lmdb::val txn_order;
|
||||||
if (!txn_id.empty() &&
|
if (!txn_id.empty() &&
|
||||||
lmdb::dbi_get(txn, evToOrderDb, lmdb::val(txn_id), txn_order)) {
|
lmdb::dbi_get(txn, evToOrderDb, lmdb::val(txn_id), txn_order)) {
|
||||||
@ -2317,7 +2322,7 @@ Cache::saveTimelineMessages(lmdb::txn &txn,
|
|||||||
lmdb::dbi_del(txn, msg2orderDb, lmdb::val(txn_id));
|
lmdb::dbi_del(txn, msg2orderDb, lmdb::val(txn_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
lmdb::dbi_put(txn, orderDb, txn_order, event_id);
|
lmdb::dbi_put(txn, orderDb, txn_order, lmdb::val(orderEntry.dump()));
|
||||||
lmdb::dbi_put(txn, evToOrderDb, event_id, txn_order);
|
lmdb::dbi_put(txn, evToOrderDb, event_id, txn_order);
|
||||||
lmdb::dbi_del(txn, evToOrderDb, lmdb::val(txn_id));
|
lmdb::dbi_del(txn, evToOrderDb, lmdb::val(txn_id));
|
||||||
|
|
||||||
@ -2389,10 +2394,6 @@ Cache::saveTimelineMessages(lmdb::txn &txn,
|
|||||||
|
|
||||||
++index;
|
++index;
|
||||||
|
|
||||||
json orderEntry = json::object();
|
|
||||||
orderEntry["event_id"] = event_id_val;
|
|
||||||
if (first && !res.prev_batch.empty())
|
|
||||||
orderEntry["prev_batch"] = res.prev_batch;
|
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
nhlog::db()->debug("saving '{}'", orderEntry.dump());
|
nhlog::db()->debug("saving '{}'", orderEntry.dump());
|
||||||
@ -2440,6 +2441,7 @@ Cache::saveOldMessages(const std::string &room_id, const mtx::responses::Message
|
|||||||
auto relationsDb = getRelationsDb(txn, room_id);
|
auto relationsDb = getRelationsDb(txn, room_id);
|
||||||
|
|
||||||
auto orderDb = getEventOrderDb(txn, room_id);
|
auto orderDb = getEventOrderDb(txn, room_id);
|
||||||
|
auto evToOrderDb = getEventToOrderDb(txn, room_id);
|
||||||
auto msg2orderDb = getMessageToOrderDb(txn, room_id);
|
auto msg2orderDb = getMessageToOrderDb(txn, room_id);
|
||||||
auto order2msgDb = getOrderToMessageDb(txn, room_id);
|
auto order2msgDb = getOrderToMessageDb(txn, room_id);
|
||||||
|
|
||||||
@ -2483,6 +2485,7 @@ Cache::saveOldMessages(const std::string &room_id, const mtx::responses::Message
|
|||||||
|
|
||||||
lmdb::dbi_put(
|
lmdb::dbi_put(
|
||||||
txn, orderDb, lmdb::val(&index, sizeof(index)), lmdb::val(orderEntry.dump()));
|
txn, orderDb, lmdb::val(&index, sizeof(index)), lmdb::val(orderEntry.dump()));
|
||||||
|
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 (event["type"] != "m.reaction" && event["type"] != "m.dummy") {
|
if (event["type"] != "m.reaction" && event["type"] != "m.dummy") {
|
||||||
@ -2516,6 +2519,94 @@ Cache::saveOldMessages(const std::string &room_id, const mtx::responses::Message
|
|||||||
return msgIndex;
|
return msgIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Cache::clearTimeline(const std::string &room_id)
|
||||||
|
{
|
||||||
|
auto txn = lmdb::txn::begin(env_);
|
||||||
|
auto eventsDb = getEventsDb(txn, room_id);
|
||||||
|
auto relationsDb = getRelationsDb(txn, room_id);
|
||||||
|
|
||||||
|
auto orderDb = getEventOrderDb(txn, room_id);
|
||||||
|
auto evToOrderDb = getEventToOrderDb(txn, room_id);
|
||||||
|
auto msg2orderDb = getMessageToOrderDb(txn, room_id);
|
||||||
|
auto order2msgDb = getOrderToMessageDb(txn, room_id);
|
||||||
|
|
||||||
|
lmdb::val indexVal, val;
|
||||||
|
auto cursor = lmdb::cursor::open(txn, orderDb);
|
||||||
|
|
||||||
|
bool start = true;
|
||||||
|
bool passed_pagination_token = false;
|
||||||
|
while (cursor.get(indexVal, val, start ? MDB_LAST : MDB_PREV)) {
|
||||||
|
start = false;
|
||||||
|
json obj;
|
||||||
|
|
||||||
|
try {
|
||||||
|
obj = json::parse(std::string_view(val.data(), val.size()));
|
||||||
|
} catch (std::exception &) {
|
||||||
|
// workaround bug in the initial db format, where we sometimes didn't store
|
||||||
|
// json...
|
||||||
|
obj = {{"event_id", std::string(val.data(), val.size())}};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (passed_pagination_token) {
|
||||||
|
if (obj.count("event_id") != 0) {
|
||||||
|
lmdb::val event_id = obj["event_id"].get<std::string>();
|
||||||
|
lmdb::dbi_del(txn, evToOrderDb, event_id);
|
||||||
|
lmdb::dbi_del(txn, eventsDb, event_id);
|
||||||
|
|
||||||
|
lmdb::dbi_del(txn, relationsDb, event_id);
|
||||||
|
|
||||||
|
lmdb::val order{};
|
||||||
|
bool exists = lmdb::dbi_get(txn, msg2orderDb, event_id, order);
|
||||||
|
if (exists) {
|
||||||
|
lmdb::dbi_del(txn, order2msgDb, order);
|
||||||
|
lmdb::dbi_del(txn, msg2orderDb, event_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lmdb::cursor_del(cursor);
|
||||||
|
} else {
|
||||||
|
if (obj.count("prev_batch") != 0)
|
||||||
|
passed_pagination_token = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto msgCursor = lmdb::cursor::open(txn, order2msgDb);
|
||||||
|
start = true;
|
||||||
|
while (msgCursor.get(indexVal, val, start ? MDB_LAST : MDB_PREV)) {
|
||||||
|
start = false;
|
||||||
|
|
||||||
|
lmdb::val eventId;
|
||||||
|
bool innerStart = true;
|
||||||
|
bool found = false;
|
||||||
|
while (cursor.get(indexVal, eventId, innerStart ? MDB_LAST : MDB_PREV)) {
|
||||||
|
innerStart = false;
|
||||||
|
|
||||||
|
json obj;
|
||||||
|
try {
|
||||||
|
obj = json::parse(std::string_view(eventId.data(), eventId.size()));
|
||||||
|
} catch (std::exception &) {
|
||||||
|
obj = {{"event_id", std::string(eventId.data(), eventId.size())}};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj["event_id"] == std::string(val.data(), val.size())) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
lmdb::cursor_del(msgCursor);
|
||||||
|
} while (msgCursor.get(indexVal, val, MDB_PREV));
|
||||||
|
|
||||||
|
cursor.close();
|
||||||
|
msgCursor.close();
|
||||||
|
txn.commit();
|
||||||
|
}
|
||||||
|
|
||||||
mtx::responses::Notifications
|
mtx::responses::Notifications
|
||||||
Cache::getTimelineMentionsForRoom(lmdb::txn &txn, const std::string &room_id)
|
Cache::getTimelineMentionsForRoom(lmdb::txn &txn, const std::string &room_id)
|
||||||
{
|
{
|
||||||
@ -2655,9 +2746,11 @@ Cache::deleteOldMessages()
|
|||||||
|
|
||||||
for (const auto &room_id : room_ids) {
|
for (const auto &room_id : room_ids) {
|
||||||
auto orderDb = getEventOrderDb(txn, room_id);
|
auto orderDb = getEventOrderDb(txn, room_id);
|
||||||
|
auto evToOrderDb = getEventToOrderDb(txn, room_id);
|
||||||
auto o2m = getOrderToMessageDb(txn, room_id);
|
auto o2m = getOrderToMessageDb(txn, room_id);
|
||||||
auto m2o = getMessageToOrderDb(txn, room_id);
|
auto m2o = getMessageToOrderDb(txn, room_id);
|
||||||
auto eventsDb = getEventsDb(txn, room_id);
|
auto eventsDb = getEventsDb(txn, room_id);
|
||||||
|
auto relationsDb = getRelationsDb(txn, room_id);
|
||||||
auto cursor = lmdb::cursor::open(txn, orderDb);
|
auto cursor = lmdb::cursor::open(txn, orderDb);
|
||||||
|
|
||||||
uint64_t first, last;
|
uint64_t first, last;
|
||||||
@ -2678,14 +2771,17 @@ Cache::deleteOldMessages()
|
|||||||
|
|
||||||
bool start = true;
|
bool start = true;
|
||||||
while (cursor.get(indexVal, val, start ? MDB_FIRST : MDB_NEXT) &&
|
while (cursor.get(indexVal, val, start ? MDB_FIRST : MDB_NEXT) &&
|
||||||
message_count-- < MAX_RESTORED_MESSAGES) {
|
message_count-- > MAX_RESTORED_MESSAGES) {
|
||||||
start = false;
|
start = false;
|
||||||
auto obj = json::parse(std::string_view(val.data(), val.size()));
|
auto obj = json::parse(std::string_view(val.data(), val.size()));
|
||||||
|
|
||||||
if (obj.count("event_id") != 0) {
|
if (obj.count("event_id") != 0) {
|
||||||
lmdb::val event_id = obj["event_id"].get<std::string>();
|
lmdb::val event_id = obj["event_id"].get<std::string>();
|
||||||
|
lmdb::dbi_del(txn, evToOrderDb, event_id);
|
||||||
lmdb::dbi_del(txn, eventsDb, event_id);
|
lmdb::dbi_del(txn, eventsDb, event_id);
|
||||||
|
|
||||||
|
lmdb::dbi_del(txn, relationsDb, event_id);
|
||||||
|
|
||||||
lmdb::val order{};
|
lmdb::val order{};
|
||||||
bool exists = lmdb::dbi_get(txn, m2o, event_id, order);
|
bool exists = lmdb::dbi_get(txn, m2o, event_id, order);
|
||||||
if (exists) {
|
if (exists) {
|
||||||
|
@ -208,6 +208,9 @@ public:
|
|||||||
const std::string &room_id);
|
const std::string &room_id);
|
||||||
void removePendingStatus(const std::string &room_id, const std::string &txn_id);
|
void removePendingStatus(const std::string &room_id, const std::string &txn_id);
|
||||||
|
|
||||||
|
//! clear timeline keeping only the latest batch
|
||||||
|
void clearTimeline(const std::string &room_id);
|
||||||
|
|
||||||
//! Remove old unused data.
|
//! Remove old unused data.
|
||||||
void deleteOldMessages();
|
void deleteOldMessages();
|
||||||
void deleteOldData() noexcept;
|
void deleteOldData() noexcept;
|
||||||
|
@ -155,6 +155,11 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
|
|||||||
trySync();
|
trySync();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(text_input_,
|
||||||
|
&TextInputWidget::clearRoomTimeline,
|
||||||
|
view_manager_,
|
||||||
|
&TimelineViewManager::clearCurrentRoomTimeline);
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
new QShortcut(QKeySequence("Ctrl+Down"), this), &QShortcut::activated, this, [this]() {
|
new QShortcut(QKeySequence("Ctrl+Down"), this), &QShortcut::activated, this, [this]() {
|
||||||
if (isVisible())
|
if (isVisible())
|
||||||
|
@ -566,27 +566,29 @@ void
|
|||||||
TextInputWidget::command(QString command, QString args)
|
TextInputWidget::command(QString command, QString args)
|
||||||
{
|
{
|
||||||
if (command == "me") {
|
if (command == "me") {
|
||||||
sendEmoteMessage(args);
|
emit sendEmoteMessage(args);
|
||||||
} else if (command == "join") {
|
} else if (command == "join") {
|
||||||
sendJoinRoomRequest(args);
|
emit sendJoinRoomRequest(args);
|
||||||
} else if (command == "invite") {
|
} else if (command == "invite") {
|
||||||
sendInviteRoomRequest(args.section(' ', 0, 0), args.section(' ', 1, -1));
|
emit sendInviteRoomRequest(args.section(' ', 0, 0), args.section(' ', 1, -1));
|
||||||
} else if (command == "kick") {
|
} else if (command == "kick") {
|
||||||
sendKickRoomRequest(args.section(' ', 0, 0), args.section(' ', 1, -1));
|
emit sendKickRoomRequest(args.section(' ', 0, 0), args.section(' ', 1, -1));
|
||||||
} else if (command == "ban") {
|
} else if (command == "ban") {
|
||||||
sendBanRoomRequest(args.section(' ', 0, 0), args.section(' ', 1, -1));
|
emit sendBanRoomRequest(args.section(' ', 0, 0), args.section(' ', 1, -1));
|
||||||
} else if (command == "unban") {
|
} else if (command == "unban") {
|
||||||
sendUnbanRoomRequest(args.section(' ', 0, 0), args.section(' ', 1, -1));
|
emit sendUnbanRoomRequest(args.section(' ', 0, 0), args.section(' ', 1, -1));
|
||||||
} else if (command == "roomnick") {
|
} else if (command == "roomnick") {
|
||||||
changeRoomNick(args);
|
emit changeRoomNick(args);
|
||||||
} else if (command == "shrug") {
|
} else if (command == "shrug") {
|
||||||
sendTextMessage("¯\\_(ツ)_/¯");
|
emit sendTextMessage("¯\\_(ツ)_/¯");
|
||||||
} else if (command == "fliptable") {
|
} else if (command == "fliptable") {
|
||||||
sendTextMessage("(╯°□°)╯︵ ┻━┻");
|
emit sendTextMessage("(╯°□°)╯︵ ┻━┻");
|
||||||
} else if (command == "unfliptable") {
|
} else if (command == "unfliptable") {
|
||||||
sendTextMessage(" ┯━┯╭( º _ º╭)");
|
emit sendTextMessage(" ┯━┯╭( º _ º╭)");
|
||||||
} else if (command == "sovietflip") {
|
} else if (command == "sovietflip") {
|
||||||
sendTextMessage("ノ┬─┬ノ ︵ ( \\o°o)\\");
|
emit sendTextMessage("ノ┬─┬ノ ︵ ( \\o°o)\\");
|
||||||
|
} else if (command == "clear-timeline") {
|
||||||
|
emit clearRoomTimeline();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,6 +156,7 @@ private slots:
|
|||||||
signals:
|
signals:
|
||||||
void sendTextMessage(const QString &msg);
|
void sendTextMessage(const QString &msg);
|
||||||
void sendEmoteMessage(QString msg);
|
void sendEmoteMessage(QString msg);
|
||||||
|
void clearRoomTimeline();
|
||||||
void heightChanged(int height);
|
void heightChanged(int height);
|
||||||
|
|
||||||
void uploadMedia(const QSharedPointer<QIODevice> data,
|
void uploadMedia(const QSharedPointer<QIODevice> data,
|
||||||
|
@ -175,6 +175,26 @@ EventStore::addPending(mtx::events::collections::TimelineEvents event)
|
|||||||
emit processPending();
|
emit processPending();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EventStore::clearTimeline()
|
||||||
|
{
|
||||||
|
emit beginResetModel();
|
||||||
|
|
||||||
|
cache::client()->clearTimeline(room_id_);
|
||||||
|
auto range = cache::client()->getTimelineRange(room_id_);
|
||||||
|
if (range) {
|
||||||
|
nhlog::db()->info("Range {} {}", range->last, range->first);
|
||||||
|
this->last = range->last;
|
||||||
|
this->first = range->first;
|
||||||
|
} else {
|
||||||
|
this->first = std::numeric_limits<uint64_t>::max();
|
||||||
|
this->last = std::numeric_limits<uint64_t>::max();
|
||||||
|
}
|
||||||
|
nhlog::ui()->info("Range {} {}", this->last, this->first);
|
||||||
|
|
||||||
|
emit endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
EventStore::handleSync(const mtx::responses::Timeline &events)
|
EventStore::handleSync(const mtx::responses::Timeline &events)
|
||||||
{
|
{
|
||||||
|
@ -101,6 +101,7 @@ signals:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void addPending(mtx::events::collections::TimelineEvents event);
|
void addPending(mtx::events::collections::TimelineEvents event);
|
||||||
|
void clearTimeline();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mtx::events::collections::TimelineEvents *decryptEvent(
|
mtx::events::collections::TimelineEvents *decryptEvent(
|
||||||
|
@ -242,6 +242,7 @@ public slots:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void setDecryptDescription(bool decrypt) { decryptDescription = decrypt; }
|
void setDecryptDescription(bool decrypt) { decryptDescription = decrypt; }
|
||||||
|
void clearTimeline() { events.clearTimeline(); }
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void addPendingMessage(mtx::events::collections::TimelineEvents event);
|
void addPendingMessage(mtx::events::collections::TimelineEvents event);
|
||||||
|
@ -92,6 +92,12 @@ public slots:
|
|||||||
uint64_t dsize);
|
uint64_t dsize);
|
||||||
void updateEncryptedDescriptions();
|
void updateEncryptedDescriptions();
|
||||||
|
|
||||||
|
void clearCurrentRoomTimeline()
|
||||||
|
{
|
||||||
|
if (timeline_)
|
||||||
|
timeline_->clearTimeline();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifdef USE_QUICK_VIEW
|
#ifdef USE_QUICK_VIEW
|
||||||
QQuickView *view;
|
QQuickView *view;
|
||||||
|
Loading…
Reference in New Issue
Block a user