use std::sync::{Arc, Mutex};
use ffi_sdk::BoxedIdentityConfig;
use crate::{
ditto::AppId,
error::{DittoError, ErrorKind},
};
use_prelude!();
#[doc(hidden)]
pub mod auth;
use self::auth::LoginProvider;
pub use self::auth::{
AuthenticationClientFeedback, DittoAuthenticationEventHandler, DittoAuthenticator,
};
#[doc(hidden)]
pub trait Identity: private::Sealed + Send + Sync {
fn identity_config(&self) -> Option<BoxedIdentityConfig>;
fn involves_authenticator(&self) -> bool {
false
}
fn set_login_provider_with_ditto_pointer(
&self,
_ditto_fields: &Arc<crate::ditto::DittoFields>,
) {
}
fn is_cloud_sync_enabled(&self) -> bool;
fn auth_url(&self) -> Result<String, DittoError>;
fn sync_url(&self) -> Result<String, DittoError>;
fn requires_offline_only_license_token(&self) -> bool;
}
pub struct OnlineWithAuthentication {
app_id: AppId,
enable_cloud_sync: bool,
auth_url: String,
identity_config: Mutex<Option<BoxedIdentityConfig>>,
auth_event_handler: Arc<dyn 'static + DittoAuthenticationEventHandler>,
}
#[doc(hidden)]
#[deprecated(note = "use OnlinePlayground instead")]
pub type OnlinePlaygroundV2 = OnlinePlayground;
pub struct OnlinePlayground {
app_id: AppId,
enable_cloud_sync: bool,
auth_url: String,
identity_config: Mutex<Option<BoxedIdentityConfig>>,
}
pub struct OfflinePlayground {
identity_config: Mutex<Option<BoxedIdentityConfig>>,
}
pub struct SharedKey {
identity_config: Mutex<Option<BoxedIdentityConfig>>,
}
pub struct Manual {
identity_config: Mutex<Option<BoxedIdentityConfig>>,
}
impl OnlineWithAuthentication {
pub fn new(
_ditto_root: Arc<dyn DittoRoot>, app_id: AppId,
auth_event_handler: impl DittoAuthenticationEventHandler + 'static,
enable_cloud_sync: bool,
custom_auth_url: Option<&str>,
) -> Result<Self, DittoError> {
let auth_url = match custom_auth_url {
Some(url) => url.to_owned(),
None => app_id.default_auth_url(),
};
let c_app_id = char_p::new(app_id.to_string());
let c_auth_url = char_p::new(auth_url.as_str());
let identity_config = Mutex::new(Some(
ffi_sdk::ditto_identity_config_make_online_with_authentication(
c_app_id.as_ref(),
c_auth_url.as_ref(),
)
.ok_or(ErrorKind::Config)?,
));
Ok(OnlineWithAuthentication {
app_id,
enable_cloud_sync,
auth_url,
identity_config,
auth_event_handler: Arc::new(auth_event_handler),
})
}
}
impl Identity for OnlineWithAuthentication {
fn identity_config(&self) -> Option<BoxedIdentityConfig> {
let mut config = self.identity_config.lock().unwrap();
config.take()
}
fn involves_authenticator(&self) -> bool {
true
}
fn set_login_provider_with_ditto_pointer(&self, ditto_fields: &Arc<crate::ditto::DittoFields>) {
let authenticator = DittoAuthenticator {
ditto_fields: Arc::downgrade(ditto_fields),
};
let auth_event_handler = self.auth_event_handler.retain();
let LoginProvider(c_provider) = LoginProvider::new(auth_event_handler, authenticator);
ffi_sdk::ditto_auth_set_login_provider(&ditto_fields.ditto, Some(c_provider));
}
fn is_cloud_sync_enabled(&self) -> bool {
self.enable_cloud_sync
}
fn auth_url(&self) -> Result<String, DittoError> {
Ok(self.auth_url.to_owned())
}
fn sync_url(&self) -> Result<String, DittoError> {
Ok(self.app_id.default_sync_url())
}
fn requires_offline_only_license_token(&self) -> bool {
false
}
}
impl OnlinePlayground {
pub fn new(
_ditto_root: Arc<dyn DittoRoot>, app_id: AppId,
shared_token: String,
enable_cloud_sync: bool,
custom_auth_url: Option<&str>,
) -> Result<Self, DittoError> {
let c_app_id = app_id.to_c_string();
let c_shared_token = char_p::new(shared_token.as_str());
let auth_url = match custom_auth_url {
Some(url) => url.to_owned(),
None => app_id.default_auth_url(),
};
let c_auth_url = char_p::new(auth_url.as_str());
let identity_config = Mutex::new(Some(
ffi_sdk::ditto_identity_config_make_online_playground(
c_app_id.as_ref(),
c_shared_token.as_ref(),
c_auth_url.as_ref(),
)
.ok_or(ErrorKind::Config)?,
));
Ok(Self {
app_id,
enable_cloud_sync,
auth_url,
identity_config,
})
}
}
impl Identity for OnlinePlayground {
fn identity_config(&self) -> Option<BoxedIdentityConfig> {
let mut config = self.identity_config.lock().unwrap();
config.take()
}
fn involves_authenticator(&self) -> bool {
true
}
fn auth_url(&self) -> Result<String, DittoError> {
Ok(self.auth_url.to_owned())
}
fn sync_url(&self) -> Result<String, DittoError> {
Ok(self.app_id.default_sync_url())
}
fn is_cloud_sync_enabled(&self) -> bool {
self.enable_cloud_sync
}
fn requires_offline_only_license_token(&self) -> bool {
false
}
}
impl OfflinePlayground {
pub fn new(_ditto_root: Arc<dyn DittoRoot>, app_id: AppId) -> Result<Self, DittoError> {
let c_app_id = app_id.to_c_string();
let identity_config = Mutex::new(Some(
ffi_sdk::ditto_identity_config_make_offline_playground(c_app_id.as_ref(), 0)
.ok_or(ErrorKind::Config)?,
));
Ok(Self { identity_config })
}
pub fn random(ditto_root: Arc<dyn DittoRoot>) -> Result<Self, DittoError> {
let app_id = AppId::generate();
Self::new(ditto_root, app_id)
}
}
impl Identity for OfflinePlayground {
fn identity_config(&self) -> Option<BoxedIdentityConfig> {
let mut config = self.identity_config.lock().unwrap();
config.take()
}
fn is_cloud_sync_enabled(&self) -> bool {
false
}
fn auth_url(&self) -> Result<String, DittoError> {
Err(DittoError::new(
ErrorKind::InvalidInput,
"Cloud Auth is not enabled for OfflinePlayground Identities".to_string(),
))
}
fn sync_url(&self) -> Result<String, DittoError> {
Err(DittoError::new(
ErrorKind::InvalidInput,
"Cloud sync is not enabled for OfflinePlayground Identities".to_string(),
))
}
fn requires_offline_only_license_token(&self) -> bool {
true
}
}
impl SharedKey {
pub fn new(
_ditto_root: Arc<dyn DittoRoot>, app_id: AppId,
key_der_b64: &str,
) -> Result<Self, DittoError> {
let c_app_id = app_id.to_c_string();
let c_key_der = char_p::new(key_der_b64);
let identity_config = Mutex::new(Some(
ffi_sdk::ditto_identity_config_make_shared_key(
c_app_id.as_ref(),
c_key_der.as_ref(),
0,
)
.ok_or(ErrorKind::Config)?,
));
Ok(Self { identity_config })
}
}
impl Identity for SharedKey {
fn identity_config(&self) -> Option<BoxedIdentityConfig> {
let mut config = self.identity_config.lock().unwrap();
config.take()
}
fn auth_url(&self) -> Result<String, DittoError> {
let msg = "SharedKey Identities don't support auth urls".to_owned();
Err(DittoError::new(ErrorKind::Config, msg))
}
fn sync_url(&self) -> Result<String, DittoError> {
let msg = "SharedKey Identities to support cloud sync".to_owned();
Err(DittoError::new(ErrorKind::Config, msg))
}
fn is_cloud_sync_enabled(&self) -> bool {
false
}
fn requires_offline_only_license_token(&self) -> bool {
true
}
}
impl Manual {
pub fn new(manual_identity: impl Into<String>) -> Result<Self, DittoError> {
let manual_identity_str = char_p::new(manual_identity.into());
let identity_config = Mutex::new(Some(
ffi_sdk::ditto_identity_config_make_manual(manual_identity_str.as_ref())
.ok_or(ErrorKind::Config)?,
));
Ok(Self { identity_config })
}
}
impl Identity for Manual {
fn identity_config(&self) -> Option<BoxedIdentityConfig> {
let mut config = self.identity_config.lock().unwrap();
config.take()
}
fn auth_url(&self) -> Result<String, DittoError> {
let msg = "Manual Identities don't support auth urls".to_owned();
Err(DittoError::new(ErrorKind::Config, msg))
}
fn sync_url(&self) -> Result<String, DittoError> {
let msg = "Manual Identities to support cloud sync".to_owned();
Err(DittoError::new(ErrorKind::Config, msg))
}
fn is_cloud_sync_enabled(&self) -> bool {
false
}
fn requires_offline_only_license_token(&self) -> bool {
true
}
}
mod private {
use super::*;
pub trait Sealed {}
impl Sealed for OnlineWithAuthentication {}
impl Sealed for OnlinePlayground {}
impl Sealed for OfflinePlayground {}
impl Sealed for SharedKey {}
impl Sealed for Manual {}
}