Big monolithic catchup commit

This commit is contained in:
Jez Cope 2021-07-03 14:56:08 +01:00
parent c984e84cb3
commit 654a33c686
4 changed files with 817 additions and 320 deletions

985
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,18 @@
use matrix_sdk::{identifiers::UserId, Client, Session}; use matrix_sdk::{
ruma::{api::client::r0::alias, RoomAliasId, RoomId, UserId},
Client, Session, SyncSettings,
};
use rpassword::prompt_password_stderr; use rpassword::prompt_password_stderr;
use serde_lexpr;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fs::File;
use std::io::{self, Write}; use std::io::{self, Write};
static SESSION_FILE: &str = "session_info"; use crate::util::{build_client_config, restore_session, save_session};
pub async fn login(username: Option<&str>) -> Result<(), Box<dyn std::error::Error>> { type CommandResult = Result<(), Box<dyn std::error::Error>>;
let stdin = io::stdin();
macro_rules! room_fmt {() => {"{:30.30} | {:30.30} | {}"};}
pub async fn login(username: Option<&str>) -> CommandResult {
let user_id = match username { let user_id = match username {
Some(s) => UserId::try_from(s)?, Some(s) => UserId::try_from(s)?,
None => { None => {
@ -18,6 +21,7 @@ pub async fn login(username: Option<&str>) -> Result<(), Box<dyn std::error::Err
eprint!("Username: "); eprint!("Username: ");
io::stderr().flush().unwrap(); io::stderr().flush().unwrap();
let stdin = io::stdin();
stdin.read_line(&mut s)?; stdin.read_line(&mut s)?;
UserId::try_from(s.trim_end())? UserId::try_from(s.trim_end())?
} }
@ -25,17 +29,11 @@ pub async fn login(username: Option<&str>) -> Result<(), Box<dyn std::error::Err
let password = prompt_password_stderr("Password: ")?; let password = prompt_password_stderr("Password: ")?;
let client = Client::new_from_user_id(user_id.clone()).await?; let client =
println!( Client::new_from_user_id_with_config(user_id.clone(), build_client_config()).await?;
"{} logged in? {}",
client.homeserver().await,
client.logged_in().await
);
let response = client let response = client
.login(user_id.localpart(), &password, None, Some("mxadm")) .login(user_id.localpart(), &password, None, Some("mxadm"))
.await?; .await?;
println!("{:?}", response);
println!( println!(
"{} logged in? {}", "{} logged in? {}",
client.homeserver().await, client.homeserver().await,
@ -47,41 +45,56 @@ pub async fn login(username: Option<&str>) -> Result<(), Box<dyn std::error::Err
user_id: response.user_id, user_id: response.user_id,
device_id: response.device_id, device_id: response.device_id,
}; };
println!("{:?}", session_info); save_session(session_info)?;
let mut session_file = File::create(SESSION_FILE)?;
serde_lexpr::to_writer(&mut session_file, &session_info)?;
Ok(()) Ok(())
} }
pub async fn status() -> Result<(), Box<dyn std::error::Error>> { pub async fn status() -> CommandResult {
let session_file = match File::open(SESSION_FILE) { let client = restore_session().await?;
Ok(f) => f,
_ => {
println!("Not logged in: no session info file found");
return Ok(())
}
};
let session_info: Session = serde_lexpr::from_reader(session_file)?;
let client = Client::new_from_user_id(session_info.user_id.clone()).await?;
if let Err(e) = client.restore_login(session_info).await {
println!("Not logged in: unable to restore session; {}", e);
return Ok(())
}
// Need to make a query requiring a valid token to check session validity // Need to make a query requiring a valid token to check session validity
if let Ok(_) = client.devices().await { match client.devices().await {
println!( Ok(_) => {
"Logged in as {} ({}) with device ID {}", println!(
client.user_id().await.unwrap(), "Logged in as {} ({}) with device ID {}",
client.display_name().await?.unwrap(), client.user_id().await.unwrap(),
client.device_id().await.unwrap() client.display_name().await?.unwrap(),
); client.device_id().await.unwrap()
} else { );
println!("Not logged in"); }
Err(e) => println!("Not logged in: {:?}", e),
} }
Ok(()) Ok(())
} }
pub async fn list_rooms() -> CommandResult {
let client = restore_session().await?;
println!("Syncing...");
// client.sync_once(SyncSettings::default()).await?;
println!(" ...done");
println!("Joined rooms:");
println!(room_fmt!(), "Name", "Main alias", "Room ID");
println!(room_fmt!(), "----", "----------", "-------");
for r in client.joined_rooms() {
println!(
room_fmt!(),
r.display_name().await?,
r.canonical_alias().map_or("".into(), |a| a.into_string()),
r.room_id().as_str(),
);
}
Ok(())
}
pub async fn add_alias(room_id: &str, alias: &str) -> CommandResult {
let room_id = RoomId::try_from(room_id)?;
let alias_id = RoomAliasId::try_from(alias)?;
let client = restore_session().await?;
todo!()
}

View File

@ -2,6 +2,7 @@
extern crate clap; extern crate clap;
mod commands; mod commands;
mod util;
use clap::{App, SubCommand}; use clap::{App, SubCommand};
@ -23,15 +24,31 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.subcommand(SubCommand::with_name("logout").about("ends the current session")) .subcommand(SubCommand::with_name("logout").about("ends the current session"))
.subcommand(SubCommand::with_name("status").about("displays current session status")) .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("list-rooms").about("lists rooms available to the user"))
.subcommand(
SubCommand::with_name("add-alias")
.about("adds an alias to a room")
.args_from_usage(
"<room_id> 'The ID of the room to alias'
<alias> 'The new alias to add'",
),
)
.get_matches(); .get_matches();
match matches.subcommand() { match matches.subcommand() {
("login", Some(login_matches)) => commands::login(login_matches.value_of("user")).await?, ("login", Some(submatches)) => commands::login(submatches.value_of("user")).await?,
("logout", Some(_)) => println!("logging out..."),
("status", Some(_)) => commands::status().await?, ("status", Some(_)) => commands::status().await?,
("list-rooms", Some(_)) => println!("listing rooms..."), ("list-rooms", Some(_)) => commands::list_rooms().await?,
("", None) => println!("No subcommand given"), ("add-alias", Some(submatches)) => {
_ => unreachable!(), commands::add_alias(
submatches.value_of("room_id").unwrap(),
submatches.value_of("alias").unwrap(),
)
.await?
}
("", None) => eprintln!("No subcommand given"),
(c, _) => {
todo!("Subcommand '{}' not implemented yet!", c);
}
} }
Ok(()) Ok(())

26
src/util.rs Normal file
View File

@ -0,0 +1,26 @@
use matrix_sdk::{Client, ClientConfig, Session};
use serde_lexpr;
use std::fs::File;
static SESSION_FILE: &str = "session_info";
pub fn build_client_config() -> ClientConfig {
ClientConfig::new().store_path("./store")
}
pub fn save_session(session: Session) -> Result<(), Box<dyn std::error::Error>> {
let mut session_file = File::create(SESSION_FILE)?;
serde_lexpr::to_writer(&mut session_file, &session)?;
Ok(())
}
pub async fn restore_session() -> Result<Client, Box<dyn std::error::Error>> {
let session_file = File::open(SESSION_FILE)?;
let session_info: Session = serde_lexpr::from_reader(session_file)?;
let client =
Client::new_from_user_id_with_config(session_info.user_id.clone(), build_client_config())
.await?;
client.restore_login(session_info).await?;
Ok(client)
}