From 10313d29abe7b67b8e179ee40aca5f87735fea14 Mon Sep 17 00:00:00 2001 From: Jez Cope Date: Wed, 21 Jul 2021 20:10:28 +0100 Subject: [PATCH] Implement `room tombstone` command --- README.md | 5 ++++- src/commands.rs | 35 ++++++++++++++++++++++++++++++++++- src/main.rs | 42 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 77 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ab5e8ea..1eea372 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,12 @@ TODO: policy on maintenance and contributions - [x] Login and store session info - [ ] Log out - [x] Show login status -- [ ] Tombstone room +- [x] Tombstone room - [x] Add room alias - [x] Remove room alias +- [ ] Set canonical room alias + - [ ] Optionally create alias in one command +- [ ] Remove canonical room alias - [x] List rooms - [ ] Filter room list in various ways (esp. Spaces!) - [ ] Handle multiple accounts on different homeservers diff --git a/src/commands.rs b/src/commands.rs index 562200a..3ee2880 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1,6 +1,10 @@ use anyhow::{Context, Result}; use matrix_sdk::{ - ruma::{api::client::r0::alias, RoomAliasId, RoomId, UserId}, + ruma::{ + api::client::r0::alias, + events::{room::tombstone::TombstoneEventContent, AnyStateEventContent}, + RoomAliasId, RoomId, UserId, + }, Client, Session, SyncSettings, }; use rpassword::prompt_password_stderr; @@ -108,6 +112,35 @@ pub async fn list_rooms() -> CommandResult { Ok(()) } +pub async fn tombstone_room(old_room_id: &str, new_room_id: &str, msg: &str) -> CommandResult { + let old_room_id = RoomId::try_from(old_room_id) + .with_context(|| format!("Failed to parse '{}' as room ID", old_room_id))?; + let new_room_id = RoomId::try_from(new_room_id) + .with_context(|| format!("Failed to parse '{}' as room ID", new_room_id))?; + let client = restore_session().await?; + let mut sync_settings = SyncSettings::new(); + if let Some(token) = client.sync_token().await { + sync_settings = sync_settings.token(token); + } + + print!("Syncing..."); + io::stderr().flush().unwrap(); + client + .sync_once(sync_settings) + .await + .context("Sync failed")?; + println!(" done"); + + if let Some(old_room) = client.get_joined_room(&old_room_id) { + let event = TombstoneEventContent::new(msg.to_string(), new_room_id); + let content = AnyStateEventContent::RoomTombstone(event); + old_room.send_state_event(content, "").await?; + } else { + println!("Room {} not joined", old_room_id); + } + Ok(()) +} + pub async fn add_alias(room_id: &str, alias: &str) -> CommandResult { let room_id = RoomId::try_from(room_id) .with_context(|| format!("Failed to parse '{}' as room ID", room_id))?; diff --git a/src/main.rs b/src/main.rs index ec2a2d5..55fbd16 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,7 @@ mod commands; mod session; use anyhow::Result; -use clap::SubCommand; +use clap::{Arg, SubCommand}; #[tokio::main] async fn main() -> Result<()> { @@ -22,7 +22,30 @@ async fn main() -> Result<()> { ) .subcommand(SubCommand::with_name("logout").about("ends the current session")) .subcommand(SubCommand::with_name("status").about("displays current session status")) - .subcommand(SubCommand::with_name("list-rooms").about("lists rooms available to the user")) + .subcommand( + SubCommand::with_name("room") + .about("room subcommands") + .subcommand( + SubCommand::with_name("list") + .alias("ls") + .about("lists rooms available to the user"), + ) + .subcommand( + SubCommand::with_name("tombstone") + .about("add a tombstone redirecting one room to another") + .args_from_usage( + " 'The ID of the source room' + 'The ID of the target room'", + ) + .arg( + Arg::with_name("MSG") + .short("m") + .long("message") + .help("The message to display in the old rom") + .default_value("This room has been replaced"), + ), + ), + ) .subcommand( SubCommand::with_name("alias") .about("alias subcommands") @@ -45,7 +68,20 @@ async fn main() -> Result<()> { match matches.subcommand() { ("login", Some(submatches)) => commands::login(submatches.value_of("user")).await?, ("status", Some(_)) => commands::status().await?, - ("list-rooms", Some(_)) => commands::list_rooms().await?, + ("room", Some(room)) => match room.subcommand() { + ("list", Some(_)) => commands::list_rooms().await?, + ("tombstone", Some(submatches)) => { + commands::tombstone_room( + submatches.value_of("OLD_ROOM_ID").unwrap(), + submatches.value_of("NEW_ROOM_ID").unwrap(), + submatches.value_of("MSG").unwrap(), + ) + .await? + } + (c, _) => { + todo!("Subcommand '{}' not implemented yet!", c); + } + }, ("alias", Some(alias)) => match alias.subcommand() { ("add", Some(submatches)) => { commands::add_alias(