atagen

matrix-rust-sdk

public
Star0
Watch0
ssh://brewery@pls.lobotomise.me:33/atagen/matrix-rust-sdk.git

Blame: examples/backups/src/main.rs

7ff8adafe9e4atagen2026-10-22 12:30 UTC1
use anyhow::Result;
7ff8adafe9e4atagen2026-10-22 12:30 UTC2
use clap::Parser;
7ff8adafe9e4atagen2026-10-22 12:30 UTC3
use futures_util::{StreamExt, pin_mut};
7ff8adafe9e4atagen2026-10-22 12:30 UTC4
use matrix_sdk::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC5
    Client,
7ff8adafe9e4atagen2026-10-22 12:30 UTC6
    config::SyncSettings,
7ff8adafe9e4atagen2026-10-22 12:30 UTC7
    encryption::{backups::BackupState, secret_storage::SecretStore},
7ff8adafe9e4atagen2026-10-22 12:30 UTC8
};
7ff8adafe9e4atagen2026-10-22 12:30 UTC9
use url::Url;
7ff8adafe9e4atagen2026-10-22 12:30 UTC10
7ff8adafe9e4atagen2026-10-22 12:30 UTC11
/// A command line example showcasing how to resume backups by importing the
7ff8adafe9e4atagen2026-10-22 12:30 UTC12
/// backup key from secret storage.
7ff8adafe9e4atagen2026-10-22 12:30 UTC13
#[derive(Parser, Debug)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC14
struct Cli {
7ff8adafe9e4atagen2026-10-22 12:30 UTC15
    /// The homeserver to connect to.
7ff8adafe9e4atagen2026-10-22 12:30 UTC16
    #[clap(value_parser)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC17
    homeserver: Url,
7ff8adafe9e4atagen2026-10-22 12:30 UTC18
7ff8adafe9e4atagen2026-10-22 12:30 UTC19
    /// The user ID that should be used to restore the session.
7ff8adafe9e4atagen2026-10-22 12:30 UTC20
    #[clap(value_parser)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC21
    user_name: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC22
7ff8adafe9e4atagen2026-10-22 12:30 UTC23
    /// The password that should be used for the login.
7ff8adafe9e4atagen2026-10-22 12:30 UTC24
    #[clap(value_parser)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC25
    password: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC26
7ff8adafe9e4atagen2026-10-22 12:30 UTC27
    /// Set the proxy that should be used for the connection.
7ff8adafe9e4atagen2026-10-22 12:30 UTC28
    #[clap(short, long)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC29
    proxy: Option<Url>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC30
7ff8adafe9e4atagen2026-10-22 12:30 UTC31
    /// Enable verbose logging output.
7ff8adafe9e4atagen2026-10-22 12:30 UTC32
    #[clap(short, long, action)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC33
    verbose: bool,
7ff8adafe9e4atagen2026-10-22 12:30 UTC34
7ff8adafe9e4atagen2026-10-22 12:30 UTC35
    /// The secret storage key, this key will be used to open the secret-store.
7ff8adafe9e4atagen2026-10-22 12:30 UTC36
    #[clap(long, action)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC37
    secret_store_key: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC38
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC39
7ff8adafe9e4atagen2026-10-22 12:30 UTC40
async fn import_known_secrets(client: &Client, secret_store: SecretStore) -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC41
    secret_store.import_secrets().await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC42
7ff8adafe9e4atagen2026-10-22 12:30 UTC43
    let status = client
7ff8adafe9e4atagen2026-10-22 12:30 UTC44
        .encryption()
7ff8adafe9e4atagen2026-10-22 12:30 UTC45
        .cross_signing_status()
7ff8adafe9e4atagen2026-10-22 12:30 UTC46
        .await
7ff8adafe9e4atagen2026-10-22 12:30 UTC47
        .expect("We should be able to get our cross-signing status");
7ff8adafe9e4atagen2026-10-22 12:30 UTC48
7ff8adafe9e4atagen2026-10-22 12:30 UTC49
    if status.is_complete() {
7ff8adafe9e4atagen2026-10-22 12:30 UTC50
        println!("Successfully imported all the cross-signing keys");
7ff8adafe9e4atagen2026-10-22 12:30 UTC51
    } else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC52
        eprintln!("Couldn't import all the cross-signing keys: {status:?}");
7ff8adafe9e4atagen2026-10-22 12:30 UTC53
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC54
7ff8adafe9e4atagen2026-10-22 12:30 UTC55
    Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC56
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC57
7ff8adafe9e4atagen2026-10-22 12:30 UTC58
async fn login(cli: &Cli) -> Result<Client> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC59
    let builder = Client::builder().homeserver_url(&cli.homeserver);
7ff8adafe9e4atagen2026-10-22 12:30 UTC60
7ff8adafe9e4atagen2026-10-22 12:30 UTC61
    let builder = if let Some(proxy) = &cli.proxy { builder.proxy(proxy) } else { builder };
7ff8adafe9e4atagen2026-10-22 12:30 UTC62
7ff8adafe9e4atagen2026-10-22 12:30 UTC63
    let client = builder.build().await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC64
7ff8adafe9e4atagen2026-10-22 12:30 UTC65
    client
7ff8adafe9e4atagen2026-10-22 12:30 UTC66
        .matrix_auth()
7ff8adafe9e4atagen2026-10-22 12:30 UTC67
        .login_username(&cli.user_name, &cli.password)
7ff8adafe9e4atagen2026-10-22 12:30 UTC68
        .initial_device_display_name("rust-sdk")
7ff8adafe9e4atagen2026-10-22 12:30 UTC69
        .await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC70
7ff8adafe9e4atagen2026-10-22 12:30 UTC71
    Ok(client)
7ff8adafe9e4atagen2026-10-22 12:30 UTC72
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC73
7ff8adafe9e4atagen2026-10-22 12:30 UTC74
async fn listen_for_backup_state_changes(client: Client) {
7ff8adafe9e4atagen2026-10-22 12:30 UTC75
    let stream = client.encryption().backups().state_stream();
7ff8adafe9e4atagen2026-10-22 12:30 UTC76
    pin_mut!(stream);
7ff8adafe9e4atagen2026-10-22 12:30 UTC77
7ff8adafe9e4atagen2026-10-22 12:30 UTC78
    while let Some(state) = stream.next().await {
7ff8adafe9e4atagen2026-10-22 12:30 UTC79
        let Ok(state) = state else { panic!("Error while receiving backup state updates") };
7ff8adafe9e4atagen2026-10-22 12:30 UTC80
7ff8adafe9e4atagen2026-10-22 12:30 UTC81
        match state {
7ff8adafe9e4atagen2026-10-22 12:30 UTC82
            BackupState::Unknown => (),
7ff8adafe9e4atagen2026-10-22 12:30 UTC83
            BackupState::Enabling => println!("Trying to enable backups"),
7ff8adafe9e4atagen2026-10-22 12:30 UTC84
            BackupState::Resuming => println!("Trying to resume backups"),
7ff8adafe9e4atagen2026-10-22 12:30 UTC85
            BackupState::Enabled => println!("Backups have been successfully enabled"),
7ff8adafe9e4atagen2026-10-22 12:30 UTC86
            BackupState::Downloading => println!("Downloading the room keys from the backup"),
7ff8adafe9e4atagen2026-10-22 12:30 UTC87
            BackupState::Disabling => println!("Disabling the backup"),
7ff8adafe9e4atagen2026-10-22 12:30 UTC88
            BackupState::Creating => println!("Trying to create a new backup"),
7ff8adafe9e4atagen2026-10-22 12:30 UTC89
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC90
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC91
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC92
7ff8adafe9e4atagen2026-10-22 12:30 UTC93
#[tokio::main]
7ff8adafe9e4atagen2026-10-22 12:30 UTC94
async fn main() -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC95
    let cli = Cli::parse();
7ff8adafe9e4atagen2026-10-22 12:30 UTC96
7ff8adafe9e4atagen2026-10-22 12:30 UTC97
    if cli.verbose {
7ff8adafe9e4atagen2026-10-22 12:30 UTC98
        tracing_subscriber::fmt::init();
7ff8adafe9e4atagen2026-10-22 12:30 UTC99
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC100
7ff8adafe9e4atagen2026-10-22 12:30 UTC101
    let client = login(&cli).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC102
7ff8adafe9e4atagen2026-10-22 12:30 UTC103
    client.sync_once(Default::default()).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC104
7ff8adafe9e4atagen2026-10-22 12:30 UTC105
    let secret_store =
7ff8adafe9e4atagen2026-10-22 12:30 UTC106
        client.encryption().secret_storage().open_secret_store(&cli.secret_store_key).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC107
7ff8adafe9e4atagen2026-10-22 12:30 UTC108
    let _task = tokio::spawn({
7ff8adafe9e4atagen2026-10-22 12:30 UTC109
        let client = client.clone();
7ff8adafe9e4atagen2026-10-22 12:30 UTC110
        async move { listen_for_backup_state_changes(client).await }
7ff8adafe9e4atagen2026-10-22 12:30 UTC111
    });
7ff8adafe9e4atagen2026-10-22 12:30 UTC112
7ff8adafe9e4atagen2026-10-22 12:30 UTC113
    import_known_secrets(&client, secret_store).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC114
7ff8adafe9e4atagen2026-10-22 12:30 UTC115
    loop {
7ff8adafe9e4atagen2026-10-22 12:30 UTC116
        if let Err(e) = client.sync(SyncSettings::new()).await {
7ff8adafe9e4atagen2026-10-22 12:30 UTC117
            eprintln!("Error syncing: {e:?}")
7ff8adafe9e4atagen2026-10-22 12:30 UTC118
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC119
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC120
}