matrix_ui_serializable/init/
login.rs

1use matrix_sdk::{Client, sliding_sync::VersionBuilder};
2
3use std::path::PathBuf;
4
5use rand::{Rng, distr::Alphanumeric, rng};
6use serde::{Deserialize, Serialize};
7
8use crate::init::singletons::CLIENT;
9
10use super::session::ClientSession;
11
12/// The user's account credentials to create a new Matrix session
13#[derive(Debug, Clone, Deserialize, Serialize)]
14pub struct MatrixClientConfig {
15    username: String,
16    password: String,
17    homeserver_url: String,
18    client_name: String,
19}
20
21impl MatrixClientConfig {
22    pub fn new(
23        username: String,
24        password: String,
25        homeserver_url: String,
26        client_name: String,
27    ) -> Self {
28        MatrixClientConfig {
29            username,
30            password,
31            homeserver_url,
32            client_name,
33        }
34    }
35}
36
37/// Details of a login request that get submitted when calling login command
38pub enum LoginRequest {
39    LoginByPassword(MatrixClientConfig),
40}
41
42pub async fn get_client_from_new_session(
43    login_request: LoginRequest,
44    app_data_dir: PathBuf,
45) -> anyhow::Result<(Client, String)> {
46    let matrix_config = match login_request {
47        LoginRequest::LoginByPassword(config) => config,
48        // TODO: add new login ways
49    };
50
51    let client_initial_state = login_and_persist_session(&matrix_config, app_data_dir).await?;
52
53    CLIENT
54        .set(client_initial_state.0.clone())
55        .expect("BUG: CLIENT already set!");
56
57    Ok(client_initial_state)
58}
59
60async fn login_and_persist_session(
61    config: &MatrixClientConfig,
62    app_data_dir: PathBuf,
63) -> anyhow::Result<(Client, String)> {
64    let (client, client_session) = build_client(config, app_data_dir).await?;
65
66    let matrix_auth = client.matrix_auth();
67
68    matrix_auth
69        .login_username(&config.username, &config.password)
70        .initial_device_display_name(&config.client_name)
71        .await?;
72
73    let user_session = matrix_auth
74        .session()
75        .expect("Should have session after login");
76
77    let full = super::session::FullMatrixSession::new(client_session, user_session);
78    let serialized = serde_json::to_string(&full)?;
79
80    Ok((client, serialized))
81}
82
83async fn build_client(
84    config: &MatrixClientConfig,
85    app_data_dir: PathBuf,
86) -> anyhow::Result<(Client, ClientSession)> {
87    let db_subfolder: String = rng()
88        .sample_iter(Alphanumeric)
89        .take(7)
90        .map(char::from)
91        .collect();
92    let db_path = app_data_dir.join("matrix-db").join(db_subfolder);
93
94    std::fs::create_dir_all(&db_path)?;
95
96    let passphrase: String = rng()
97        .sample_iter(Alphanumeric)
98        .take(32)
99        .map(char::from)
100        .collect();
101
102    let client = Client::builder()
103        .homeserver_url(&config.homeserver_url)
104        .sqlite_store(&db_path, Some(&passphrase))
105        .sliding_sync_version_builder(VersionBuilder::DiscoverNative) // Comment this if your homeserver doesn't support simplified sliding sync.
106        .handle_refresh_tokens()
107        .build()
108        .await?;
109
110    let client_session = ClientSession::new(config.homeserver_url.clone(), db_path, passphrase);
111
112    Ok((client, client_session))
113}