Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic support for login detection to the FFI. #774

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bindings/matrix-sdk-ffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ tracing = "0.1.32"
# keep in sync with uniffi dependency in matrix-sdk-crypto-ffi, and uniffi_bindgen in ffi CI job
uniffi = "0.18.0"
uniffi_macros = "0.18.0"
url = "2.2.2"
15 changes: 14 additions & 1 deletion bindings/matrix-sdk-ffi/src/api.udl
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
namespace sdk {
[Throws=ClientError]
Client login_new_client(string base_path, string username, string password);
Client new_client(string homeserver);

[Throws=ClientError]
Client discover_client(string domain);

[Throws=ClientError]
Client guest_client(string base_path, string homeserver);

[Throws=ClientError]
Client login_with_token(string base_path, string restore_token);

[Throws=ClientError]
Client login_new_client(string base_path, string username, string password);

MediaSource media_source_from_url(string url);
MessageEventContent message_event_content_from_markdown(string md);
string gen_transaction_id();
Expand All @@ -24,6 +30,13 @@ callback interface ClientDelegate {

interface Client {
void set_delegate(ClientDelegate? delegate);

[Throws=ClientError]
boolean supports_password_login();

string homeserver();

string? authentication_server();

void start_sync();

Expand Down
23 changes: 23 additions & 0 deletions bindings/matrix-sdk-ffi/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use matrix_sdk::{
ruma::{
api::client::{
filter::{FilterDefinition, LazyLoadOptions, RoomEventFilter, RoomFilter},
session::get_login_types,
sync::sync_events::v3::Filter,
},
events::room::MediaSource,
Expand Down Expand Up @@ -48,6 +49,28 @@ impl Client {
*self.delegate.write() = delegate;
}

pub fn supports_password_login(&self) -> anyhow::Result<bool> {
RUNTIME.block_on(async move {
let login_types = self.client.get_login_types().await?;
let supports_password = login_types.flows.iter().any(|login_type| match login_type {
get_login_types::v3::LoginType::Password(_) => true,
_ => false,
});
Ok(supports_password)
})
}

/// The homeserver address of this client.
pub fn homeserver(&self) -> String {
RUNTIME.block_on(async move { self.client.homeserver().await.to_string() })
}

pub fn authentication_server(&self) -> Option<String> {
RUNTIME.block_on(async move {
self.client.authentication_server().await.map(|server| server.to_string())
})
}

pub fn start_sync(&self) {
let client = self.client.clone();
let state = self.state.clone();
Expand Down
36 changes: 35 additions & 1 deletion bindings/matrix-sdk-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@ mod uniffi_api;
use std::{fs, path, sync::Arc};

use client::Client;
use matrix_sdk::{store::make_store_config, Client as MatrixClient, ClientBuilder, Session};
use matrix_sdk::{
ruma::ServerName, store::make_store_config, Client as MatrixClient, ClientBuilder, Session,
};
use once_cell::sync::Lazy;
use sanitize_filename_reader_friendly::sanitize;
use serde::{Deserialize, Serialize};
use tokio::runtime::Runtime;
pub use uniffi_api::*;
use url::Url;

pub static RUNTIME: Lazy<Runtime> =
Lazy::new(|| Runtime::new().expect("Can't start Tokio runtime"));
Expand All @@ -25,6 +28,37 @@ pub use matrix_sdk::ruma::{api::client::account::register, UserId};

pub use self::{backward_stream::*, client::*, messages::*, room::*};

/// Create a new [`Client`] that will use the given homeserver.
///
/// # Arguments
///
/// * `homeserver` - The homeserver's URL as a string.
pub fn new_client(homeserver: String) -> anyhow::Result<Arc<Client>> {
RUNTIME.block_on(async move {
let homeserver_url = Url::parse(&homeserver)?;
let client = MatrixClient::new(homeserver_url).await?;
let state = ClientState::default();

Ok(Arc::new(Client::new(client, state)))
})
}

/// Create a new [`Client`] that will discover a homeserver for the given
/// domain.
///
/// # Arguments
///
/// * `domain` - The domain the client should use for discovery.
pub fn discover_client(domain: String) -> anyhow::Result<Arc<Client>> {
RUNTIME.block_on(async move {
let server_name = ServerName::parse(domain).unwrap();
let client = MatrixClient::discover(&server_name).await?;
let state = ClientState::default();

Ok(Arc::new(Client::new(client, state)))
})
}

pub fn guest_client(base_path: String, homeurl: String) -> anyhow::Result<Arc<Client>> {
let builder = new_client_builder(base_path, homeurl.clone())?.homeserver_url(&homeurl);
let mut guest_registration = register::v3::Request::new();
Expand Down
7 changes: 7 additions & 0 deletions crates/matrix-sdk/src/client/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ impl ClientBuilder {
let base_client = BaseClient::with_store_config(self.store_config);
let http_client = HttpClient::new(inner_http_client.clone(), self.request_config);

let mut authentication_server: Option<Url> = None;
let homeserver = match homeserver_cfg {
HomeserverConfig::Url(url) => url,
HomeserverConfig::ServerName(server_name) => {
Expand All @@ -313,14 +314,20 @@ impl ClientBuilder {
err => ClientBuildError::Http(err),
})?;

if let Some(base_url) = well_known.identity_server.map(|server| server.base_url) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the identity_server for now as a placeholder for testing.

authentication_server = Url::parse(&base_url).ok();
};

well_known.homeserver.base_url
}
};

let homeserver = RwLock::new(Url::parse(&homeserver)?);
let authentication_server = authentication_server.map(|server| RwLock::new(server));

let inner = Arc::new(ClientInner {
homeserver,
authentication_server,
http_client,
base_client,
server_versions: OnceCell::new_with(self.server_versions),
Expand Down
24 changes: 24 additions & 0 deletions crates/matrix-sdk/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ pub struct Client {
pub(crate) struct ClientInner {
/// The URL of the homeserver to connect to.
homeserver: RwLock<Url>,
/// The URL of the authentication server to connect to.
authentication_server: Option<RwLock<Url>>,
/// The underlying HTTP client.
http_client: HttpClient,
/// User session data.
Expand Down Expand Up @@ -192,6 +194,20 @@ impl Client {
.map_err(ClientBuildError::assert_valid_builder_args)
}

/// Create a new [`Client`] that will discover a homeserver from the given
/// server name.
///
/// # Arguments
///
/// * `server_name` - The server name the client should use for discovery.
pub async fn discover(server_name: &ServerName) -> Result<Self, HttpError> {
Self::builder()
.server_name(server_name)
.build()
.await
.map_err(ClientBuildError::assert_valid_builder_args)
}

/// Create a new [`ClientBuilder`].
pub fn builder() -> ClientBuilder {
ClientBuilder::new()
Expand Down Expand Up @@ -272,6 +288,14 @@ impl Client {
self.inner.homeserver.read().await.clone()
}

/// The authentication server of the client.
pub async fn authentication_server(&self) -> Option<Url> {
if let Some(server) = &self.inner.authentication_server {
return Some(server.read().await.clone());
}
return None;
}

/// Get the user id of the current owner of the client.
pub fn user_id(&self) -> Option<&UserId> {
self.session().map(|s| s.user_id.as_ref())
Expand Down