use std::io::Write; use clap::Args; use color_eyre::{eyre::eyre, Result}; use matrix_sdk::{config::SyncSettings, ruma::UserId, Client, Session}; use tokio::io::AsyncBufReadExt; use crate::SessionData; #[derive(Args, Debug)] pub(crate) struct Setup { username: Box, #[arg(long, short = 's')] homeserver_url: Option, } async fn login_password_interactive(setup: &Setup, client: &Client) -> Result { print!("Enter password for {}: ", setup.username); std::io::stdout().flush()?; let stdin = tokio::io::BufReader::new(tokio::io::stdin()); let password = stdin .lines() .next_line() .await? .ok_or(eyre!("Password is required on first start"))?; let session = client .login_username(&setup.username, &password) .initial_device_display_name("gavel bot") .send() .await? .into(); Ok(session) } pub(crate) async fn setup(setup: Setup) -> Result<()> { let client = { let mut builder = Client::builder().sled_store(crate::sled_store_path()?, None)?; if let Some(ref url) = setup.homeserver_url { builder = builder.homeserver_url(url); } else { builder = builder.server_name(setup.username.server_name()); } builder.build().await? }; let session = login_password_interactive(&setup, &client).await?; let data = SessionData { session, homeserver_url: setup.homeserver_url, }; tokio::fs::write(crate::session_path()?, toml::to_vec(&data)?).await?; client.sync_once(SyncSettings::default()).await?; Ok(()) }