veilid/veilid-core/src/core_context.rs
2022-02-06 21:18:42 -05:00

198 lines
6.7 KiB
Rust

use crate::api_logger::*;
use crate::attachment_manager::*;
use crate::dht::crypto::Crypto;
use crate::intf::*;
use crate::veilid_api::*;
use crate::veilid_config::*;
use crate::xx::*;
cfg_if! {
if #[cfg(target_arch = "wasm32")] {
pub type UpdateCallback = Arc<dyn Fn(VeilidUpdate) -> SystemPinBoxFuture<()>>;
} else {
pub type UpdateCallback = Arc<dyn Fn(VeilidUpdate) -> SystemPinBoxFuture<()> + Send + Sync>;
}
}
pub struct VeilidCoreSetup {
pub update_callback: UpdateCallback,
pub config_callback: ConfigCallback,
}
pub struct VeilidCoreContext {
pub config: VeilidConfig,
pub protected_store: ProtectedStore,
pub table_store: TableStore,
pub block_store: BlockStore,
pub crypto: Crypto,
pub attachment_manager: AttachmentManager,
}
impl VeilidCoreContext {
async fn new(setup: VeilidCoreSetup) -> Result<VeilidCoreContext, VeilidAPIError> {
// Start up api logging early if it's in the config
let api_log_level: VeilidConfigLogLevel =
*(setup.config_callback)("api_log_level".to_owned())
.map_err(|e| VeilidAPIError::ParseError {
message: "Failed to get api_log_level".to_owned(),
value: e,
})?
.downcast()
.map_err(|e| VeilidAPIError::ParseError {
message: "Incorrect type for key 'api_log_level'".to_owned(),
value: format!("Invalid type: {:?}", e.type_id()),
})?;
if api_log_level != VeilidConfigLogLevel::Off {
ApiLogger::init(
api_log_level.to_level_filter(),
setup.update_callback.clone(),
);
for ig in crate::DEFAULT_LOG_IGNORE_LIST {
ApiLogger::add_filter_ignore_str(ig);
}
}
trace!("VeilidCoreContext::new starting");
cfg_if! {
if #[cfg(target_os = "android")] {
if utils::android::ANDROID_GLOBALS.lock().is_none() {
error!("Android globals are not set up");
return Err("Android globals are not set up".to_owned());
}
}
}
// Set up config
trace!("VeilidCoreContext::new init config");
let mut config = VeilidConfig::new();
if let Err(e) = config.init(setup.config_callback).await {
ApiLogger::terminate();
return Err(VeilidAPIError::Internal(e));
}
// Set up protected store
trace!("VeilidCoreContext::new init protected store");
let protected_store = ProtectedStore::new(config.clone());
if let Err(e) = protected_store.init().await {
config.terminate().await;
ApiLogger::terminate();
return Err(VeilidAPIError::Internal(e));
}
// Init node id from config now that protected store is set up
if let Err(e) = config.init_node_id(protected_store.clone()).await {
protected_store.terminate().await;
config.terminate().await;
ApiLogger::terminate();
return Err(VeilidAPIError::Internal(e));
}
// Set up tablestore
trace!("VeilidCoreContext::new init table store");
let table_store = TableStore::new(config.clone());
if let Err(e) = table_store.init().await {
protected_store.terminate().await;
config.terminate().await;
ApiLogger::terminate();
return Err(VeilidAPIError::Internal(e));
}
// Set up crypto
trace!("VeilidCoreContext::new init crypto");
let crypto = Crypto::new(config.clone(), table_store.clone());
if let Err(e) = crypto.init().await {
table_store.terminate().await;
protected_store.terminate().await;
config.terminate().await;
ApiLogger::terminate();
return Err(VeilidAPIError::Internal(e));
}
// Set up block store
trace!("VeilidCoreContext::new init block store");
let block_store = BlockStore::new(config.clone());
if let Err(e) = block_store.init().await {
crypto.terminate().await;
table_store.terminate().await;
protected_store.terminate().await;
config.terminate().await;
ApiLogger::terminate();
return Err(VeilidAPIError::Internal(e));
}
// Set up attachment manager
trace!("VeilidCoreContext::new init attachment manager");
let cb = setup.update_callback;
let attachment_manager =
AttachmentManager::new(config.clone(), table_store.clone(), crypto.clone());
if let Err(e) = attachment_manager
.init(Arc::new(
move |_old_state: AttachmentState, new_state: AttachmentState| {
cb(VeilidUpdate::Attachment(new_state))
},
))
.await
{
block_store.terminate().await;
crypto.terminate().await;
table_store.terminate().await;
protected_store.terminate().await;
config.terminate().await;
ApiLogger::terminate();
return Err(VeilidAPIError::Internal(e));
}
Ok(VeilidCoreContext {
config,
protected_store,
table_store,
block_store,
crypto,
attachment_manager,
})
}
async fn shutdown(self) {
trace!("VeilidCoreContext::terminate_core_context starting");
self.attachment_manager.terminate().await;
self.block_store.terminate().await;
self.crypto.terminate().await;
self.table_store.terminate().await;
self.protected_store.terminate().await;
self.config.terminate().await;
trace!("VeilidCoreContext::shutdown complete");
ApiLogger::terminate();
}
}
/////////////////////////////////////////////////////////////////////////////
static INITIALIZED: AsyncMutex<bool> = AsyncMutex::new(false);
pub async fn api_startup(setup: VeilidCoreSetup) -> Result<VeilidAPI, VeilidAPIError> {
// See if we have an API started up already
let mut initialized_lock = INITIALIZED.lock().await;
if *initialized_lock {
return Err(VeilidAPIError::AlreadyInitialized);
}
// Create core context
let context = VeilidCoreContext::new(setup).await?;
// Return an API object around our context
let veilid_api = VeilidAPI::new(context);
*initialized_lock = true;
Ok(veilid_api)
}
pub async fn api_shutdown(context: VeilidCoreContext) {
let mut initialized_lock = INITIALIZED.lock().await;
context.shutdown().await;
*initialized_lock = false;
}