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

feat(sdk): Welcome sliding_sync::Version and sliding_sync::VersionBuilder #3889

Merged
merged 11 commits into from
Aug 27, 2024
12 changes: 6 additions & 6 deletions .github/workflows/bindings_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,12 @@ jobs:
- name: Build Framework
run: target/debug/xtask swift build-framework --target=aarch64-apple-ios

complement-crypto:
name: "Run Complement Crypto tests"
uses: matrix-org/complement-crypto/.github/workflows/single_sdk_tests.yml@main
with:
use_rust_sdk: "." # use local checkout
use_complement_crypto: "MATCHING_BRANCH"
#complement-crypto:
# name: "Run Complement Crypto tests"
# uses: matrix-org/complement-crypto/.github/workflows/single_sdk_tests.yml@main
# with:
# use_rust_sdk: "." # use local checkout
# use_complement_crypto: "MATCHING_BRANCH"

test-crypto-apple-framework-generation:
name: Generate Crypto FFI Apple XCFramework
Expand Down
11 changes: 5 additions & 6 deletions bindings/matrix-sdk-ffi/src/authentication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ use matrix_sdk::{
};
use url::Url;

use crate::client::Client;
use crate::client::{Client, SlidingSyncVersion};

#[derive(uniffi::Object)]
pub struct HomeserverLoginDetails {
pub(crate) url: String,
pub(crate) sliding_sync_proxy: Option<String>,
pub(crate) sliding_sync_version: SlidingSyncVersion,
pub(crate) supports_oidc_login: bool,
pub(crate) supports_password_login: bool,
}
Expand All @@ -36,10 +36,9 @@ impl HomeserverLoginDetails {
self.url.clone()
}

