feat: Add admin command to delete sync tokens from a room

This commit is contained in:
Jade Ellis 2025-05-21 22:24:33 +01:00
parent 5d44653e3a
commit 0d8a8bf02e
No known key found for this signature in database
GPG key ID: 8705A2A3EBF77BD2
3 changed files with 63 additions and 2 deletions

View file

@ -1,6 +1,6 @@
use conduwuit::{Err, Result}; use conduwuit::{Err, Result};
use futures::StreamExt; use futures::StreamExt;
use ruma::OwnedRoomId; use ruma::{OwnedRoomId, OwnedRoomOrAliasId};
use crate::{PAGE_SIZE, admin_command, get_room_info}; use crate::{PAGE_SIZE, admin_command, get_room_info};
@ -66,3 +66,20 @@ pub(super) async fn exists(&self, room_id: OwnedRoomId) -> Result {
self.write_str(&format!("{result}")).await self.write_str(&format!("{result}")).await
} }
#[admin_command]
pub(super) async fn purge_sync_tokens(&self, room: OwnedRoomOrAliasId) -> Result {
// Resolve the room ID from the room or alias ID
let room_id = self.services.rooms.alias.resolve(&room).await?;
// Delete all tokens for this room using the service method
let deleted_count = match self.services.rooms.user.delete_room_tokens(&room_id).await {
| Ok(count) => count,
| Err(_) => return Err!("Failed to delete sync tokens for room {}", room_id),
};
self.write_str(&format!(
"Successfully deleted {deleted_count} sync tokens for room {room_id}"
))
.await
}

View file

@ -6,7 +6,7 @@ mod moderation;
use clap::Subcommand; use clap::Subcommand;
use conduwuit::Result; use conduwuit::Result;
use ruma::OwnedRoomId; use ruma::{OwnedRoomId, OwnedRoomOrAliasId};
use self::{ use self::{
alias::RoomAliasCommand, directory::RoomDirectoryCommand, info::RoomInfoCommand, alias::RoomAliasCommand, directory::RoomDirectoryCommand, info::RoomInfoCommand,
@ -56,4 +56,11 @@ pub(super) enum RoomCommand {
Exists { Exists {
room_id: OwnedRoomId, room_id: OwnedRoomId,
}, },
/// - Delete all sync tokens for a room
PurgeSyncTokens {
/// Room ID or alias to purge sync tokens for
#[arg(value_parser)]
room: OwnedRoomOrAliasId,
},
} }

View file

@ -127,3 +127,40 @@ pub async fn get_token_shortstatehash(
.await .await
.deserialized() .deserialized()
} }
/// Delete all sync tokens associated with a room
///
/// This helps clean up the database as these tokens are never otherwise removed
#[implement(Service)]
pub async fn delete_room_tokens(&self, room_id: &RoomId) -> Result<usize> {
use futures::TryStreamExt;
let shortroomid = self.services.short.get_shortroomid(room_id).await?;
// Create a prefix to search by - all entries for this room will start with its
// short ID
let prefix = &[shortroomid];
// Get all keys with this room prefix
let mut count = 0;
// Collect all keys into a Vec first, then delete them
let keys = self
.db
.roomsynctoken_shortstatehash
.keys_prefix_raw(prefix)
.map_ok(|key| {
// Clone the key since we can't store references in the Vec
Vec::from(key)
})
.try_collect::<Vec<_>>()
.await?;
// Delete each key individually
for key in &keys {
self.db.roomsynctoken_shortstatehash.del(key);
count += 1;
}
Ok(count)
}