From 02809e218bb94750867488fd08f9dd647f1754bc Mon Sep 17 00:00:00 2001 From: Kevin Boos Date: Thu, 26 Sep 2024 12:07:28 -0700 Subject: [PATCH] Use `robius-directories` crate to support persistence on Android Fix CLI to accept server names instead of only fully-formed URLs. Allow specifying the homserver on both the CLI and in `login.toml`. --- Cargo.lock | 32 ++++++++++++++++++++++---------- Cargo.toml | 5 ++++- login.toml | 4 +++- src/app.rs | 5 +++++ src/event_preview.rs | 2 +- src/lib.rs | 2 +- src/persistent_state.rs | 4 ++-- src/sliding_sync.rs | 35 +++++++++++++++++++++-------------- 8 files changed, 59 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8d5970e2..02d3a429 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -826,15 +826,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "directories" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" -dependencies = [ - "dirs-sys", -] - [[package]] name = "dirs-sys" version = "0.4.1" @@ -3077,6 +3068,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "312584c40c0d996c96a0c8498c6e556c38ca5785eda670ae11ba12fe2e556c4f" dependencies = [ "jni", + "makepad-android-state", +] + +[[package]] +name = "robius-directories" +version = "5.0.1" +source = "git+https://github.com/project-robius/robius-directories?branch=robius#a7ac6b7b137232f5a835b4d4946a07f9dda05c3d" +dependencies = [ + "dirs-sys", + "jni", + "robius-android-env", ] [[package]] @@ -3092,6 +3094,15 @@ dependencies = [ "robius-android-env", ] +[[package]] +name = "robius-use-makepad" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dc404c4111c88cd9f8a409b2831d13fe93e5242c95939a3852e7e7d675f89c4" +dependencies = [ + "robius-android-env", +] + [[package]] name = "robrix" version = "0.0.1-pre-alpha" @@ -3101,7 +3112,6 @@ dependencies = [ "clap", "crossbeam-channel", "crossbeam-queue", - "directories", "emojis", "eyeball", "eyeball-im", @@ -3114,7 +3124,9 @@ dependencies = [ "matrix-sdk-ui", "rand", "rangemap", + "robius-directories", "robius-open", + "robius-use-makepad", "serde", "serde_json", "tokio", diff --git a/Cargo.toml b/Cargo.toml index f64f1455..563b53b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,8 +17,11 @@ metadata.makepad-auto-version = "zqpv-Yj-K7WNVK2I8h5Okhho46Q=" [dependencies] makepad-widgets = { git = "https://github.com/makepad/makepad", branch = "rik" } -directories = "5.0.1" +## Including this crate automatically configures all `robius-*` crates to work with Makepad. +robius-use-makepad = "0.1.0" robius-open = "0.1.0" +## A fork of the `directories` crate that adds support for Android by using our `robius-android-env` crate. +robius-directories = { git = "https://github.com/project-robius/robius-directories", branch = "robius"} anyhow = "1.0" chrono = "0.4" diff --git a/login.toml b/login.toml index 6d1d30e9..e5ec2440 100644 --- a/login.toml +++ b/login.toml @@ -1,7 +1,9 @@ username = " " password = " " +homeserver = " " ### Please fill in your username and password above. +### The homeserver name/URL field is optional, but defaults to "matrix.org". ### ### Robrix does not yet have a login splash screen. ### Thus, on desktop platforms, we allow the user to @@ -12,7 +14,7 @@ password = " " ### Instead, we enable the mobile apps to read them from a copy ### of this file that is included in the app package files. ### -### Only the two username and password fields are supported. +### Only the username, password, and homeserver fields are supported. ### ### Note that for obvious reasons you should not commit this file ### or upload it to a public repo with your actual username and password in it. diff --git a/src/app.rs b/src/app.rs index 58df8925..77cd32ba 100644 --- a/src/app.rs +++ b/src/app.rs @@ -137,6 +137,11 @@ impl LiveHook for App { } impl MatchEvent for App { fn handle_startup(&mut self, _cx: &mut Cx) { + // Initialize the project directory here from the main UI thread + // such that background threads/tasks will be able to can access it. + let _app_data_dir = crate::app_data_dir(); + log!("App::handle_startup(): app_data_dir: {:?}", _app_data_dir); + log!("App::handle_startup(): starting matrix sdk loop"); crate::sliding_sync::start_matrix_tokio().unwrap(); } diff --git a/src/event_preview.rs b/src/event_preview.rs index c585b6b5..afff566f 100644 --- a/src/event_preview.rs +++ b/src/event_preview.rs @@ -281,7 +281,7 @@ pub fn text_preview_of_other_state( HistoryVisibility::Shared => "joined users, for all of time.", HistoryVisibility::WorldReadable | _ => "anyone for all time.", }; - Some(format!("set this room's history to be visible by {}.", visibility)) + Some(format!("set this room's history to be visible by {}", visibility)) } AnyOtherFullStateEventContent::RoomJoinRules(FullStateEventContent::Original { content, .. }) => { Some(match content.join_rule { diff --git a/src/lib.rs b/src/lib.rs index 6f42fac6..7c9b8df1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ use std::{path::Path, sync::OnceLock}; -use directories::ProjectDirs; +use robius_directories::ProjectDirs; pub use makepad_widgets; pub mod app; diff --git a/src/persistent_state.rs b/src/persistent_state.rs index 52da25bc..71edd5ed 100644 --- a/src/persistent_state.rs +++ b/src/persistent_state.rs @@ -1,7 +1,7 @@ //! Handles app persistence by saving and restoring client session data to/from the filesystem. use std::{ - path::{Path, PathBuf}, + path::PathBuf, }; use anyhow::{anyhow, bail}; use makepad_widgets::log; @@ -110,7 +110,7 @@ pub async fn restore_session( // Build the client with the previous settings from the session. let client = Client::builder() - .homeserver_url(client_session.homeserver) + .server_name_or_homeserver_url(client_session.homeserver) .sqlite_store(client_session.db_path, Some(&client_session.passphrase)) .simplified_sliding_sync(false) .build() diff --git a/src/sliding_sync.rs b/src/sliding_sync.rs index f65aee1d..cd57a412 100644 --- a/src/sliding_sync.rs +++ b/src/sliding_sync.rs @@ -16,12 +16,10 @@ use tokio::{ }; use unicode_segmentation::UnicodeSegmentation; use std::{cmp::{max, min}, collections::{BTreeMap, BTreeSet}, ops::Range, path:: Path, sync::{Arc, Mutex, OnceLock}}; -use url::Url; use crate::{ app_data_dir, avatar_cache::AvatarUpdate, event_preview::text_preview_of_timeline_item, home::{ - room_screen::TimelineUpdate, - rooms_list::{self, enqueue_rooms_list_update, RoomPreviewAvatar, RoomPreviewEntry, RoomsListUpdate}, + room_screen::TimelineUpdate, rooms_list::{self, enqueue_rooms_list_update, RoomPreviewAvatar, RoomPreviewEntry, RoomsListUpdate} }, media_cache::MediaCacheEntry, persistent_state::{self, ClientSessionPersisted}, profile::{ user_profile::{AvatarState, UserProfile}, user_profile_cache::{enqueue_user_profile_update, UserProfileUpdate}, @@ -41,11 +39,11 @@ struct Cli { /// The homeserver to connect to. #[clap(value_parser)] - homeserver: Option, + homeserver: Option, /// Set the proxy that should be used for the connection. #[clap(short, long)] - proxy: Option, + proxy: Option, /// Enable verbose logging output. #[clap(short, long, action)] @@ -74,13 +72,12 @@ async fn build_client( .collect() }; - let homeserver_url = cli.homeserver.as_ref() - .map(|h| h.as_str()) + let homeserver_url = cli.homeserver.as_deref() .unwrap_or("https://matrix-client.matrix.org/"); // .unwrap_or("https://matrix.org/"); let mut builder = Client::builder() - .homeserver_url(homeserver_url) + .server_name_or_homeserver_url(homeserver_url) // Use a sqlite database to persist the client's encryption setup. .sqlite_store(&db_path, Some(&passphrase)) // The matrix homeserver's sliding sync proxy doesn't support Simplified MSC3575. @@ -763,10 +760,12 @@ async fn async_main_loop() -> Result<()> { let start = std::time::Instant::now(); let cli = Cli::try_parse().ok().or_else(|| { - // Quickly try to parse the username and password fields from "login.toml". + // Quickly try to parse the username, password, and homeserver fields from "login.toml". let login_file = std::include_str!("../login.toml"); let mut username = None; let mut password = None; + let mut homeserver = None; + let mut homeserver_found = false; for line in login_file.lines() { if line.starts_with("username") { username = line.find('=') @@ -778,7 +777,16 @@ async fn async_main_loop() -> Result<()> { .and_then(|i| line.get((i + 1) ..)) .map(|s| s.trim().trim_matches('"').trim().to_string()); } - if username.is_some() && password.is_some() { + if line.starts_with("homeserver") { + homeserver_found = true; + homeserver = line.find('=') + .and_then(|i| line.get((i + 1) ..)) + .map(|s| s.trim().trim_matches('"').trim().to_string()); + if homeserver.as_ref().is_some_and(|h| h.is_empty()) { + homeserver = None; + } + } + if username.is_some() && password.is_some() && homeserver_found { break; } } @@ -786,11 +794,11 @@ async fn async_main_loop() -> Result<()> { if username.is_empty() || password.is_empty() { None } else { - log!("Parsed username: {username:?} and password."); + log!("Parsed username and password from 'login.toml': {username:?}, homeserver: {homeserver:?}"); Some(Cli { username, password, - homeserver: None, + homeserver, proxy: None, verbose: false, }) @@ -815,8 +823,7 @@ async fn async_main_loop() -> Result<()> { let specified_username: Option = cli.username.to_string().try_into().ok() .or_else(|| { - let homeserver_url = cli.homeserver.as_ref() - .and_then(|u| u.host_str()) + let homeserver_url = cli.homeserver.as_deref() .unwrap_or("matrix.org"); let user_id_str = if cli.username.starts_with("@") { format!("{}:{}", cli.username, homeserver_url)