/// The URL of the discovered or manually set sliding sync proxy,
/// if any.
pub fn sliding_sync_proxy(&self) -> Option<String> {
self.sliding_sync_proxy.clone()
/// The sliding sync version.
pub fn sliding_sync_version(&self) -> SlidingSyncVersion {
self.sliding_sync_version.clone()
}

/// Whether the current homeserver supports login using OIDC.
Expand Down
87 changes: 60 additions & 27 deletions bindings/matrix-sdk-ffi/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use matrix_sdk::{
serde::Raw,
EventEncryptionAlgorithm, RoomId, TransactionId, UInt, UserId,
},
sliding_sync::Version as SdkSlidingSyncVersion,
AuthApi, AuthSession, Client as MatrixClient, SessionChange, SessionTokens,
};
use matrix_sdk_ui::notification_client::{
Expand Down Expand Up @@ -261,11 +262,11 @@ impl Client {
pub async fn homeserver_login_details(&self) -> Arc<HomeserverLoginDetails> {
let supports_oidc_login = self.inner.oidc().fetch_authentication_issuer().await.is_ok();
let supports_password_login = self.supports_password_login().await.ok().unwrap_or(false);
let sliding_sync_proxy = self.sliding_sync_proxy().map(|proxy_url| proxy_url.to_string());
let sliding_sync_version = self.sliding_sync_version();

Arc::new(HomeserverLoginDetails {
url: self.homeserver(),
sliding_sync_proxy,
sliding_sync_version,
supports_oidc_login,
supports_password_login,
})
Expand Down Expand Up @@ -383,19 +384,11 @@ impl Client {

/// Restores the client from a `Session`.
pub async fn restore_session(&self, session: Session) -> Result<(), ClientError> {
let sliding_sync_proxy = session.sliding_sync_proxy.clone();
let sliding_sync_version = session.sliding_sync_version.clone();
let auth_session: AuthSession = session.try_into()?;

self.restore_session_inner(auth_session).await?;

if !self.inner.is_simplified_sliding_sync_enabled() {
if let Some(sliding_sync_proxy) = sliding_sync_proxy {
let sliding_sync_proxy = Url::parse(&sliding_sync_proxy)
.map_err(|error| ClientError::Generic { msg: error.to_string() })?;

self.inner.set_sliding_sync_proxy(Some(sliding_sync_proxy));
}
}
self.inner.set_sliding_sync_version(sliding_sync_version.try_into()?);

Ok(())
}
Expand Down Expand Up @@ -467,13 +460,6 @@ impl Client {
Ok(())
}

/// The sliding sync proxy of the homeserver. It is either set automatically
/// during discovery or manually via `set_sliding_sync_proxy` or `None`
/// when not configured.
pub fn sliding_sync_proxy(&self) -> Option<Url> {
self.inner.sliding_sync_proxy()
}

/// Whether or not the client's homeserver supports the password login flow.
pub(crate) async fn supports_password_login(&self) -> anyhow::Result<bool> {
let login_types = self.inner.matrix_auth().get_login_types().await?;
Expand All @@ -487,6 +473,22 @@ impl Client {

#[uniffi::export(async_runtime = "tokio")]
impl Client {
/// The sliding sync version.
pub fn sliding_sync_version(&self) -> SlidingSyncVersion {
self.inner.sliding_sync_version().into()
}

/// Find all sliding sync versions that are available.
///
/// Be careful: This method may hit the store and will send new requests for
/// each call. It can be costly to call it repeatedly.
///
/// If `.well-known` or `/versions` is unreachable, it will simply move
/// potential sliding sync versions aside. No error will be reported.
pub async fn available_sliding_sync_versions(&self) -> Vec<SlidingSyncVersion> {
self.inner.available_sliding_sync_versions().await.into_iter().map(Into::into).collect()
}

pub fn set_delegate(
self: Arc<Self>,
delegate: Option<Box<dyn ClientDelegate>>,
Expand Down Expand Up @@ -1083,9 +1085,9 @@ impl Client {
let auth_api = client.auth_api().context("Missing authentication API")?;

let homeserver_url = client.homeserver().into();
let sliding_sync_proxy = client.sliding_sync_proxy().map(|url| url.to_string());
let sliding_sync_version = client.sliding_sync_version();

Session::new(auth_api, homeserver_url, sliding_sync_proxy)
Session::new(auth_api, homeserver_url, sliding_sync_version.into())
}

fn save_session(
Expand Down Expand Up @@ -1312,15 +1314,15 @@ pub struct Session {
/// Additional data for this session if OpenID Connect was used for
/// authentication.
pub oidc_data: Option<String>,
/// The URL for the sliding sync proxy used for this session.
pub sliding_sync_proxy: Option<String>,
/// The sliding sync version used for this session.
pub sliding_sync_version: SlidingSyncVersion,
}

impl Session {
fn new(
auth_api: AuthApi,
homeserver_url: String,
sliding_sync_proxy: Option<String>,
sliding_sync_version: SlidingSyncVersion,
) -> Result<Session, ClientError> {
match auth_api {
// Build the session from the regular Matrix Auth Session.
Expand All @@ -1338,7 +1340,7 @@ impl Session {
device_id: device_id.to_string(),
homeserver_url,
oidc_data: None,
sliding_sync_proxy,
sliding_sync_version,
})
}
// Build the session from the OIDC UserSession.
Expand Down Expand Up @@ -1375,7 +1377,7 @@ impl Session {
device_id: device_id.to_string(),
homeserver_url,
oidc_data,
sliding_sync_proxy,
sliding_sync_version,
})
}
_ => Err(anyhow!("Unknown authentication API").into()),
Expand All @@ -1393,7 +1395,7 @@ impl TryFrom<Session> for AuthSession {
device_id,
homeserver_url: _,
oidc_data,
sliding_sync_proxy: _,
sliding_sync_version: _,
} = value;

if let Some(oidc_data) = oidc_data {
Expand Down Expand Up @@ -1581,3 +1583,34 @@ impl MediaFileHandle {
)
}
}

#[derive(Clone, uniffi::Enum)]
pub enum SlidingSyncVersion {
None,
Proxy { url: String },
Native,
}

impl From<SdkSlidingSyncVersion> for SlidingSyncVersion {
fn from(value: SdkSlidingSyncVersion) -> Self {
match value {
SdkSlidingSyncVersion::None => Self::None,
SdkSlidingSyncVersion::Proxy { url } => Self::Proxy { url: url.to_string() },
SdkSlidingSyncVersion::Native => Self::Native,
}
}
}

impl TryFrom<SlidingSyncVersion> for SdkSlidingSyncVersion {
type Error = ClientError;

fn try_from(value: SlidingSyncVersion) -> Result<Self, Self::Error> {
Ok(match value {
SlidingSyncVersion::None => Self::None,
SlidingSyncVersion::Proxy { url } => Self::Proxy {
url: Url::parse(&url).map_err(|e| ClientError::Generic { msg: e.to_string() })?,
},
SlidingSyncVersion::Native => Self::Native,
})
}
}
94 changes: 55 additions & 39 deletions bindings/matrix-sdk-ffi/src/client_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,16 @@ use matrix_sdk::{
encryption::{BackupDownloadStrategy, EncryptionSettings},
reqwest::Certificate,
ruma::{ServerName, UserId},
sliding_sync::{
Error as MatrixSlidingSyncError, VersionBuilder as MatrixSlidingSyncVersionBuilder,
VersionBuilderError,
},
Client as MatrixClient, ClientBuildError as MatrixClientBuildError, HttpError, IdParseError,
RumaApiError,
};
use ruma::api::error::{DeserializationError, FromHttpResponseError};
use tracing::{debug, error};
use url::Url;
use zeroize::Zeroizing;

use super::{client::Client, RUNTIME};
Expand Down Expand Up @@ -78,7 +83,7 @@ pub enum HumanQrLoginError {
Declined,
#[error("An unknown error has happened.")]
Unknown,
#[error("The homeserver doesn't provide a sliding sync proxy in its configuration.")]
#[error("The homeserver doesn't provide sliding sync in its configuration.")]
SlidingSyncNotAvailable,
#[error("Unable to use OIDC as the supplied client metadata is invalid.")]
OidcMetadataInvalid,
Expand Down Expand Up @@ -190,12 +195,13 @@ pub enum ClientBuildError {
WellKnownLookupFailed(RumaApiError),
#[error(transparent)]
WellKnownDeserializationError(DeserializationError),
#[error("The homeserver doesn't provide a trusted sliding sync proxy in its well-known configuration.")]
SlidingSyncNotAvailable,

#[error(transparent)]
#[allow(dead_code)] // rustc's drunk, this is used
SlidingSync(MatrixSlidingSyncError),
#[error(transparent)]
SlidingSyncVersion(VersionBuilderError),
#[error(transparent)]
Sdk(MatrixClientBuildError),

#[error("Failed to build the client: {message}")]
Generic { message: String },
}
Expand All @@ -211,10 +217,9 @@ impl From<MatrixClientBuildError> for ClientBuildError {
MatrixClientBuildError::AutoDiscovery(FromHttpResponseError::Deserialization(e)) => {
ClientBuildError::WellKnownDeserializationError(e)
}
MatrixClientBuildError::SlidingSyncNotAvailable => {
ClientBuildError::SlidingSyncNotAvailable
MatrixClientBuildError::SlidingSyncVersion(e) => {
ClientBuildError::SlidingSyncVersion(e)
}

_ => ClientBuildError::Sdk(e),
}
}
Expand Down Expand Up @@ -251,9 +256,7 @@ pub struct ClientBuilder {
homeserver_cfg: Option<HomeserverConfig>,
passphrase: Zeroizing<Option<String>>,
user_agent: Option<String>,
requires_sliding_sync: bool,
sliding_sync_proxy: Option<String>,
is_simplified_sliding_sync_enabled: bool,
sliding_sync_version_builder: SlidingSyncVersionBuilder,
proxy: Option<String>,
disable_ssl_verification: bool,
disable_automatic_token_refresh: bool,
Expand All @@ -276,10 +279,7 @@ impl ClientBuilder {
homeserver_cfg: None,
passphrase: Zeroizing::new(None),
user_agent: None,
requires_sliding_sync: false,
sliding_sync_proxy: None,
// By default, Simplified MSC3575 is turned off.
is_simplified_sliding_sync_enabled: false,
sliding_sync_version_builder: SlidingSyncVersionBuilder::None,
proxy: None,
disable_ssl_verification: false,
disable_automatic_token_refresh: false,
Expand Down Expand Up @@ -365,21 +365,12 @@ impl ClientBuilder {
Arc::new(builder)
}

pub fn requires_sliding_sync(self: Arc<Self>) -> Arc<Self> {
let mut builder = unwrap_or_clone_arc(self);
builder.requires_sliding_sync = true;
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)
}

pub fn simplified_sliding_sync(self: Arc<Self>, enable: bool) -> Arc<Self> {
pub fn sliding_sync_version_builder(
self: Arc<Self>,
version_builder: SlidingSyncVersionBuilder,
) -> Arc<Self> {
let mut builder = unwrap_or_clone_arc(self);
builder.is_simplified_sliding_sync_enabled = enable;
builder.sliding_sync_version_builder = version_builder;
Arc::new(builder)
}

Expand Down Expand Up @@ -550,15 +541,31 @@ impl ClientBuilder {
.with_encryption_settings(builder.encryption_settings)
.with_room_key_recipient_strategy(builder.room_key_recipient_strategy);

if let Some(sliding_sync_proxy) = builder.sliding_sync_proxy {
inner_builder = inner_builder.sliding_sync_proxy(sliding_sync_proxy);
}

inner_builder =
inner_builder.simplified_sliding_sync(builder.is_simplified_sliding_sync_enabled);

if builder.requires_sliding_sync {
inner_builder = inner_builder.requires_sliding_sync();
match builder.sliding_sync_version_builder {
SlidingSyncVersionBuilder::None => {
inner_builder = inner_builder
.sliding_sync_version_builder(MatrixSlidingSyncVersionBuilder::None)
}
SlidingSyncVersionBuilder::Proxy { url } => {
inner_builder = inner_builder.sliding_sync_version_builder(
MatrixSlidingSyncVersionBuilder::Proxy {
url: Url::parse(&url)
.map_err(|e| ClientBuildError::Generic { message: e.to_string() })?,
},
)
}
SlidingSyncVersionBuilder::Native => {
inner_builder = inner_builder
.sliding_sync_version_builder(MatrixSlidingSyncVersionBuilder::Native)
}
SlidingSyncVersionBuilder::DiscoverProxy => {
inner_builder = inner_builder
.sliding_sync_version_builder(MatrixSlidingSyncVersionBuilder::DiscoverProxy)
}
SlidingSyncVersionBuilder::DiscoverNative => {
inner_builder = inner_builder
.sliding_sync_version_builder(MatrixSlidingSyncVersionBuilder::DiscoverNative)
}
}

if let Some(config) = builder.request_config {
Expand Down Expand Up @@ -619,7 +626,7 @@ impl ClientBuilder {
let builder = self.server_name_or_homeserver_url(server_name.to_owned());

let client = builder.build().await.map_err(|e| match e {
ClientBuildError::SlidingSyncNotAvailable => HumanQrLoginError::SlidingSyncNotAvailable,
ClientBuildError::SlidingSync(_) => HumanQrLoginError::SlidingSyncNotAvailable,
_ => {
error!("Couldn't build the client {e:?}");
HumanQrLoginError::Unknown
Expand Down Expand Up @@ -660,3 +667,12 @@ pub struct RequestConfig {
/// Base delay between retries.
retry_timeout: Option<u64>,
}

#[derive(Clone, uniffi::Enum)]
pub enum SlidingSyncVersionBuilder {
None,
Proxy { url: String },
Native,
DiscoverProxy,
DiscoverNative,
}
Loading
Loading