matrix-rust-sdk/bindings/matrix-sdk-ffi/src/client_builder.rs

168 lines
5.5 KiB
Rust

use std::{fs, path::PathBuf, sync::Arc};
use anyhow::anyhow;
use matrix_sdk::{
config::StoreConfig,
ruma::{
api::{error::UnknownVersionError, MatrixVersion},
ServerName, UserId,
},
Client as MatrixClient, ClientBuilder as MatrixClientBuilder,
};
use sanitize_filename_reader_friendly::sanitize;
use zeroize::Zeroizing;
use super::{client::Client, RUNTIME};
use crate::helpers::unwrap_or_clone_arc;
#[derive(Clone)]
pub struct ClientBuilder {
base_path: Option<String>,
username: Option<String>,
server_name: Option<String>,
homeserver_url: Option<String>,
server_versions: Option<Vec<String>>,
passphrase: Zeroizing<Option<String>>,
user_agent: Option<String>,
sliding_sync_proxy: Option<String>,
inner: MatrixClientBuilder,
}
#[uniffi::export]
impl ClientBuilder {
pub fn base_path(self: Arc<Self>, path: String) -> Arc<Self> {
let mut builder = unwrap_or_clone_arc(self);
builder.base_path = Some(path);
Arc::new(builder)
}
pub fn username(self: Arc<Self>, username: String) -> Arc<Self> {
let mut builder = unwrap_or_clone_arc(self);
builder.username = Some(username);
Arc::new(builder)
}
pub fn server_versions(self: Arc<Self>, versions: Vec<String>) -> Arc<Self> {
let mut builder = unwrap_or_clone_arc(self);
builder.server_versions = Some(versions);
Arc::new(builder)
}
pub fn server_name(self: Arc<Self>, server_name: String) -> Arc<Self> {
let mut builder = unwrap_or_clone_arc(self);
builder.server_name = Some(server_name);
Arc::new(builder)
}
pub fn homeserver_url(self: Arc<Self>, url: String) -> Arc<Self> {
let mut builder = unwrap_or_clone_arc(self);
builder.homeserver_url = Some(url);
Arc::new(builder)
}
pub fn passphrase(self: Arc<Self>, passphrase: Option<String>) -> Arc<Self> {
let mut builder = unwrap_or_clone_arc(self);
builder.passphrase = Zeroizing::new(passphrase);
Arc::new(builder)
}
pub fn user_agent(self: Arc<Self>, user_agent: String) -> Arc<Self> {
let mut builder = unwrap_or_clone_arc(self);
builder.user_agent = Some(user_agent);
Arc::new(builder)
}
pub fn sliding_sync_proxy(self: Arc<Self>, sliding_sync_proxy: Option<String>) -> Arc<Self> {
let mut builder = unwrap_or_clone_arc(self);
builder.sliding_sync_proxy = sliding_sync_proxy;
Arc::new(builder)
}
}
impl ClientBuilder {
pub fn new() -> Self {
Self {
base_path: None,
username: None,
server_name: None,
homeserver_url: None,
server_versions: None,
passphrase: Zeroizing::new(None),
user_agent: None,
sliding_sync_proxy: None,
inner: MatrixClient::builder(),
}
}
pub fn build(self: Arc<Self>) -> anyhow::Result<Arc<Client>> {
let builder = unwrap_or_clone_arc(self);
let mut inner_builder = builder.inner;
if let (Some(base_path), Some(username)) = (builder.base_path, &builder.username) {
// Determine store path
let data_path = PathBuf::from(base_path).join(sanitize(username));
fs::create_dir_all(&data_path)?;
let mut state_store =
matrix_sdk_sled::SledStateStore::builder().path(data_path.to_owned());
if let Some(passphrase) = builder.passphrase.as_deref() {
state_store = state_store.passphrase(passphrase.to_owned());
}
let state_store = state_store.build()?;
let crypto_store = RUNTIME.block_on(matrix_sdk_sqlite::SqliteCryptoStore::open(
&data_path,
builder.passphrase.as_deref(),
))?;
let store_config =
StoreConfig::new().state_store(state_store).crypto_store(crypto_store);
inner_builder = inner_builder.store_config(store_config)
}
// Determine server either from URL, server name or user ID.
if let Some(homeserver_url) = builder.homeserver_url {
inner_builder = inner_builder.homeserver_url(homeserver_url);
} else if let Some(server_name) = builder.server_name {
let server_name = ServerName::parse(server_name)?;
inner_builder = inner_builder.server_name(&server_name);
} else if let Some(username) = builder.username {
let user = UserId::parse(username)?;
inner_builder = inner_builder.server_name(user.server_name());
} else {
return Err(anyhow!(
"Failed to build: One of homeserver_url, server_name or username must be called."
));
}
if let Some(user_agent) = builder.user_agent {
inner_builder = inner_builder.user_agent(user_agent);
}
if let Some(server_versions) = builder.server_versions {
inner_builder = inner_builder.server_versions(
server_versions
.iter()
.map(|s| MatrixVersion::try_from(s.as_str()))
.collect::<Result<Vec<MatrixVersion>, UnknownVersionError>>()?,
);
}
RUNTIME.block_on(async move {
let client = inner_builder.build().await?;
let c = Client::new(client);
c.set_sliding_sync_proxy(builder.sliding_sync_proxy);
Ok(Arc::new(c))
})
}
}
impl Default for ClientBuilder {
fn default() -> Self {
Self::new()
}
}