2025-02-10 03:06:41 +00:00
use crate ::attachment_manager ::{ AttachmentManager , AttachmentManagerStartupContext } ;
2022-10-30 19:29:31 -04:00
use crate ::crypto ::Crypto ;
2024-03-07 16:49:59 -05:00
use crate ::logging ::* ;
2025-02-10 03:06:41 +00:00
use crate ::network_manager ::{ NetworkManager , NetworkManagerStartupContext } ;
use crate ::routing_table ::RoutingTable ;
use crate ::rpc_processor ::{ RPCProcessor , RPCProcessorStartupContext } ;
use crate ::storage_manager ::StorageManager ;
2022-02-06 21:18:42 -05:00
use crate ::veilid_api ::* ;
use crate ::veilid_config ::* ;
2022-11-26 16:17:30 -05:00
use crate ::* ;
2022-02-06 21:18:42 -05:00
2022-07-11 08:37:08 -04:00
pub type UpdateCallback = Arc < dyn Fn ( VeilidUpdate ) + Send + Sync > ;
2022-02-06 21:18:42 -05:00
2025-02-10 03:06:41 +00:00
type InitKey = ( String , String ) ;
/////////////////////////////////////////////////////////////////////////////
#[ derive(Clone, Debug) ]
pub ( crate ) struct VeilidCoreContext {
registry : VeilidComponentRegistry ,
2022-02-06 21:18:42 -05:00
}
2025-02-10 03:06:41 +00:00
impl_veilid_component_registry_accessor! ( VeilidCoreContext ) ;
impl VeilidCoreContext {
#[ instrument(level = " trace " , target = " core_context " , err, skip_all) ]
async fn new_with_config_callback (
update_callback : UpdateCallback ,
config_callback : ConfigCallback ,
) -> VeilidAPIResult < VeilidCoreContext > {
// Set up config from callback
let config = VeilidConfig ::new_from_callback ( config_callback , update_callback ) ? ;
Self ::new_common ( config ) . await
2022-02-09 09:47:36 -05:00
}
2025-02-10 03:06:41 +00:00
#[ instrument(level = " trace " , target = " core_context " , err, skip_all) ]
async fn new_with_config (
2022-02-09 09:47:36 -05:00
update_callback : UpdateCallback ,
2025-02-10 03:06:41 +00:00
config_inner : VeilidConfigInner ,
) -> VeilidAPIResult < VeilidCoreContext > {
// Set up config from json
let config = VeilidConfig ::new_from_config ( config_inner , update_callback ) ;
Self ::new_common ( config ) . await
2022-02-09 09:47:36 -05:00
}
2022-02-06 21:18:42 -05:00
2024-07-03 21:00:12 -04:00
#[ instrument(level = " trace " , target = " core_context " , err, skip_all) ]
2025-02-10 03:06:41 +00:00
async fn new_common ( config : VeilidConfig ) -> VeilidAPIResult < VeilidCoreContext > {
cfg_if! {
if #[ cfg(target_os = " android " ) ] {
if ! crate ::intf ::android ::is_android_ready ( ) {
apibail_internal! ( " Android globals are not set up " ) ;
}
}
}
2022-03-11 07:35:41 -05:00
info! ( " Veilid API starting up " ) ;
2022-03-08 22:32:12 -05:00
2025-02-10 03:06:41 +00:00
let ( program_name , namespace , update_callback ) = {
let cfginner = config . get ( ) ;
(
cfginner . program_name . clone ( ) ,
cfginner . namespace . clone ( ) ,
config . update_callback ( ) ,
)
2024-08-17 01:01:30 +00:00
} ;
2025-02-10 03:06:41 +00:00
ApiTracingLayer ::add_callback ( program_name , namespace , update_callback . clone ( ) ) . await ? ;
2022-07-01 12:13:52 -04:00
2025-02-10 03:06:41 +00:00
// Create component registry
let registry = VeilidComponentRegistry ::new ( config ) ;
2022-02-06 21:18:42 -05:00
2025-02-10 03:06:41 +00:00
// Register all components
registry . register ( ProtectedStore ::new ) ;
registry . register ( Crypto ::new ) ;
registry . register ( TableStore ::new ) ;
2023-06-04 21:22:55 -04:00
#[ cfg(feature = " unstable-blockstore " ) ]
2025-02-10 03:06:41 +00:00
registry . register ( BlockStore ::new ) ;
registry . register ( StorageManager ::new ) ;
registry . register ( RoutingTable ::new ) ;
registry
. register_with_context ( NetworkManager ::new , NetworkManagerStartupContext ::default ( ) ) ;
registry . register_with_context ( RPCProcessor ::new , RPCProcessorStartupContext ::default ( ) ) ;
registry . register_with_context (
AttachmentManager ::new ,
AttachmentManagerStartupContext ::default ( ) ,
2023-05-29 19:24:57 +00:00
) ;
2025-02-10 03:06:41 +00:00
// Run initialization
// This should make the majority of subsystems functional
registry . init ( ) . await . map_err ( VeilidAPIError ::internal ) ? ;
// Run post-initialization
// This should resolve any inter-subsystem dependencies
// required for background processes that utilize multiple subsystems
// Background processes also often require registry lookup of the
// current subsystem, which is not available until after init succeeds
if let Err ( e ) = registry . post_init ( ) . await {
registry . terminate ( ) . await ;
return Err ( VeilidAPIError ::internal ( e ) ) ;
2022-03-08 22:32:12 -05:00
}
2022-03-11 07:35:41 -05:00
info! ( " Veilid API startup complete " ) ;
2025-02-10 03:06:41 +00:00
Ok ( Self { registry } )
2022-03-08 22:32:12 -05:00
}
2024-07-03 21:00:12 -04:00
#[ instrument(level = " trace " , target = " core_context " , skip_all) ]
2025-02-10 03:06:41 +00:00
async fn shutdown ( self ) {
2022-03-11 07:35:41 -05:00
info! ( " Veilid API shutdown complete " ) ;
2022-03-08 22:32:12 -05:00
2025-02-10 03:06:41 +00:00
let ( program_name , namespace , update_callback ) = {
let config = self . registry . config ( ) ;
let cfginner = config . get ( ) ;
(
cfginner . program_name . clone ( ) ,
cfginner . namespace . clone ( ) ,
config . update_callback ( ) ,
)
2024-08-17 01:01:30 +00:00
} ;
2025-02-10 03:06:41 +00:00
// Run pre-termination
// This should shut down background processes that may require the existence of
// other subsystems that may not exist during final termination
self . registry . pre_terminate ( ) . await ;
// Run termination
// This should finish any shutdown operations for the subsystems
self . registry . terminate ( ) . await ;
2024-08-17 01:01:30 +00:00
if let Err ( e ) = ApiTracingLayer ::remove_callback ( program_name , namespace ) . await {
error! ( " Error removing callback from ApiTracingLayer: {} " , e ) ;
}
2022-03-08 22:32:12 -05:00
// send final shutdown update
2025-02-10 03:06:41 +00:00
update_callback ( VeilidUpdate ::Shutdown ) ;
2022-03-08 22:32:12 -05:00
}
}
/////////////////////////////////////////////////////////////////////////////
2025-02-10 03:06:41 +00:00
pub trait RegisteredComponents {
fn protected_store < ' a > ( & self ) -> VeilidComponentGuard < ' a , ProtectedStore > ;
fn crypto < ' a > ( & self ) -> VeilidComponentGuard < ' a , Crypto > ;
fn table_store < ' a > ( & self ) -> VeilidComponentGuard < ' a , TableStore > ;
fn storage_manager < ' a > ( & self ) -> VeilidComponentGuard < ' a , StorageManager > ;
fn routing_table < ' a > ( & self ) -> VeilidComponentGuard < ' a , RoutingTable > ;
fn network_manager < ' a > ( & self ) -> VeilidComponentGuard < ' a , NetworkManager > ;
fn rpc_processor < ' a > ( & self ) -> VeilidComponentGuard < ' a , RPCProcessor > ;
fn attachment_manager < ' a > ( & self ) -> VeilidComponentGuard < ' a , AttachmentManager > ;
}
2022-02-06 21:18:42 -05:00
2025-02-10 03:06:41 +00:00
impl < T : VeilidComponentRegistryAccessor > RegisteredComponents for T {
fn protected_store < ' a > ( & self ) -> VeilidComponentGuard < ' a , ProtectedStore > {
self . registry ( ) . lookup ::< ProtectedStore > ( ) . unwrap ( )
2022-02-06 21:18:42 -05:00
}
2025-02-10 03:06:41 +00:00
fn crypto < ' a > ( & self ) -> VeilidComponentGuard < ' a , Crypto > {
self . registry ( ) . lookup ::< Crypto > ( ) . unwrap ( )
2024-01-05 15:12:17 -08:00
}
2025-02-10 03:06:41 +00:00
fn table_store < ' a > ( & self ) -> VeilidComponentGuard < ' a , TableStore > {
self . registry ( ) . lookup ::< TableStore > ( ) . unwrap ( )
2022-03-08 22:32:12 -05:00
}
2025-02-10 03:06:41 +00:00
fn storage_manager < ' a > ( & self ) -> VeilidComponentGuard < ' a , StorageManager > {
self . registry ( ) . lookup ::< StorageManager > ( ) . unwrap ( )
}
fn routing_table < ' a > ( & self ) -> VeilidComponentGuard < ' a , RoutingTable > {
self . registry ( ) . lookup ::< RoutingTable > ( ) . unwrap ( )
}
fn network_manager < ' a > ( & self ) -> VeilidComponentGuard < ' a , NetworkManager > {
self . registry ( ) . lookup ::< NetworkManager > ( ) . unwrap ( )
}
fn rpc_processor < ' a > ( & self ) -> VeilidComponentGuard < ' a , RPCProcessor > {
self . registry ( ) . lookup ::< RPCProcessor > ( ) . unwrap ( )
}
fn attachment_manager < ' a > ( & self ) -> VeilidComponentGuard < ' a , AttachmentManager > {
self . registry ( ) . lookup ::< AttachmentManager > ( ) . unwrap ( )
2022-02-06 21:18:42 -05:00
}
}
/////////////////////////////////////////////////////////////////////////////
2022-06-27 23:46:29 -04:00
lazy_static ::lazy_static! {
2025-02-10 03:06:41 +00:00
static ref INITIALIZED : Mutex < HashSet < InitKey > > = Mutex ::new ( HashSet ::new ( ) ) ;
static ref STARTUP_TABLE : AsyncTagLockTable < InitKey > = AsyncTagLockTable ::new ( ) ;
2022-06-27 23:46:29 -04:00
}
2022-02-06 21:18:42 -05:00
2023-09-01 21:13:05 -04:00
/// Initialize a Veilid node.
///
2024-08-17 01:01:30 +00:00
/// Must be called only once per 'program_name + namespace' combination at the start of an application.
/// The 'config_callback' must return a unique 'program_name + namespace' combination per simulataneous call to api_startup.
/// You can use the same program_name multiple times to create separate storage locations.
/// Multiple namespaces for the same program_name will use the same databases and on-disk locations, but will partition keys internally
/// to keep the namespaces distict.
2023-09-01 21:13:05 -04:00
///
2024-05-01 20:37:06 -04:00
/// * `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.
2023-09-01 21:13:05 -04:00
///
2024-05-01 20:37:06 -04:00
/// Returns a [VeilidAPI] object that can be used to operate the node.
2024-07-03 21:00:12 -04:00
#[ instrument(level = " trace " , target = " core_context " , err, skip_all) ]
2022-02-09 09:47:36 -05:00
pub async fn api_startup (
update_callback : UpdateCallback ,
config_callback : ConfigCallback ,
2023-05-29 19:24:57 +00:00
) -> VeilidAPIResult < VeilidAPI > {
2024-08-17 01:01:30 +00:00
// Get the program_name and namespace we're starting up in
let program_name = * config_callback ( " program_name " . to_owned ( ) ) ?
. downcast ::< String > ( )
. map_err ( | _ | {
VeilidAPIError ::invalid_argument ( " api_startup " , " config_callback " , " program_name " )
} ) ? ;
let namespace = * config_callback ( " namespace " . to_owned ( ) ) ?
. downcast ::< String > ( )
. map_err ( | _ | {
VeilidAPIError ::invalid_argument ( " api_startup " , " config_callback " , " namespace " )
} ) ? ;
let init_key = ( program_name , namespace ) ;
2025-02-10 03:06:41 +00:00
// Only allow one startup/shutdown per program_name+namespace combination simultaneously
let _tag_guard = STARTUP_TABLE . lock_tag ( init_key . clone ( ) ) . await ;
2022-02-09 09:47:36 -05:00
// See if we have an API started up already
2025-02-10 03:06:41 +00:00
if INITIALIZED . lock ( ) . contains ( & init_key ) {
2022-11-26 16:17:30 -05:00
apibail_already_initialized! ( ) ;
2022-02-09 09:47:36 -05: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 ) ;
2025-02-10 03:06:41 +00:00
// Add to the initialized set
INITIALIZED . lock ( ) . insert ( init_key ) ;
2022-02-09 09:47:36 -05:00
Ok ( veilid_api )
}
2024-05-01 20:37:06 -04:00
/// Initialize a Veilid node, with the configuration in JSON format.
2023-09-01 21:13:05 -04:00
///
2024-08-17 01:01:30 +00:00
/// Must be called only once per 'program_name + namespace' combination at the start of an application.
/// The 'config_json' must specify a unique 'program_name + namespace' combination per simulataneous call to api_startup.
/// You can use the same program_name multiple times to create separate storage locations.
/// Multiple namespaces for the same program_name will use the same databases and on-disk locations, but will partition keys internally
/// to keep the namespaces distict.
2023-09-01 21:13:05 -04:00
///
2024-05-01 20:37:06 -04:00
/// * `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.
2023-09-01 21:13:05 -04:00
///
2024-05-01 20:37:06 -04:00
/// Returns a [VeilidAPI] object that can be used to operate the node.
2024-07-03 21:00:12 -04:00
#[ instrument(level = " trace " , target = " core_context " , err, skip_all) ]
2022-02-09 09:47:36 -05:00
pub async fn api_startup_json (
update_callback : UpdateCallback ,
config_json : String ,
2023-05-29 19:24:57 +00:00
) -> VeilidAPIResult < VeilidAPI > {
2024-08-17 01:01:30 +00:00
// Parse the JSON config
let config : VeilidConfigInner =
serde_json ::from_str ( & config_json ) . map_err ( VeilidAPIError ::generic ) ? ;
2022-02-06 21:18:42 -05:00
2024-08-17 01:01:30 +00:00
api_startup_config ( update_callback , config ) . await
2022-02-06 21:18:42 -05:00
}
2024-05-01 20:37:06 -04:00
/// Initialize a Veilid node, with the configuration object.
2024-01-05 15:12:17 -08:00
///
2024-05-01 20:37:06 -04:00
/// Must be called only once at the start of an application.
2024-01-05 15:12:17 -08:00
///
2024-05-01 20:37:06 -04:00
/// * `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` - called at startup to supply a configuration object.
2024-01-05 15:12:17 -08:00
///
2024-05-01 20:37:06 -04:00
/// Returns a [VeilidAPI] object that can be used to operate the node.
2024-07-03 21:00:12 -04:00
#[ instrument(level = " trace " , target = " core_context " , err, skip_all) ]
2024-01-05 15:12:17 -08:00
pub async fn api_startup_config (
update_callback : UpdateCallback ,
config : VeilidConfigInner ,
) -> VeilidAPIResult < VeilidAPI > {
2024-08-17 01:01:30 +00:00
// Get the program_name and namespace we're starting up in
let program_name = config . program_name . clone ( ) ;
let namespace = config . namespace . clone ( ) ;
let init_key = ( program_name , namespace ) ;
2025-02-10 03:06:41 +00:00
// Only allow one startup/shutdown per program_name+namespace combination simultaneously
let _tag_guard = STARTUP_TABLE . lock_tag ( init_key . clone ( ) ) . await ;
2024-01-05 15:12:17 -08:00
// See if we have an API started up already
2025-02-10 03:06:41 +00:00
if INITIALIZED . lock ( ) . contains ( & init_key ) {
2024-01-05 15:12:17 -08:00
apibail_already_initialized! ( ) ;
}
// Create core context
let context = VeilidCoreContext ::new_with_config ( update_callback , config ) . await ? ;
// Return an API object around our context
let veilid_api = VeilidAPI ::new ( context ) ;
2025-02-10 03:06:41 +00:00
// Add to the initialized set
INITIALIZED . lock ( ) . insert ( init_key ) ;
2024-01-05 15:12:17 -08:00
Ok ( veilid_api )
}
2024-07-03 21:00:12 -04:00
#[ instrument(level = " trace " , target = " core_context " , skip_all) ]
2025-02-10 03:06:41 +00:00
pub ( crate ) async fn api_shutdown ( context : VeilidCoreContext ) {
2024-08-17 01:01:30 +00:00
let init_key = {
2025-02-10 03:06:41 +00:00
let registry = context . registry ( ) ;
let config = registry . config ( ) ;
let cfginner = config . get ( ) ;
( cfginner . program_name . clone ( ) , cfginner . namespace . clone ( ) )
2024-08-17 01:01:30 +00:00
} ;
2025-02-10 03:06:41 +00:00
// Only allow one startup/shutdown per program_name+namespace combination simultaneously
let _tag_guard = STARTUP_TABLE . lock_tag ( init_key . clone ( ) ) . await ;
// See if we have an API started up already
if ! INITIALIZED . lock ( ) . contains ( & init_key ) {
return ;
}
// Shutdown the context
2022-02-06 21:18:42 -05:00
context . shutdown ( ) . await ;
2025-02-10 03:06:41 +00:00
// Remove from the initialized set
INITIALIZED . lock ( ) . remove ( & init_key ) ;
2022-02-06 21:18:42 -05:00
}