From 7a55be8015c4ba95b38adbdbda2b0c94556c9e28 Mon Sep 17 00:00:00 2001 From: Salvatore Testa Date: Fri, 5 Jan 2024 15:12:17 -0800 Subject: [PATCH] Add VeilidConfigInner-based VeilidAPI startup Allow for a type-safe initialization of the API Closes https://gitlab.com/veilid/veilid/-/issues/354 --- veilid-core/src/core_context.rs | 43 +++++++++++++++++++ veilid-core/src/lib.rs | 5 ++- .../src/tests/common/test_veilid_core.rs | 32 ++++++++++++++ veilid-core/src/veilid_config.rs | 29 ++++++++++++- 4 files changed, 106 insertions(+), 3 deletions(-) diff --git a/veilid-core/src/core_context.rs b/veilid-core/src/core_context.rs index e8f79ab3..c77bed93 100644 --- a/veilid-core/src/core_context.rs +++ b/veilid-core/src/core_context.rs @@ -237,6 +237,19 @@ impl VeilidCoreContext { Self::new_common(update_callback, config).await } + + #[instrument(err, skip_all)] + async fn new_with_config( + update_callback: UpdateCallback, + config_inner: VeilidConfigInner, + ) -> VeilidAPIResult { + // Set up config from json + trace!("setup config with json"); + let mut config = VeilidConfig::new(); + config.setup_from_config(config_inner, update_callback.clone())?; + Self::new_common(update_callback, config).await + } + #[instrument(err, skip_all)] async fn new_common( update_callback: UpdateCallback, @@ -350,6 +363,36 @@ pub async fn api_startup_json( Ok(veilid_api) } +/// Initialize a Veilid node, with the configuration object +/// +/// 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` - called at startup to supply a configuration object +/// +/// Returns a [VeilidAPI] object that can be used to operate the node +#[instrument(err, skip_all)] +pub async fn api_startup_config( + update_callback: UpdateCallback, + config: VeilidConfigInner, +) -> VeilidAPIResult { + // 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) +} + #[instrument(skip_all)] pub(crate) async fn api_shutdown(context: VeilidCoreContext) { let mut initialized_lock = INITIALIZED.lock().await; diff --git a/veilid-core/src/lib.rs b/veilid-core/src/lib.rs index 4086c598..9cf19d6c 100644 --- a/veilid-core/src/lib.rs +++ b/veilid-core/src/lib.rs @@ -5,7 +5,8 @@ //! `veilid-core` contains all of the core logic for Veilid and can be used in mobile applications as well as desktop //! and in-browser WebAssembly apps. //! -//! The public API is accessed by getting a [VeilidAPI] object via a call to [api_startup] or [api_startup_json]. +//! The public API is accessed by getting a [VeilidAPI] object via a call to [api_startup], [api_startup_json], or +//! [api_startup_config]. //! //! From there, a [RoutingContext] object can get you access to public and private routed operations. //! @@ -59,7 +60,7 @@ mod veilid_layer_filter; mod wasm_helpers; pub use self::api_tracing_layer::ApiTracingLayer; -pub use self::core_context::{api_startup, api_startup_json, UpdateCallback}; +pub use self::core_context::{api_startup, api_startup_json, api_startup_config, UpdateCallback}; pub use self::veilid_api::*; pub use self::veilid_config::*; pub use self::veilid_layer_filter::*; diff --git a/veilid-core/src/tests/common/test_veilid_core.rs b/veilid-core/src/tests/common/test_veilid_core.rs index e1f20f3e..70b864cd 100644 --- a/veilid-core/src/tests/common/test_veilid_core.rs +++ b/veilid-core/src/tests/common/test_veilid_core.rs @@ -12,6 +12,37 @@ pub async fn test_startup_shutdown() { trace!("test_startup_shutdown: finished"); } +pub async fn test_startup_shutdown_from_config() { + trace!("test_startup_from_config: starting"); + let config = VeilidConfigInner { + program_name: "VeilidCoreTests".into(), + table_store: VeilidConfigTableStore { + directory: get_table_store_path(), + delete: true, + ..Default::default() + }, + block_store: VeilidConfigBlockStore { + directory: get_block_store_path(), + delete: true, + ..Default::default() + }, + protected_store: VeilidConfigProtectedStore { + allow_insecure_fallback: true, + directory: get_protected_store_path(), + device_encryption_key_password: "".to_owned(), + delete: true, + ..Default::default() + }, + ..Default::default() + }; + let api = api_startup_config(Arc::new(|_: VeilidUpdate| {}), config) + .await + .expect("startup failed"); + trace!("test_startup_from_config: shutting down"); + api.shutdown().await; + trace!("test_startup_from_config: finished"); +} + pub async fn test_attach_detach() { info!("--- test normal order ---"); let (update_callback, config_callback) = setup_veilid_core(); @@ -44,5 +75,6 @@ pub async fn test_attach_detach() { pub async fn test_all() { test_startup_shutdown().await; + test_startup_shutdown_from_config().await; test_attach_detach().await; } diff --git a/veilid-core/src/veilid_config.rs b/veilid-core/src/veilid_config.rs index f9c55b2e..8f0f9d2b 100644 --- a/veilid-core/src/veilid_config.rs +++ b/veilid-core/src/veilid_config.rs @@ -207,7 +207,7 @@ pub struct VeilidConfigDHT { /// Configure RPC /// -#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(target_arch = "wasm32", derive(Tsify))] pub struct VeilidConfigRPC { pub concurrency: u32, @@ -221,6 +221,20 @@ pub struct VeilidConfigRPC { pub default_route_hop_count: u8, } +impl Default for VeilidConfigRPC { + fn default() -> Self { + Self { + concurrency: 0, + queue_size: 1024, + max_timestamp_behind_ms: None, + max_timestamp_ahead_ms: None, + timeout_ms: 5000, + max_route_hop_count: 4, + default_route_hop_count: 1, + } + } +} + /// Configure the network routing table /// #[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] @@ -446,6 +460,19 @@ impl VeilidConfig { }) } + pub fn setup_from_config( + &mut self, + config: VeilidConfigInner, + update_cb: UpdateCallback, + ) -> VeilidAPIResult<()> { + self.update_cb = Some(update_cb); + + self.with_mut(|inner| { + *inner = config; + Ok(()) + }) + } + pub fn setup(&mut self, cb: ConfigCallback, update_cb: UpdateCallback) -> VeilidAPIResult<()> { self.update_cb = Some(update_cb); self.with_mut(|inner| {