2022-06-08 01:31:05 +00:00
use crate ::api_tracing_layer ::* ;
2022-02-07 02:18:42 +00:00
use crate ::attachment_manager ::* ;
2022-10-30 23:29:31 +00:00
use crate ::crypto ::Crypto ;
2023-05-29 19:24:57 +00:00
use crate ::storage_manager ::* ;
2022-02-07 02:18:42 +00:00
use crate ::veilid_api ::* ;
use crate ::veilid_config ::* ;
2022-11-26 21:17:30 +00:00
use crate ::* ;
2022-02-07 02:18:42 +00:00
2022-07-11 12:37:08 +00:00
pub type UpdateCallback = Arc < dyn Fn ( VeilidUpdate ) + Send + Sync > ;
2022-02-07 02:18:42 +00:00
2023-05-29 19:24:57 +00:00
/// Internal services startup mechanism
/// Ensures that everything is started up, and shut down in the right order
/// and provides an atomic state for if the system is properly operational
2022-03-09 03:32:12 +00:00
struct ServicesContext {
2022-02-07 02:18:42 +00:00
pub config : VeilidConfig ,
2022-02-15 18:40:17 +00:00
pub update_callback : UpdateCallback ,
2022-03-09 03:32:12 +00:00
pub protected_store : Option < ProtectedStore > ,
pub table_store : Option < TableStore > ,
2023-06-05 01:22:55 +00:00
#[ cfg(feature = " unstable-blockstore " ) ]
2022-03-09 03:32:12 +00:00
pub block_store : Option < BlockStore > ,
pub crypto : Option < Crypto > ,
pub attachment_manager : Option < AttachmentManager > ,
2023-05-29 19:24:57 +00:00
pub storage_manager : Option < StorageManager > ,
2022-02-07 02:18:42 +00:00
}
2022-03-09 03:32:12 +00:00
impl ServicesContext {
pub fn new_empty ( config : VeilidConfig , update_callback : UpdateCallback ) -> Self {
Self {
config ,
update_callback ,
protected_store : None ,
table_store : None ,
2023-06-05 01:22:55 +00:00
#[ cfg(feature = " unstable-blockstore " ) ]
2022-03-09 03:32:12 +00:00
block_store : None ,
crypto : None ,
attachment_manager : None ,
2023-05-29 19:24:57 +00:00
storage_manager : None ,
2022-02-09 14:47:36 +00:00
}
}
2022-03-09 03:32:12 +00:00
pub fn new_full (
config : VeilidConfig ,
2022-02-09 14:47:36 +00:00
update_callback : UpdateCallback ,
2022-03-09 03:32:12 +00:00
protected_store : ProtectedStore ,
table_store : TableStore ,
2023-06-05 01:22:55 +00:00
#[ cfg(feature = " unstable-blockstore " ) ] block_store : BlockStore ,
2022-03-09 03:32:12 +00:00
crypto : Crypto ,
attachment_manager : AttachmentManager ,
2023-05-29 19:24:57 +00:00
storage_manager : StorageManager ,
2022-03-09 03:32:12 +00:00
) -> Self {
Self {
config ,
update_callback ,
protected_store : Some ( protected_store ) ,
table_store : Some ( table_store ) ,
2023-06-05 01:22:55 +00:00
#[ cfg(feature = " unstable-blockstore " ) ]
2022-03-09 03:32:12 +00:00
block_store : Some ( block_store ) ,
crypto : Some ( crypto ) ,
attachment_manager : Some ( attachment_manager ) ,
2023-05-29 19:24:57 +00:00
storage_manager : Some ( storage_manager ) ,
2022-02-07 02:18:42 +00:00
}
2022-02-09 14:47:36 +00:00
}
2022-02-07 02:18:42 +00:00
2022-06-10 21:07:10 +00:00
#[ instrument(err, skip_all) ]
2022-07-10 21:36:50 +00:00
pub async fn startup ( & mut self ) -> EyreResult < ( ) > {
2022-03-11 12:35:41 +00:00
info! ( " Veilid API starting up " ) ;
2022-03-09 03:32:12 +00:00
2022-07-01 16:13:52 +00:00
info! ( " init api tracing " ) ;
ApiTracingLayer ::init ( self . update_callback . clone ( ) ) . await ;
2022-02-07 02:18:42 +00:00
// Set up protected store
2022-03-09 03:32:12 +00:00
trace! ( " init protected store " ) ;
let protected_store = ProtectedStore ::new ( self . config . clone ( ) ) ;
2022-02-07 02:18:42 +00:00
if let Err ( e ) = protected_store . init ( ) . await {
2023-05-29 19:24:57 +00:00
error! ( " failed to init protected store: {} " , e ) ;
2022-03-09 03:32:12 +00:00
self . shutdown ( ) . await ;
2022-07-10 21:36:50 +00:00
return Err ( e ) ;
2022-02-07 02:18:42 +00:00
}
2022-03-09 03:32:12 +00:00
self . protected_store = Some ( protected_store . clone ( ) ) ;
2022-02-07 02:18:42 +00:00
2023-05-29 19:24:57 +00:00
// Set up tablestore and crypto system
trace! ( " create table store and crypto system " ) ;
let table_store = TableStore ::new ( self . config . clone ( ) , protected_store . clone ( ) ) ;
let crypto = Crypto ::new ( self . config . clone ( ) , table_store . clone ( ) ) ;
table_store . set_crypto ( crypto . clone ( ) ) ;
// Initialize table store first, so crypto code can load caches
// Tablestore can use crypto during init, just not any cached operations or things
// that require flushing back to the tablestore
2022-03-09 03:32:12 +00:00
trace! ( " init table store " ) ;
2022-02-07 02:18:42 +00:00
if let Err ( e ) = table_store . init ( ) . await {
2023-05-29 19:24:57 +00:00
error! ( " failed to init table store: {} " , e ) ;
2022-03-09 03:32:12 +00:00
self . shutdown ( ) . await ;
2022-07-10 21:36:50 +00:00
return Err ( e ) ;
2022-02-07 02:18:42 +00:00
}
2022-03-09 03:32:12 +00:00
self . table_store = Some ( table_store . clone ( ) ) ;
2022-02-07 02:18:42 +00:00
// Set up crypto
2022-03-09 03:32:12 +00:00
trace! ( " init crypto " ) ;
2022-02-07 02:18:42 +00:00
if let Err ( e ) = crypto . init ( ) . await {
2023-05-29 19:24:57 +00:00
error! ( " failed to init crypto: {} " , e ) ;
2022-03-09 03:32:12 +00:00
self . shutdown ( ) . await ;
2022-07-10 21:36:50 +00:00
return Err ( e ) ;
2022-02-07 02:18:42 +00:00
}
2022-03-09 03:32:12 +00:00
self . crypto = Some ( crypto . clone ( ) ) ;
2022-02-07 02:18:42 +00:00
// Set up block store
2023-06-05 01:22:55 +00:00
#[ cfg(feature = " unstable-blockstore " ) ]
{
trace! ( " init block store " ) ;
let block_store = BlockStore ::new ( self . config . clone ( ) ) ;
if let Err ( e ) = block_store . init ( ) . await {
error! ( " failed to init block store: {} " , e ) ;
self . shutdown ( ) . await ;
return Err ( e ) ;
}
self . block_store = Some ( block_store . clone ( ) ) ;
2022-02-07 02:18:42 +00:00
}
2023-05-29 19:24:57 +00:00
// Set up storage manager
trace! ( " init storage manager " ) ;
let storage_manager = StorageManager ::new (
self . config . clone ( ) ,
self . crypto . clone ( ) . unwrap ( ) ,
self . table_store . clone ( ) . unwrap ( ) ,
2023-06-05 01:22:55 +00:00
#[ cfg(feature = " unstable-blockstore " ) ]
2023-05-29 19:24:57 +00:00
self . block_store . clone ( ) . unwrap ( ) ,
) ;
if let Err ( e ) = storage_manager . init ( ) . await {
error! ( " failed to init storage manager: {} " , e ) ;
self . shutdown ( ) . await ;
return Err ( e ) ;
}
self . storage_manager = Some ( storage_manager . clone ( ) ) ;
2022-02-07 02:18:42 +00:00
// Set up attachment manager
2022-03-09 03:32:12 +00:00
trace! ( " init attachment manager " ) ;
2022-03-24 14:14:50 +00:00
let update_callback = self . update_callback . clone ( ) ;
2022-10-30 23:29:31 +00:00
let attachment_manager = AttachmentManager ::new (
self . config . clone ( ) ,
2023-05-29 19:24:57 +00:00
storage_manager ,
2022-10-30 23:29:31 +00:00
protected_store ,
table_store ,
2023-06-05 01:22:55 +00:00
#[ cfg(feature = " unstable-blockstore " ) ]
2022-10-30 23:29:31 +00:00
block_store ,
crypto ,
) ;
2022-03-24 14:14:50 +00:00
if let Err ( e ) = attachment_manager . init ( update_callback ) . await {
2023-05-29 19:24:57 +00:00
error! ( " failed to init attachment manager: {} " , e ) ;
2022-03-09 03:32:12 +00:00
self . shutdown ( ) . await ;
2022-07-10 21:36:50 +00:00
return Err ( e ) ;
2022-03-09 03:32:12 +00:00
}
self . attachment_manager = Some ( attachment_manager ) ;
2022-03-11 12:35:41 +00:00
info! ( " Veilid API startup complete " ) ;
2022-03-09 03:32:12 +00:00
Ok ( ( ) )
}
2022-06-10 21:07:10 +00:00
#[ instrument(skip_all) ]
2022-03-09 03:32:12 +00:00
pub async fn shutdown ( & mut self ) {
2022-03-11 12:35:41 +00:00
info! ( " Veilid API shutting down " ) ;
2022-03-09 03:32:12 +00:00
if let Some ( attachment_manager ) = & mut self . attachment_manager {
trace! ( " terminate attachment manager " ) ;
attachment_manager . terminate ( ) . await ;
}
2023-05-29 19:24:57 +00:00
if let Some ( storage_manager ) = & mut self . storage_manager {
trace! ( " terminate storage manager " ) ;
storage_manager . terminate ( ) . await ;
}
2023-06-05 01:22:55 +00:00
#[ cfg(feature = " unstable-blockstore " ) ]
2022-03-09 03:32:12 +00:00
if let Some ( block_store ) = & mut self . block_store {
trace! ( " terminate block store " ) ;
2022-02-07 02:18:42 +00:00
block_store . terminate ( ) . await ;
2022-03-09 03:32:12 +00:00
}
if let Some ( crypto ) = & mut self . crypto {
trace! ( " terminate crypto " ) ;
2022-02-07 02:18:42 +00:00
crypto . terminate ( ) . await ;
2022-03-09 03:32:12 +00:00
}
if let Some ( table_store ) = & mut self . table_store {
trace! ( " terminate table store " ) ;
2022-02-07 02:18:42 +00:00
table_store . terminate ( ) . await ;
2022-03-09 03:32:12 +00:00
}
if let Some ( protected_store ) = & mut self . protected_store {
trace! ( " terminate protected store " ) ;
2022-02-07 02:18:42 +00:00
protected_store . terminate ( ) . await ;
2022-03-09 03:32:12 +00:00
}
2022-03-11 12:35:41 +00:00
info! ( " Veilid API shutdown complete " ) ;
2022-03-09 03:32:12 +00:00
// api logger terminate is idempotent
2022-06-08 01:31:05 +00:00
ApiTracingLayer ::terminate ( ) . await ;
2022-03-09 03:32:12 +00:00
// send final shutdown update
2022-03-11 12:35:41 +00:00
( self . update_callback ) ( VeilidUpdate ::Shutdown ) ;
2022-03-09 03:32:12 +00:00
}
}
/////////////////////////////////////////////////////////////////////////////
///
pub struct VeilidCoreContext {
pub config : VeilidConfig ,
pub update_callback : UpdateCallback ,
// Services
2023-05-29 19:24:57 +00:00
pub storage_manager : StorageManager ,
2022-03-09 03:32:12 +00:00
pub protected_store : ProtectedStore ,
pub table_store : TableStore ,
2023-06-05 01:22:55 +00:00
#[ cfg(feature = " unstable-blockstore " ) ]
2022-03-09 03:32:12 +00:00
pub block_store : BlockStore ,
pub crypto : Crypto ,
pub attachment_manager : AttachmentManager ,
}
impl VeilidCoreContext {
2022-06-10 21:07:10 +00:00
#[ instrument(err, skip_all) ]
2022-03-09 03:32:12 +00:00
async fn new_with_config_callback (
update_callback : UpdateCallback ,
config_callback : ConfigCallback ,
2023-05-29 19:24:57 +00:00
) -> VeilidAPIResult < VeilidCoreContext > {
2022-03-09 03:32:12 +00:00
// Set up config from callback
trace! ( " setup config with callback " ) ;
let mut config = VeilidConfig ::new ( ) ;
2022-11-16 17:49:53 +00:00
config . setup ( config_callback , update_callback . clone ( ) ) ? ;
2022-02-07 02:18:42 +00:00
2022-03-09 03:32:12 +00:00
Self ::new_common ( update_callback , config ) . await
2022-02-07 02:18:42 +00:00
}
2022-06-11 22:47:58 +00:00
#[ instrument(err, skip_all) ]
2022-03-09 03:32:12 +00:00
async fn new_with_config_json (
update_callback : UpdateCallback ,
config_json : String ,
2023-05-29 19:24:57 +00:00
) -> VeilidAPIResult < VeilidCoreContext > {
2022-03-09 03:32:12 +00:00
// Set up config from callback
trace! ( " setup config with json " ) ;
let mut config = VeilidConfig ::new ( ) ;
2022-11-16 17:49:53 +00:00
config . setup_from_json ( config_json , update_callback . clone ( ) ) ? ;
2022-03-09 03:32:12 +00:00
Self ::new_common ( update_callback , config ) . await
}
2022-02-07 02:18:42 +00:00
2022-06-11 22:47:58 +00:00
#[ instrument(err, skip_all) ]
2022-03-09 03:32:12 +00:00
async fn new_common (
update_callback : UpdateCallback ,
config : VeilidConfig ,
2023-05-29 19:24:57 +00:00
) -> VeilidAPIResult < VeilidCoreContext > {
2022-03-09 03:32:12 +00:00
cfg_if! {
if #[ cfg(target_os = " android " ) ] {
2022-12-01 19:32:02 +00:00
if ! crate ::intf ::android ::is_android_ready ( ) {
2022-11-26 21:17:30 +00:00
apibail_internal! ( " Android globals are not set up " ) ;
2022-03-09 03:32:12 +00:00
}
}
}
2022-02-07 02:18:42 +00:00
2022-03-09 03:32:12 +00:00
let mut sc = ServicesContext ::new_empty ( config . clone ( ) , update_callback ) ;
2022-07-10 21:36:50 +00:00
sc . startup ( ) . await . map_err ( VeilidAPIError ::generic ) ? ;
2022-02-15 18:40:17 +00:00
2022-03-09 03:32:12 +00:00
Ok ( VeilidCoreContext {
config : sc . config ,
2023-05-29 19:24:57 +00:00
update_callback : sc . update_callback ,
storage_manager : sc . storage_manager . unwrap ( ) ,
2022-03-09 03:32:12 +00:00
protected_store : sc . protected_store . unwrap ( ) ,
table_store : sc . table_store . unwrap ( ) ,
2023-06-05 01:22:55 +00:00
#[ cfg(feature = " unstable-blockstore " ) ]
2022-03-09 03:32:12 +00:00
block_store : sc . block_store . unwrap ( ) ,
crypto : sc . crypto . unwrap ( ) ,
attachment_manager : sc . attachment_manager . unwrap ( ) ,
} )
}
2022-06-10 21:07:10 +00:00
#[ instrument(skip_all) ]
2022-03-09 03:32:12 +00:00
async fn shutdown ( self ) {
let mut sc = ServicesContext ::new_full (
self . config . clone ( ) ,
self . update_callback . clone ( ) ,
self . protected_store ,
self . table_store ,
2023-06-05 01:22:55 +00:00
#[ cfg(feature = " unstable-blockstore " ) ]
2022-03-09 03:32:12 +00:00
self . block_store ,
self . crypto ,
self . attachment_manager ,
2023-05-29 19:24:57 +00:00
self . storage_manager ,
2022-03-09 03:32:12 +00:00
) ;
sc . shutdown ( ) . await ;
2022-02-07 02:18:42 +00:00
}
}
/////////////////////////////////////////////////////////////////////////////
2022-06-28 03:46:29 +00:00
lazy_static ::lazy_static! {
static ref INITIALIZED : AsyncMutex < bool > = AsyncMutex ::new ( false ) ;
}
2022-02-07 02:18:42 +00:00
2023-09-02 01:13:05 +00:00
/// Initialize a Veilid node.
///
/// Must be called only once at the start of an application
///
/// * `update_callback` - called when internal state of the Veilid node changes, for example, when app-level messages are received, when private routes die and need to be reallocated, or when routing table states change
/// * `config_callback` - called at startup to supply a configuration object directly to Veilid
///
/// Returns a [VeilidAPI] object that can be used to operate the node
2022-06-10 21:07:10 +00:00
#[ instrument(err, skip_all) ]
2022-02-09 14:47:36 +00:00
pub async fn api_startup (
update_callback : UpdateCallback ,
config_callback : ConfigCallback ,
2023-05-29 19:24:57 +00:00
) -> VeilidAPIResult < VeilidAPI > {
2022-02-09 14:47:36 +00:00
// See if we have an API started up already
let mut initialized_lock = INITIALIZED . lock ( ) . await ;
if * initialized_lock {
2022-11-26 21:17:30 +00:00
apibail_already_initialized! ( ) ;
2022-02-09 14:47:36 +00:00
}
// Create core context
let context =
VeilidCoreContext ::new_with_config_callback ( update_callback , config_callback ) . await ? ;
// Return an API object around our context
let veilid_api = VeilidAPI ::new ( context ) ;
* initialized_lock = true ;
Ok ( veilid_api )
}
2023-09-02 01:13:05 +00:00
/// Initialize a Veilid node, with the configuration in JSON format
///
/// Must be called only once at the start of an application
///
/// * `update_callback` - called when internal state of the Veilid node changes, for example, when app-level messages are received, when private routes die and need to be reallocated, or when routing table states change
/// * `config_json` - called at startup to supply a JSON configuration object
///
/// Returns a [VeilidAPI] object that can be used to operate the node
2023-08-26 02:01:57 +00:00
#[ instrument(err, skip_all) ]
2022-02-09 14:47:36 +00:00
pub async fn api_startup_json (
update_callback : UpdateCallback ,
config_json : String ,
2023-05-29 19:24:57 +00:00
) -> VeilidAPIResult < VeilidAPI > {
2022-02-07 02:18:42 +00:00
// See if we have an API started up already
let mut initialized_lock = INITIALIZED . lock ( ) . await ;
if * initialized_lock {
2022-11-26 21:17:30 +00:00
apibail_already_initialized! ( ) ;
2022-02-07 02:18:42 +00:00
}
// Create core context
2022-02-09 14:47:36 +00:00
let context = VeilidCoreContext ::new_with_config_json ( update_callback , config_json ) . await ? ;
2022-02-07 02:18:42 +00:00
// Return an API object around our context
let veilid_api = VeilidAPI ::new ( context ) ;
* initialized_lock = true ;
Ok ( veilid_api )
}
2022-06-10 21:07:10 +00:00
#[ instrument(skip_all) ]
2022-03-09 03:32:12 +00:00
pub ( crate ) async fn api_shutdown ( context : VeilidCoreContext ) {
2022-02-07 02:18:42 +00:00
let mut initialized_lock = INITIALIZED . lock ( ) . await ;
context . shutdown ( ) . await ;
* initialized_lock = false ;
}