use ffi_sdk::Platform;
use super::*;
use crate::identity::Identity;
pub struct DittoBuilder {
ditto_root: Option<Arc<dyn DittoRoot>>,
identity: Option<Arc<dyn Identity>>,
minimum_log_level: LogLevel,
transport_config: Option<TransportConfig>,
}
impl DittoBuilder {
pub fn new() -> DittoBuilder {
DittoBuilder {
ditto_root: None,
identity: None,
minimum_log_level: LogLevel::Info,
transport_config: None,
}
}
pub fn with_root(mut self, ditto_root: Arc<dyn DittoRoot>) -> Self {
self.ditto_root = Some(ditto_root);
self
}
pub fn with_minimum_log_level(mut self, log_level: LogLevel) -> Self {
self.minimum_log_level = log_level;
self
}
pub fn with_temp_dir(mut self) -> Self {
let root = TempRoot::new();
self.ditto_root = Some(Arc::new(root));
self
}
fn platform() -> Platform {
using!(match () {
use ffi_sdk::Platform;
| _case if cfg!(target_os = "windows") => Platform::Windows,
| _case if cfg!(target_os = "android") => Platform::Android,
| _case if cfg!(target_os = "macos") => Platform::Mac,
| _case if cfg!(target_os = "ios") => Platform::Ios,
| _case if cfg!(target_os = "linux") => Platform::Linux,
| _default => Platform::Unknown,
})
}
fn sdk_version() -> String {
let sdk_semver = env!("CARGO_PKG_VERSION");
sdk_semver.to_string()
}
fn init_sdk_version() {
let platform = Self::platform();
let sdk_semver = Self::sdk_version();
let c_version = char_p::new(sdk_semver);
ffi_sdk::ditto_init_sdk_version(platform, ffi_sdk::Language::Rust, c_version.as_ref());
}
fn init_logging(&self) {
ffi_sdk::ditto_logger_init();
ffi_sdk::ditto_logger_minimum_log_level(self.minimum_log_level);
ffi_sdk::ditto_logger_enabled(true);
}
pub fn with_identity<F, I>(mut self, factory: F) -> Result<Self, DittoError>
where
F: FnOnce(Arc<dyn DittoRoot>) -> Result<I, DittoError>,
I: Identity + 'static, {
match &self.ditto_root {
Some(root) => {
let identity = factory(root.retain())?;
self.identity = Some(Arc::new(identity));
}
None => {
let msg = "A valid DittoRoot directory must be provided before configuring the \
Identity"
.to_string();
return Err(DittoError::new(ErrorKind::Config, msg));
}
};
Ok(self)
}
pub fn with_transport_config<T>(mut self, factory: T) -> Result<Self, DittoError>
where
T: FnOnce(Arc<dyn Identity>) -> TransportConfig,
{
match &self.identity {
Some(id) => {
let config = factory(id.retain());
self.transport_config = Some(config)
}
None => {
let msg = "A DittoRoot directory and Identity must first be specified before \
providing a custom TransportConfig"
.to_string();
return Err(DittoError::new(ErrorKind::Config, msg));
}
}
Ok(self)
}
pub fn build(self) -> Result<Ditto, DittoError> {
self.init_logging();
Self::init_sdk_version();
let ditto_root = self.ditto_root.ok_or_else(|| {
DittoError::new(ErrorKind::Config, "No Ditto Root Directory provided")
})?;
crate::fs::drain_ditto_data_dir(&ditto_root);
let c_root_dir = ditto_root.root_dir_to_c_str()?;
let identity = self
.identity
.ok_or_else(|| DittoError::new(ErrorKind::Config, "No Identity specified"))?;
let identity_config = identity
.identity_config()
.expect("identity config to be Some");
let boxed_ditto = ffi_sdk::ditto_make(
c_root_dir.as_ref(),
identity_config,
ffi_sdk::HistoryTracking::Disabled,
);
let ditto: DittoHandleWrapper = Arc::new(boxed_ditto);
let site_id: SiteId = ffi_sdk::ditto_auth_client_get_site_id(&ditto);
let transport_config = self.transport_config.unwrap_or_else(|| {
let mut config = TransportConfig::new();
config.enable_all_peer_to_peer();
config
});
let transports: Arc<RwLock<TransportSync>> = Arc::new(RwLock::new(
TransportSync::from_config(transport_config, ditto.retain(), identity.retain()),
));
let auth = identity.authenticator();
let validity_listener = Some(ValidityListener::new(Arc::downgrade(&transports), &ditto));
let presence = Arc::new(Presence::new(ditto.retain()));
let on_connecting = Arc::new(OnConnecting::new(ditto.retain()));
let disk_usage = DiskUsage::new(ditto.retain(), FsComponent::Root);
let small_peer_info = SmallPeerInfo::new(ditto.retain());
let fields = Arc::new_cyclic(|weak_fields: &arc::Weak<_>| {
let store = Store::new(ditto.retain(), weak_fields.clone());
let auth = auth.map(|mut auth| {
auth.ditto_fields = weak_fields.clone();
auth
});
let sync = crate::sync::Sync::new(weak_fields.clone());
DittoFields {
ditto: ditto.retain(),
auth,
identity: identity.retain(),
store,
sync,
activated: identity.requires_offline_only_license_token().not().into(),
site_id,
transports,
ditto_root,
validity_listener,
presence,
on_connecting,
disk_usage,
small_peer_info,
}
});
identity.set_login_provider(fields.auth.as_ref().map(|a| a.retain()));
let sdk_ditto = Ditto {
fields,
is_shut_down_able: true,
};
Ok(sdk_ditto)
}
}
impl Default for DittoBuilder {
fn default() -> Self {
Self::new()
}
}