2022-02-06 21:18:42 -05:00
use crate ::attachment_manager ::* ;
2022-10-30 19:29:31 -04:00
use crate ::crypto ::Crypto ;
2024-03-07 16:49:59 -05:00
use crate ::logging ::* ;
2023-05-29 19:24:57 +00:00
use crate ::storage_manager ::* ;
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
2024-05-01 20:37:06 -04:00
/// Internal services startup mechanism.
2023-05-29 19:24:57 +00:00
/// Ensures that everything is started up, and shut down in the right order
2024-05-01 20:37:06 -04:00
/// and provides an atomic state for if the system is properly operational.
2022-03-08 22:32:12 -05:00
struct ServicesContext {
2022-02-06 21:18:42 -05:00
pub config : VeilidConfig ,
2022-02-15 13:40:17 -05:00
pub update_callback : UpdateCallback ,
2022-03-08 22:32:12 -05:00
pub protected_store : Option < ProtectedStore > ,
pub table_store : Option < TableStore > ,
2023-06-04 21:22:55 -04:00
#[ cfg(feature = " unstable-blockstore " ) ]
2022-03-08 22:32:12 -05: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-06 21:18:42 -05:00
}
2022-03-08 22:32:12 -05: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-04 21:22:55 -04:00
#[ cfg(feature = " unstable-blockstore " ) ]
2022-03-08 22:32:12 -05:00
block_store : None ,
crypto : None ,
attachment_manager : None ,
2023-05-29 19:24:57 +00:00
storage_manager : None ,
2022-02-09 09:47:36 -05:00
}
}
2022-03-08 22:32:12 -05:00
pub fn new_full (
config : VeilidConfig ,
2022-02-09 09:47:36 -05:00
update_callback : UpdateCallback ,
2022-03-08 22:32:12 -05:00
protected_store : ProtectedStore ,
table_store : TableStore ,
2023-06-04 21:22:55 -04:00
#[ cfg(feature = " unstable-blockstore " ) ] block_store : BlockStore ,
2022-03-08 22:32:12 -05:00
crypto : Crypto ,
attachment_manager : AttachmentManager ,
2023-05-29 19:24:57 +00:00
storage_manager : StorageManager ,
2022-03-08 22:32:12 -05:00
) -> Self {
Self {
config ,
update_callback ,
protected_store : Some ( protected_store ) ,
table_store : Some ( table_store ) ,
2023-06-04 21:22:55 -04:00
#[ cfg(feature = " unstable-blockstore " ) ]
2022-03-08 22:32:12 -05: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-06 21:18:42 -05:00
}
2022-02-09 09:47:36 -05:00
}
2022-02-06 21:18:42 -05:00
2022-06-10 17:07:10 -04:00
#[ instrument(err, skip_all) ]
2022-07-10 17:36:50 -04:00
pub async fn startup ( & mut self ) -> EyreResult < ( ) > {
2022-03-11 07:35:41 -05:00
info! ( " Veilid API starting up " ) ;
2022-03-08 22:32:12 -05:00
2022-07-01 12:13:52 -04:00
info! ( " init api tracing " ) ;
ApiTracingLayer ::init ( self . update_callback . clone ( ) ) . await ;
2022-02-06 21:18:42 -05:00
// Set up protected store
2022-03-08 22:32:12 -05:00
let protected_store = ProtectedStore ::new ( self . config . clone ( ) ) ;
2022-02-06 21:18:42 -05: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-08 22:32:12 -05:00
self . shutdown ( ) . await ;
2022-07-10 17:36:50 -04:00
return Err ( e ) ;
2022-02-06 21:18:42 -05:00
}
2022-03-08 22:32:12 -05:00
self . protected_store = Some ( protected_store . clone ( ) ) ;
2022-02-06 21:18:42 -05:00
2023-05-29 19:24:57 +00:00
// Set up tablestore 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-02-06 21:18:42 -05: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-08 22:32:12 -05:00
self . shutdown ( ) . await ;
2022-07-10 17:36:50 -04:00
return Err ( e ) ;
2022-02-06 21:18:42 -05:00
}
2022-03-08 22:32:12 -05:00
self . table_store = Some ( table_store . clone ( ) ) ;
2022-02-06 21:18:42 -05:00
// Set up crypto
if let Err ( e ) = crypto . init ( ) . await {
2023-05-29 19:24:57 +00:00
error! ( " failed to init crypto: {} " , e ) ;
2022-03-08 22:32:12 -05:00
self . shutdown ( ) . await ;
2022-07-10 17:36:50 -04:00
return Err ( e ) ;
2022-02-06 21:18:42 -05:00
}
2022-03-08 22:32:12 -05:00
self . crypto = Some ( crypto . clone ( ) ) ;
2022-02-06 21:18:42 -05:00
// Set up block store
2023-06-04 21:22:55 -04:00
#[ cfg(feature = " unstable-blockstore " ) ]
{
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-06 21:18:42 -05:00
}
2023-05-29 19:24:57 +00:00
// Set up storage manager
2023-12-04 22:01:50 -05:00
let update_callback = self . update_callback . clone ( ) ;
2023-05-29 19:24:57 +00:00
let storage_manager = StorageManager ::new (
self . config . clone ( ) ,
self . crypto . clone ( ) . unwrap ( ) ,
self . table_store . clone ( ) . unwrap ( ) ,
2023-06-04 21:22:55 -04:00
#[ cfg(feature = " unstable-blockstore " ) ]
2023-05-29 19:24:57 +00:00
self . block_store . clone ( ) . unwrap ( ) ,
) ;
2023-12-04 22:01:50 -05:00
if let Err ( e ) = storage_manager . init ( update_callback ) . await {
2023-05-29 19:24:57 +00:00
error! ( " failed to init storage manager: {} " , e ) ;
self . shutdown ( ) . await ;
return Err ( e ) ;
}
self . storage_manager = Some ( storage_manager . clone ( ) ) ;
2022-02-06 21:18:42 -05:00
// Set up attachment manager
2022-03-24 10:14:50 -04:00
let update_callback = self . update_callback . clone ( ) ;
2022-10-30 19:29:31 -04:00
let attachment_manager = AttachmentManager ::new (
self . config . clone ( ) ,
2023-05-29 19:24:57 +00:00
storage_manager ,
2022-10-30 19:29:31 -04:00
table_store ,
2023-06-04 21:22:55 -04:00
#[ cfg(feature = " unstable-blockstore " ) ]
2022-10-30 19:29:31 -04:00
block_store ,
crypto ,
) ;
2022-03-24 10:14:50 -04: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-08 22:32:12 -05:00
self . shutdown ( ) . await ;
2022-07-10 17:36:50 -04:00
return Err ( e ) ;
2022-03-08 22:32:12 -05:00
}
self . attachment_manager = Some ( attachment_manager ) ;
2022-03-11 07:35:41 -05:00
info! ( " Veilid API startup complete " ) ;
2022-03-08 22:32:12 -05:00
Ok ( ( ) )
}
2022-06-10 17:07:10 -04:00
#[ instrument(skip_all) ]
2022-03-08 22:32:12 -05:00
pub async fn shutdown ( & mut self ) {
2022-03-11 07:35:41 -05:00
info! ( " Veilid API shutting down " ) ;
2022-03-08 22:32:12 -05:00
if let Some ( attachment_manager ) = & mut self . attachment_manager {
attachment_manager . terminate ( ) . await ;
}
2023-05-29 19:24:57 +00:00
if let Some ( storage_manager ) = & mut self . storage_manager {
storage_manager . terminate ( ) . await ;
}
2023-06-04 21:22:55 -04:00
#[ cfg(feature = " unstable-blockstore " ) ]
2022-03-08 22:32:12 -05:00
if let Some ( block_store ) = & mut self . block_store {
2022-02-06 21:18:42 -05:00
block_store . terminate ( ) . await ;
2022-03-08 22:32:12 -05:00
}
if let Some ( crypto ) = & mut self . crypto {
2022-02-06 21:18:42 -05:00
crypto . terminate ( ) . await ;
2022-03-08 22:32:12 -05:00
}
if let Some ( table_store ) = & mut self . table_store {
2022-02-06 21:18:42 -05:00
table_store . terminate ( ) . await ;
2022-03-08 22:32:12 -05:00
}
if let Some ( protected_store ) = & mut self . protected_store {
2022-02-06 21:18:42 -05:00
protected_store . terminate ( ) . await ;
2022-03-08 22:32:12 -05:00
}
2022-03-11 07:35:41 -05:00
info! ( " Veilid API shutdown complete " ) ;
2022-03-08 22:32:12 -05:00
// api logger terminate is idempotent
2022-06-07 21:31:05 -04:00
ApiTracingLayer ::terminate ( ) . await ;
2022-03-08 22:32:12 -05:00
// send final shutdown update
2022-03-11 07:35:41 -05:00
( self . update_callback ) ( VeilidUpdate ::Shutdown ) ;
2022-03-08 22:32:12 -05:00
}
}
/////////////////////////////////////////////////////////////////////////////
2023-10-25 22:32:06 -04:00
pub ( crate ) struct VeilidCoreContext {
2022-03-08 22:32:12 -05:00
pub config : VeilidConfig ,
pub update_callback : UpdateCallback ,
// Services
2023-05-29 19:24:57 +00:00
pub storage_manager : StorageManager ,
2022-03-08 22:32:12 -05:00
pub protected_store : ProtectedStore ,
pub table_store : TableStore ,
2023-06-04 21:22:55 -04:00
#[ cfg(feature = " unstable-blockstore " ) ]
2022-03-08 22:32:12 -05:00
pub block_store : BlockStore ,
pub crypto : Crypto ,
pub attachment_manager : AttachmentManager ,
}
impl VeilidCoreContext {
2022-06-10 17:07:10 -04:00
#[ instrument(err, skip_all) ]
2022-03-08 22:32:12 -05: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-08 22:32:12 -05:00
// Set up config from callback
let mut config = VeilidConfig ::new ( ) ;
2022-11-16 12:49:53 -05:00
config . setup ( config_callback , update_callback . clone ( ) ) ? ;
2022-02-06 21:18:42 -05:00
2022-03-08 22:32:12 -05:00
Self ::new_common ( update_callback , config ) . await
2022-02-06 21:18:42 -05:00
}
2022-06-11 18:47:58 -04:00
#[ instrument(err, skip_all) ]
2022-03-08 22:32:12 -05:00
async fn new_with_config_json (
update_callback : UpdateCallback ,
config_json : String ,
2023-05-29 19:24:57 +00:00
) -> VeilidAPIResult < VeilidCoreContext > {
2023-08-16 10:25:09 -04:00
// Set up config from json
2022-03-08 22:32:12 -05:00
let mut config = VeilidConfig ::new ( ) ;
2022-11-16 12:49:53 -05:00
config . setup_from_json ( config_json , update_callback . clone ( ) ) ? ;
2022-03-08 22:32:12 -05:00
Self ::new_common ( update_callback , config ) . await
}
2022-02-06 21:18:42 -05:00
2024-01-05 15:12:17 -08:00
#[ instrument(err, skip_all) ]
async fn new_with_config (
update_callback : UpdateCallback ,
config_inner : VeilidConfigInner ,
) -> VeilidAPIResult < VeilidCoreContext > {
// Set up config from json
let mut config = VeilidConfig ::new ( ) ;
config . setup_from_config ( config_inner , update_callback . clone ( ) ) ? ;
Self ::new_common ( update_callback , config ) . await
}
2022-06-11 18:47:58 -04:00
#[ instrument(err, skip_all) ]
2022-03-08 22:32:12 -05:00
async fn new_common (
update_callback : UpdateCallback ,
config : VeilidConfig ,
2023-05-29 19:24:57 +00:00
) -> VeilidAPIResult < VeilidCoreContext > {
2022-03-08 22:32:12 -05:00
cfg_if! {
if #[ cfg(target_os = " android " ) ] {
2022-12-01 14:32:02 -05:00
if ! crate ::intf ::android ::is_android_ready ( ) {
2022-11-26 16:17:30 -05:00
apibail_internal! ( " Android globals are not set up " ) ;
2022-03-08 22:32:12 -05:00
}
}
}
2022-02-06 21:18:42 -05:00
2022-03-08 22:32:12 -05:00
let mut sc = ServicesContext ::new_empty ( config . clone ( ) , update_callback ) ;
2022-07-10 17:36:50 -04:00
sc . startup ( ) . await . map_err ( VeilidAPIError ::generic ) ? ;
2022-02-15 13:40:17 -05:00
2022-03-08 22:32:12 -05: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-08 22:32:12 -05:00
protected_store : sc . protected_store . unwrap ( ) ,
table_store : sc . table_store . unwrap ( ) ,
2023-06-04 21:22:55 -04:00
#[ cfg(feature = " unstable-blockstore " ) ]
2022-03-08 22:32:12 -05:00
block_store : sc . block_store . unwrap ( ) ,
crypto : sc . crypto . unwrap ( ) ,
attachment_manager : sc . attachment_manager . unwrap ( ) ,
} )
}
2022-06-10 17:07:10 -04:00
#[ instrument(skip_all) ]
2022-03-08 22:32:12 -05: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-04 21:22:55 -04:00
#[ cfg(feature = " unstable-blockstore " ) ]
2022-03-08 22:32:12 -05:00
self . block_store ,
self . crypto ,
self . attachment_manager ,
2023-05-29 19:24:57 +00:00
self . storage_manager ,
2022-03-08 22:32:12 -05:00
) ;
sc . shutdown ( ) . await ;
2022-02-06 21:18:42 -05:00
}
}
/////////////////////////////////////////////////////////////////////////////
2022-06-27 23:46:29 -04:00
lazy_static ::lazy_static! {
static ref INITIALIZED : AsyncMutex < bool > = AsyncMutex ::new ( false ) ;
}
2022-02-06 21:18:42 -05:00
2023-09-01 21:13:05 -04:00
/// Initialize a Veilid node.
///
2024-05-01 20:37:06 -04:00
/// Must be called only once at the start of an application.
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.
2022-06-10 17:07:10 -04:00
#[ instrument(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 > {
2022-02-09 09:47:36 -05:00
// See if we have an API started up already
let mut initialized_lock = INITIALIZED . lock ( ) . await ;
if * initialized_lock {
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 ) ;
* initialized_lock = true ;
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-05-01 20:37:06 -04:00
/// Must be called only once at the start of an application.
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.
2023-08-26 02:01:57 +00:00
#[ instrument(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 > {
2022-02-06 21:18:42 -05:00
// See if we have an API started up already
let mut initialized_lock = INITIALIZED . lock ( ) . await ;
if * initialized_lock {
2022-11-26 16:17:30 -05:00
apibail_already_initialized! ( ) ;
2022-02-06 21:18:42 -05:00
}
// Create core context
2022-02-09 09:47:36 -05:00
let context = VeilidCoreContext ::new_with_config_json ( update_callback , config_json ) . await ? ;
2022-02-06 21:18:42 -05:00
// Return an API object around our context
let veilid_api = VeilidAPI ::new ( context ) ;
* initialized_lock = true ;
Ok ( veilid_api )
}
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-01-05 15:12:17 -08:00
#[ instrument(err, skip_all) ]
pub async fn api_startup_config (
update_callback : UpdateCallback ,
config : VeilidConfigInner ,
) -> VeilidAPIResult < VeilidAPI > {
// See if we have an API started up already
let mut initialized_lock = INITIALIZED . lock ( ) . await ;
if * initialized_lock {
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 ) ;
* initialized_lock = true ;
Ok ( veilid_api )
}
2022-06-10 17:07:10 -04:00
#[ instrument(skip_all) ]
2022-03-08 22:32:12 -05:00
pub ( crate ) async fn api_shutdown ( context : VeilidCoreContext ) {
2022-02-06 21:18:42 -05:00
let mut initialized_lock = INITIALIZED . lock ( ) . await ;
context . shutdown ( ) . await ;
* initialized_lock = false ;
}