| 1 | use anyhow::Result; |
| 2 | use clap::Parser; |
| 3 | use futures_util::{StreamExt, pin_mut}; |
| 4 | use matrix_sdk::{ |
| 5 | Client, |
| 6 | config::SyncSettings, |
| 7 | encryption::{backups::BackupState, secret_storage::SecretStore}, |
| 8 | }; |
| 9 | use url::Url; |
| 10 | |
| 11 | /// A command line example showcasing how to resume backups by importing the |
| 12 | /// backup key from secret storage. |
| 13 | #[derive(Parser, Debug)] |
| 14 | struct Cli { |
| 15 | /// The homeserver to connect to. |
| 16 | #[clap(value_parser)] |
| 17 | homeserver: Url, |
| 18 | |
| 19 | /// The user ID that should be used to restore the session. |
| 20 | #[clap(value_parser)] |
| 21 | user_name: String, |
| 22 | |
| 23 | /// The password that should be used for the login. |
| 24 | #[clap(value_parser)] |
| 25 | password: String, |
| 26 | |
| 27 | /// Set the proxy that should be used for the connection. |
| 28 | #[clap(short, long)] |
| 29 | proxy: Option<Url>, |
| 30 | |
| 31 | /// Enable verbose logging output. |
| 32 | #[clap(short, long, action)] |
| 33 | verbose: bool, |
| 34 | |
| 35 | /// The secret storage key, this key will be used to open the secret-store. |
| 36 | #[clap(long, action)] |
| 37 | secret_store_key: String, |
| 38 | } |
| 39 | |
| 40 | async fn import_known_secrets(client: &Client, secret_store: SecretStore) -> Result<()> { |
| 41 | secret_store.import_secrets().await?; |
| 42 | |
| 43 | let status = client |
| 44 | .encryption() |
| 45 | .cross_signing_status() |
| 46 | .await |
| 47 | .expect("We should be able to get our cross-signing status"); |
| 48 | |
| 49 | if status.is_complete() { |
| 50 | println!("Successfully imported all the cross-signing keys"); |
| 51 | } else { |
| 52 | eprintln!("Couldn't import all the cross-signing keys: {status:?}"); |
| 53 | } |
| 54 | |
| 55 | Ok(()) |
| 56 | } |
| 57 | |
| 58 | async fn login(cli: &Cli) -> Result<Client> { |
| 59 | let builder = Client::builder().homeserver_url(&cli.homeserver); |
| 60 | |
| 61 | let builder = if let Some(proxy) = &cli.proxy { builder.proxy(proxy) } else { builder }; |
| 62 | |
| 63 | let client = builder.build().await?; |
| 64 | |
| 65 | client |
| 66 | .matrix_auth() |
| 67 | .login_username(&cli.user_name, &cli.password) |
| 68 | .initial_device_display_name("rust-sdk") |
| 69 | .await?; |
| 70 | |
| 71 | Ok(client) |
| 72 | } |
| 73 | |
| 74 | async fn listen_for_backup_state_changes(client: Client) { |
| 75 | let stream = client.encryption().backups().state_stream(); |
| 76 | pin_mut!(stream); |
| 77 | |
| 78 | while let Some(state) = stream.next().await { |
| 79 | let Ok(state) = state else { panic!("Error while receiving backup state updates") }; |
| 80 | |
| 81 | match state { |
| 82 | BackupState::Unknown => (), |
| 83 | BackupState::Enabling => println!("Trying to enable backups"), |
| 84 | BackupState::Resuming => println!("Trying to resume backups"), |
| 85 | BackupState::Enabled => println!("Backups have been successfully enabled"), |
| 86 | BackupState::Downloading => println!("Downloading the room keys from the backup"), |
| 87 | BackupState::Disabling => println!("Disabling the backup"), |
| 88 | BackupState::Creating => println!("Trying to create a new backup"), |
| 89 | } |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | #[tokio::main] |
| 94 | async fn main() -> Result<()> { |
| 95 | let cli = Cli::parse(); |
| 96 | |
| 97 | if cli.verbose { |
| 98 | tracing_subscriber::fmt::init(); |
| 99 | } |
| 100 | |
| 101 | let client = login(&cli).await?; |
| 102 | |
| 103 | client.sync_once(Default::default()).await?; |
| 104 | |
| 105 | let secret_store = |
| 106 | client.encryption().secret_storage().open_secret_store(&cli.secret_store_key).await?; |
| 107 | |
| 108 | let _task = tokio::spawn({ |
| 109 | let client = client.clone(); |
| 110 | async move { listen_for_backup_state_changes(client).await } |
| 111 | }); |
| 112 | |
| 113 | import_known_secrets(&client, secret_store).await?; |
| 114 | |
| 115 | loop { |
| 116 | if let Err(e) = client.sync(SyncSettings::new()).await { |
| 117 | eprintln!("Error syncing: {e:?}") |
| 118 | } |
| 119 | } |
| 120 | } |