diff --git a/Cargo.lock b/Cargo.lock index 35ce4de4..30c41ac7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3922,6 +3922,7 @@ dependencies = [ "serde 1.0.136", "serde-big-array", "serde_cbor", + "serde_json", "serial_test 0.5.1", "simplelog", "socket2", diff --git a/veilid-core/Cargo.toml b/veilid-core/Cargo.toml index 6b491aef..0bbd5b80 100644 --- a/veilid-core/Cargo.toml +++ b/veilid-core/Cargo.toml @@ -63,6 +63,7 @@ keyvaluedb-sqlite = { path = "../external/keyvaluedb/keyvaluedb-sqlite" } data-encoding = { version = "^2" } serde = { version = "^1", features = ["derive" ] } serde_cbor = { version = "^0" } +serde_json = { version = "^1" } async_executors = { version = "^0", default-features = false, features = [ "async_std" ]} socket2 = "^0" bugsalot = "^0" @@ -84,6 +85,7 @@ keyvaluedb-web = { path = "../external/keyvaluedb/keyvaluedb-web" } data-encoding = { version = "^2", default_features = false, features = ["alloc"] } serde = { version = "^1", default-features = false, features = ["derive", "alloc"] } serde_cbor = { version = "^0", default-features = false, features = ["alloc"] } +serde_json = { version = "^1", default-features = false, features = ["alloc"] } getrandom = { version = "^0", features = ["js"] } ws_stream_wasm = "^0" async_executors = { version = "^0", default-features = false, features = [ "bindgen" ]} diff --git a/veilid-core/src/core_context.rs b/veilid-core/src/core_context.rs index fad355ae..f088cf5f 100644 --- a/veilid-core/src/core_context.rs +++ b/veilid-core/src/core_context.rs @@ -14,11 +14,6 @@ cfg_if! { } } -pub struct VeilidCoreSetup { - pub update_callback: UpdateCallback, - pub config_callback: ConfigCallback, -} - pub struct VeilidCoreContext { pub config: VeilidConfig, pub protected_store: ProtectedStore, @@ -29,46 +24,56 @@ pub struct VeilidCoreContext { } impl VeilidCoreContext { - async fn new(setup: VeilidCoreSetup) -> Result { - // 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); - } + async fn new_with_config_callback( + update_callback: UpdateCallback, + config_callback: ConfigCallback, + ) -> Result { + // Set up config from callback + trace!("VeilidCoreContext::new_with_config_callback init config"); + let mut config = VeilidConfig::new(); + if let Err(e) = config.init(config_callback).await { + return Err(VeilidAPIError::Internal { message: e }); } - trace!("VeilidCoreContext::new starting"); + Self::new_common(update_callback, config).await + } + async fn new_with_config_json( + update_callback: UpdateCallback, + config_json: String, + ) -> Result { + // Set up config from callback + trace!("VeilidCoreContext::new_with_config_json init config"); + let mut config = VeilidConfig::new(); + if let Err(e) = config.init_from_json(config_json).await { + return Err(VeilidAPIError::Internal { message: e }); + } + + Self::new_common(update_callback, config).await + } + + async fn new_common( + update_callback: UpdateCallback, + config: VeilidConfig, + ) -> Result { cfg_if! { if #[cfg(target_os = "android")] { if utils::android::ANDROID_GLOBALS.lock().is_none() { error!("Android globals are not set up"); + config.terminate().await; 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)); + // Start up api logging + let api_log_level: VeilidConfigLogLevel = config.get().api_log_level; + if api_log_level != VeilidConfigLogLevel::Off { + ApiLogger::init(api_log_level.to_level_filter(), update_callback.clone()); + for ig in crate::DEFAULT_LOG_IGNORE_LIST { + ApiLogger::add_filter_ignore_str(ig); + } + info!("Veilid API logging initialized"); } // Set up protected store @@ -77,7 +82,7 @@ impl VeilidCoreContext { if let Err(e) = protected_store.init().await { config.terminate().await; ApiLogger::terminate(); - return Err(VeilidAPIError::Internal(e)); + return Err(VeilidAPIError::Internal { message: e }); } // Init node id from config now that protected store is set up @@ -85,7 +90,7 @@ impl VeilidCoreContext { protected_store.terminate().await; config.terminate().await; ApiLogger::terminate(); - return Err(VeilidAPIError::Internal(e)); + return Err(VeilidAPIError::Internal { message: e }); } // Set up tablestore @@ -95,7 +100,7 @@ impl VeilidCoreContext { protected_store.terminate().await; config.terminate().await; ApiLogger::terminate(); - return Err(VeilidAPIError::Internal(e)); + return Err(VeilidAPIError::Internal { message: e }); } // Set up crypto @@ -106,7 +111,7 @@ impl VeilidCoreContext { protected_store.terminate().await; config.terminate().await; ApiLogger::terminate(); - return Err(VeilidAPIError::Internal(e)); + return Err(VeilidAPIError::Internal { message: e }); } // Set up block store @@ -118,18 +123,17 @@ impl VeilidCoreContext { protected_store.terminate().await; config.terminate().await; ApiLogger::terminate(); - return Err(VeilidAPIError::Internal(e)); + return Err(VeilidAPIError::Internal { message: 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)) + update_callback(VeilidUpdate::Attachment { state: new_state }) }, )) .await @@ -140,7 +144,7 @@ impl VeilidCoreContext { protected_store.terminate().await; config.terminate().await; ApiLogger::terminate(); - return Err(VeilidAPIError::Internal(e)); + return Err(VeilidAPIError::Internal { message: e }); } Ok(VeilidCoreContext { @@ -172,7 +176,10 @@ impl VeilidCoreContext { static INITIALIZED: AsyncMutex = AsyncMutex::new(false); -pub async fn api_startup(setup: VeilidCoreSetup) -> Result { +pub async fn api_startup( + update_callback: UpdateCallback, + config_callback: ConfigCallback, +) -> Result { // See if we have an API started up already let mut initialized_lock = INITIALIZED.lock().await; if *initialized_lock { @@ -180,7 +187,29 @@ pub async fn api_startup(setup: VeilidCoreSetup) -> Result Result { + // 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_with_config_json(update_callback, config_json).await?; // Return an API object around our context let veilid_api = VeilidAPI::new(context); diff --git a/veilid-core/src/lib.rs b/veilid-core/src/lib.rs index 953388a2..07bd575d 100644 --- a/veilid-core/src/lib.rs +++ b/veilid-core/src/lib.rs @@ -26,7 +26,7 @@ mod veilid_rng; pub mod xx; pub use self::attachment_manager::AttachmentState; -pub use self::core_context::{api_startup, VeilidCoreSetup}; +pub use self::core_context::{api_startup, api_startup_json, UpdateCallback}; pub use self::veilid_api::*; pub use self::veilid_config::*; diff --git a/veilid-core/src/tests/common/test_crypto.rs b/veilid-core/src/tests/common/test_crypto.rs index 689e599f..8e8079b7 100644 --- a/veilid-core/src/tests/common/test_crypto.rs +++ b/veilid-core/src/tests/common/test_crypto.rs @@ -6,22 +6,10 @@ use crate::*; static LOREM_IPSUM:&[u8] = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. "; -fn setup_veilid_core() -> VeilidCoreSetup { - VeilidCoreSetup { - update_callback: Arc::new( - move |veilid_update: VeilidUpdate| -> SystemPinBoxFuture<()> { - Box::pin(async move { - trace!("update_callback: {:?}", veilid_update); - }) - }, - ), - config_callback: Arc::new(config_callback), - } -} - async fn startup() -> VeilidAPI { trace!("test_table_store: starting"); - let api = api_startup(setup_veilid_core()) + let (update_callback, config_callback) = setup_veilid_core(); + let api = api_startup(update_callback, config_callback) .await .expect("startup failed"); api diff --git a/veilid-core/src/tests/common/test_envelope_receipt.rs b/veilid-core/src/tests/common/test_envelope_receipt.rs index f353b527..2223943a 100644 --- a/veilid-core/src/tests/common/test_envelope_receipt.rs +++ b/veilid-core/src/tests/common/test_envelope_receipt.rs @@ -8,7 +8,8 @@ use crate::*; pub async fn test_envelope_round_trip() { info!("--- test envelope round trip ---"); - let api = api_startup(setup_veilid_core()) + let (update_callback, config_callback) = setup_veilid_core(); + let api = api_startup(update_callback, config_callback) .await .expect("startup failed"); diff --git a/veilid-core/src/tests/common/test_protected_store.rs b/veilid-core/src/tests/common/test_protected_store.rs index 269756dc..8e770513 100644 --- a/veilid-core/src/tests/common/test_protected_store.rs +++ b/veilid-core/src/tests/common/test_protected_store.rs @@ -3,22 +3,10 @@ use crate::intf::*; use crate::xx::*; use crate::*; -fn setup_veilid_core() -> VeilidCoreSetup { - VeilidCoreSetup { - update_callback: Arc::new( - move |veilid_update: VeilidUpdate| -> SystemPinBoxFuture<()> { - Box::pin(async move { - trace!("update_callback: {:?}", veilid_update); - }) - }, - ), - config_callback: Arc::new(config_callback), - } -} - async fn startup() -> VeilidAPI { trace!("test_table_store: starting"); - api_startup(setup_veilid_core()) + let (update_callback, config_callback) = setup_veilid_core(); + api_startup(update_callback, config_callback) .await .expect("startup failed") } diff --git a/veilid-core/src/tests/common/test_table_store.rs b/veilid-core/src/tests/common/test_table_store.rs index 44975ec3..40e0e384 100644 --- a/veilid-core/src/tests/common/test_table_store.rs +++ b/veilid-core/src/tests/common/test_table_store.rs @@ -4,22 +4,10 @@ use crate::intf::*; use crate::xx::*; use crate::*; -fn setup_veilid_core() -> VeilidCoreSetup { - VeilidCoreSetup { - update_callback: Arc::new( - move |veilid_update: VeilidUpdate| -> SystemPinBoxFuture<()> { - Box::pin(async move { - trace!("update_callback: {:?}", veilid_update); - }) - }, - ), - config_callback: Arc::new(config_callback), - } -} - async fn startup() -> VeilidAPI { trace!("test_table_store: starting"); - api_startup(setup_veilid_core()) + let (update_callback, config_callback) = setup_veilid_core(); + api_startup(update_callback, config_callback) .await .expect("startup failed") } diff --git a/veilid-core/src/tests/common/test_veilid_config.rs b/veilid-core/src/tests/common/test_veilid_config.rs index 514587b0..9d569dc7 100644 --- a/veilid-core/src/tests/common/test_veilid_config.rs +++ b/veilid-core/src/tests/common/test_veilid_config.rs @@ -158,20 +158,20 @@ cfg_if! { } } -pub fn setup_veilid_core() -> VeilidCoreSetup { - VeilidCoreSetup { - update_callback: Arc::new( +pub fn setup_veilid_core() -> (UpdateCallback, ConfigCallback) { + ( + Arc::new( move |veilid_update: VeilidUpdate| -> SystemPinBoxFuture<()> { Box::pin(async move { trace!("update_callback: {:?}", veilid_update); }) }, ), - config_callback: Arc::new(config_callback), - } + Arc::new(config_callback), + ) } -pub fn config_callback(key: String) -> ConfigCallbackReturn { +fn config_callback(key: String) -> ConfigCallbackReturn { match key.as_str() { "program_name" => Ok(Box::new(String::from("Veilid"))), "namespace" => Ok(Box::new(String::from(""))), diff --git a/veilid-core/src/tests/common/test_veilid_core.rs b/veilid-core/src/tests/common/test_veilid_core.rs index 889469c5..5847c32a 100644 --- a/veilid-core/src/tests/common/test_veilid_core.rs +++ b/veilid-core/src/tests/common/test_veilid_core.rs @@ -4,7 +4,8 @@ use crate::*; pub async fn test_startup_shutdown() { trace!("test_startup_shutdown: starting"); - let api = api_startup(setup_veilid_core()) + let (update_callback, config_callback) = setup_veilid_core(); + let api = api_startup(update_callback, config_callback) .await .expect("startup failed"); trace!("test_startup_shutdown: shutting down"); @@ -14,19 +15,26 @@ pub async fn test_startup_shutdown() { pub async fn test_attach_detach() { info!("--- test normal order ---"); - let api = api_startup(setup_veilid_core()) + let (update_callback, config_callback) = setup_veilid_core(); + let api = api_startup(update_callback, config_callback) .await .expect("startup failed"); api.attach().await.unwrap(); intf::sleep(5000).await; api.detach().await.unwrap(); - api.wait_for_update(VeilidUpdate::Attachment(AttachmentState::Detached), None) - .await - .unwrap(); + api.wait_for_update( + VeilidUpdate::Attachment { + state: AttachmentState::Detached, + }, + None, + ) + .await + .unwrap(); api.shutdown().await; info!("--- test auto detach ---"); - let api = api_startup(setup_veilid_core()) + let (update_callback, config_callback) = setup_veilid_core(); + let api = api_startup(update_callback, config_callback) .await .expect("startup failed"); api.attach().await.unwrap(); @@ -34,7 +42,8 @@ pub async fn test_attach_detach() { api.shutdown().await; info!("--- test detach without attach ---"); - let api = api_startup(setup_veilid_core()) + let (update_callback, config_callback) = setup_veilid_core(); + let api = api_startup(update_callback, config_callback) .await .expect("startup failed"); api.detach().await.unwrap(); diff --git a/veilid-core/src/veilid_api/mod.rs b/veilid-core/src/veilid_api/mod.rs index f43ce278..29df412d 100644 --- a/veilid-core/src/veilid_api/mod.rs +++ b/veilid-core/src/veilid_api/mod.rs @@ -37,10 +37,18 @@ pub enum VeilidAPIError { AlreadyInitialized, Timeout, Shutdown, - NodeNotFound(NodeId), - NoDialInfo(NodeId), - Internal(String), - Unimplemented(String), + NodeNotFound { + node_id: NodeId, + }, + NoDialInfo { + node_id: NodeId, + }, + Internal { + message: String, + }, + Unimplemented { + message: String, + }, ParseError { message: String, value: String, @@ -63,10 +71,18 @@ impl fmt::Display for VeilidAPIError { VeilidAPIError::AlreadyInitialized => write!(f, "VeilidAPIError::AlreadyInitialized"), VeilidAPIError::Timeout => write!(f, "VeilidAPIError::Timeout"), VeilidAPIError::Shutdown => write!(f, "VeilidAPIError::Shutdown"), - VeilidAPIError::NodeNotFound(ni) => write!(f, "VeilidAPIError::NodeNotFound({})", ni), - VeilidAPIError::NoDialInfo(ni) => write!(f, "VeilidAPIError::NoDialInfo({})", ni), - VeilidAPIError::Internal(e) => write!(f, "VeilidAPIError::Internal({})", e), - VeilidAPIError::Unimplemented(e) => write!(f, "VeilidAPIError::Unimplemented({})", e), + VeilidAPIError::NodeNotFound { node_id } => { + write!(f, "VeilidAPIError::NodeNotFound({})", node_id) + } + VeilidAPIError::NoDialInfo { node_id } => { + write!(f, "VeilidAPIError::NoDialInfo({})", node_id) + } + VeilidAPIError::Internal { message } => { + write!(f, "VeilidAPIError::Internal({})", message) + } + VeilidAPIError::Unimplemented { message } => { + write!(f, "VeilidAPIError::Unimplemented({})", message) + } VeilidAPIError::ParseError { message, value } => { write!(f, "VeilidAPIError::ParseError({}: {})", message, value) } @@ -95,10 +111,12 @@ impl fmt::Display for VeilidAPIError { fn convert_rpc_error(x: RPCError) -> VeilidAPIError { match x { RPCError::Timeout => VeilidAPIError::Timeout, - RPCError::Unimplemented(s) => VeilidAPIError::Unimplemented(s), - RPCError::Internal(s) => VeilidAPIError::Internal(s), - RPCError::Protocol(s) => VeilidAPIError::Internal(s), - RPCError::InvalidFormat => VeilidAPIError::Internal("Invalid packet format".to_owned()), + RPCError::Unimplemented(s) => VeilidAPIError::Unimplemented { message: s }, + RPCError::Internal(s) => VeilidAPIError::Internal { message: s }, + RPCError::Protocol(s) => VeilidAPIError::Internal { message: s }, + RPCError::InvalidFormat => VeilidAPIError::Internal { + message: "Invalid packet format".to_owned(), + }, } } @@ -147,7 +165,9 @@ pub enum VeilidUpdate { log_level: VeilidLogLevel, message: String, }, - Attachment(AttachmentState), + Attachment { + state: AttachmentState, + }, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -1209,9 +1229,9 @@ impl VeilidAPI { } => { // No point in waiting for a log } - VeilidUpdate::Attachment(cs) => { + VeilidUpdate::Attachment { state } => { self.attachment_manager()? - .wait_for_state(cs, timeout_ms) + .wait_for_state(state, timeout_ms) .await; } } @@ -1230,7 +1250,7 @@ impl VeilidAPI { let rpc = self.rpc_processor()?; let routing_table = rpc.routing_table(); let node_ref = match routing_table.lookup_node_ref(node_id.key) { - None => return Err(VeilidAPIError::NodeNotFound(node_id)), + None => return Err(VeilidAPIError::NodeNotFound { node_id }), Some(nr) => nr, }; let info_answer = rpc @@ -1250,7 +1270,7 @@ impl VeilidAPI { let rpc = self.rpc_processor()?; let routing_table = rpc.routing_table(); let node_ref = match routing_table.lookup_node_ref(node_id.key) { - None => return Err(VeilidAPIError::NodeNotFound(node_id)), + None => return Err(VeilidAPIError::NodeNotFound { node_id }), Some(nr) => nr, }; rpc.rpc_call_validate_dial_info(node_ref.clone(), dial_info, redirect, alternate_port) diff --git a/veilid-core/src/veilid_config.rs b/veilid-core/src/veilid_config.rs index f46ed0a4..5394dbb7 100644 --- a/veilid-core/src/veilid_config.rs +++ b/veilid-core/src/veilid_config.rs @@ -15,7 +15,7 @@ cfg_if! { } } -#[derive(Default, Clone)] +#[derive(Default, Clone, Serialize, Deserialize)] pub struct VeilidConfigHTTPS { pub enabled: bool, pub listen_address: String, @@ -23,7 +23,7 @@ pub struct VeilidConfigHTTPS { pub url: Option, // Fixed URL is not optional for TLS-based protocols and is dynamically validated } -#[derive(Default, Clone)] +#[derive(Default, Clone, Serialize, Deserialize)] pub struct VeilidConfigHTTP { pub enabled: bool, pub listen_address: String, @@ -31,13 +31,13 @@ pub struct VeilidConfigHTTP { pub url: Option, } -#[derive(Default, Clone)] +#[derive(Default, Clone, Serialize, Deserialize)] pub struct VeilidConfigApplication { pub https: VeilidConfigHTTPS, pub http: VeilidConfigHTTP, } -#[derive(Default, Clone)] +#[derive(Default, Clone, Serialize, Deserialize)] pub struct VeilidConfigUDP { pub enabled: bool, pub socket_pool_size: u32, @@ -45,7 +45,7 @@ pub struct VeilidConfigUDP { pub public_address: Option, } -#[derive(Default, Clone)] +#[derive(Default, Clone, Serialize, Deserialize)] pub struct VeilidConfigTCP { pub connect: bool, pub listen: bool, @@ -54,7 +54,7 @@ pub struct VeilidConfigTCP { pub public_address: Option, } -#[derive(Default, Clone)] +#[derive(Default, Clone, Serialize, Deserialize)] pub struct VeilidConfigWS { pub connect: bool, pub listen: bool, @@ -64,7 +64,7 @@ pub struct VeilidConfigWS { pub url: Option, } -#[derive(Default, Clone)] +#[derive(Default, Clone, Serialize, Deserialize)] pub struct VeilidConfigWSS { pub connect: bool, pub listen: bool, @@ -74,7 +74,7 @@ pub struct VeilidConfigWSS { pub url: Option, // Fixed URL is not optional for TLS-based protocols and is dynamically validated } -#[derive(Default, Clone)] +#[derive(Default, Clone, Serialize, Deserialize)] pub struct VeilidConfigProtocol { pub udp: VeilidConfigUDP, pub tcp: VeilidConfigTCP, @@ -82,14 +82,14 @@ pub struct VeilidConfigProtocol { pub wss: VeilidConfigWSS, } -#[derive(Default, Clone)] +#[derive(Default, Clone, Serialize, Deserialize)] pub struct VeilidConfigTLS { pub certificate_path: String, pub private_key_path: String, pub connection_initial_timeout_ms: u32, } -#[derive(Default, Clone)] +#[derive(Default, Clone, Serialize, Deserialize)] pub struct VeilidConfigDHT { pub resolve_node_timeout_ms: Option, pub resolve_node_count: u32, @@ -106,7 +106,7 @@ pub struct VeilidConfigDHT { pub validate_dial_info_receipt_time_ms: u32, } -#[derive(Default, Clone)] +#[derive(Default, Clone, Serialize, Deserialize)] pub struct VeilidConfigRPC { pub concurrency: u32, pub queue_size: u32, @@ -116,7 +116,7 @@ pub struct VeilidConfigRPC { pub max_route_hop_count: u8, } -#[derive(Default, Clone)] +#[derive(Default, Clone, Serialize, Deserialize)] pub struct VeilidConfigLeases { pub max_server_signal_leases: u32, pub max_server_relay_leases: u32, @@ -124,7 +124,7 @@ pub struct VeilidConfigLeases { pub max_client_relay_leases: u32, } -#[derive(Default, Clone)] +#[derive(Default, Clone, Serialize, Deserialize)] pub struct VeilidConfigNetwork { pub max_connections: u32, pub connection_initial_timeout_ms: u32, @@ -143,19 +143,19 @@ pub struct VeilidConfigNetwork { pub leases: VeilidConfigLeases, } -#[derive(Default, Clone)] +#[derive(Default, Clone, Serialize, Deserialize)] pub struct VeilidConfigTableStore { pub directory: String, pub delete: bool, } -#[derive(Default, Clone)] +#[derive(Default, Clone, Serialize, Deserialize)] pub struct VeilidConfigBlockStore { pub directory: String, pub delete: bool, } -#[derive(Default, Clone)] +#[derive(Default, Clone, Serialize, Deserialize)] pub struct VeilidConfigProtectedStore { pub allow_insecure_fallback: bool, pub always_use_insecure_storage: bool, @@ -163,7 +163,7 @@ pub struct VeilidConfigProtectedStore { pub delete: bool, } -#[derive(Default, Clone)] +#[derive(Default, Clone, Serialize, Deserialize)] pub struct VeilidConfigCapabilities { pub protocol_udp: bool, pub protocol_connect_tcp: bool, @@ -202,7 +202,7 @@ impl Default for VeilidConfigLogLevel { } } -#[derive(Default, Clone)] +#[derive(Default, Clone, Serialize, Deserialize)] pub struct VeilidConfigInner { pub program_name: String, pub namespace: String, @@ -235,6 +235,16 @@ impl VeilidConfig { } } + pub async fn init_from_json(&mut self, config: String) -> Result<(), String> { + let mut inner = self.inner.write(); + *inner = serde_json::from_str(&config).map_err(map_to_string)?; + + // Validate settings + self.validate().await?; + + Ok(()) + } + pub async fn init(&mut self, cb: ConfigCallback) -> Result<(), String> { macro_rules! get_config { ($key:expr) => { diff --git a/veilid-flutter/example/pubspec.lock b/veilid-flutter/example/pubspec.lock index 76cf02c8..420d3cc6 100644 --- a/veilid-flutter/example/pubspec.lock +++ b/veilid-flutter/example/pubspec.lock @@ -15,6 +15,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + change_case: + dependency: transitive + description: + name: change_case + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" characters: dependency: transitive description: @@ -50,13 +57,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.4" - equatable: - dependency: transitive - description: - name: equatable - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.3" fake_async: dependency: transitive description: @@ -64,6 +64,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + ffi: + dependency: transitive + description: + name: ffi + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.2" flutter: dependency: "direct main" description: flutter @@ -76,30 +83,16 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.4" - flutter_rust_bridge: - dependency: transitive - description: - name: flutter_rust_bridge - url: "https://pub.dartlang.org" - source: hosted - version: "1.14.0" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" flutter_web_plugins: - dependency: transitive + dependency: "direct main" description: flutter source: sdk version: "0.0.0" - freezed_annotation: - dependency: transitive - description: - name: freezed_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" js: dependency: transitive description: @@ -107,13 +100,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.6.3" - json_annotation: - dependency: transitive - description: - name: json_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "4.4.0" lints: dependency: transitive description: @@ -142,13 +128,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.7.0" - oxidized: - dependency: transitive - description: - name: oxidized - url: "https://pub.dartlang.org" - source: hosted - version: "5.1.0" path: dependency: transitive description: diff --git a/veilid-flutter/example/pubspec.yaml b/veilid-flutter/example/pubspec.yaml index f95ac307..ea8fb3ab 100644 --- a/veilid-flutter/example/pubspec.yaml +++ b/veilid-flutter/example/pubspec.yaml @@ -4,10 +4,11 @@ version: 1.0.0+1 # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev +publish_to: "none" # Remove this line if you wish to publish to pub.dev environment: sdk: ">=2.15.1 <3.0.0" + flutter: ">=2.5.0" # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -18,6 +19,8 @@ environment: dependencies: flutter: sdk: flutter + flutter_web_plugins: + sdk: flutter veilid: # When depending on this package from a real application you should use: @@ -47,7 +50,6 @@ dev_dependencies: # The following section is specific to Flutter. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. diff --git a/veilid-flutter/lib/bridge_generated.dart b/veilid-flutter/lib/bridge_generated.dart deleted file mode 100644 index a7fbdb99..00000000 --- a/veilid-flutter/lib/bridge_generated.dart +++ /dev/null @@ -1,955 +0,0 @@ -// AUTO GENERATED FILE, DO NOT EDIT. -// Generated by `flutter_rust_bridge`. - -// ignore_for_file: non_constant_identifier_names, unused_element, duplicate_ignore, directives_ordering, curly_braces_in_flow_control_structures, unnecessary_lambdas, slash_for_doc_comments, prefer_const_literals_to_create_immutables, implicit_dynamic_list_literal, duplicate_import, unused_import - -import 'dart:convert'; -import 'dart:typed_data'; -import 'package:freezed_annotation/freezed_annotation.dart'; - -import 'dart:convert'; -import 'dart:typed_data'; -import 'package:flutter_rust_bridge/flutter_rust_bridge.dart'; -import 'dart:ffi' as ffi; - -part 'bridge_generated.freezed.dart'; - -abstract class VeilidFlutter { - Stream startupVeilidCore( - {required VeilidConfig config, dynamic hint}); - - Future getVeilidState({dynamic hint}); - - Future changeApiLogLevel( - {required VeilidLogLevel logLevel, dynamic hint}); - - Future shutdownVeilidCore({dynamic hint}); - - Future veilidVersionString({dynamic hint}); - - Future veilidVersion({dynamic hint}); -} - -enum AttachmentState { - Detached, - Attaching, - AttachedWeak, - AttachedGood, - AttachedStrong, - FullyAttached, - OverAttached, - Detaching, -} - -class VeilidConfig { - final String programName; - final String veilidNamespace; - final VeilidLogLevel apiLogLevel; - final bool capabilitiesProtocolUdp; - final bool capabilitiesProtocolConnectTcp; - final bool capabilitiesProtocolAcceptTcp; - final bool capabilitiesProtocolConnectWs; - final bool capabilitiesProtocolAcceptWs; - final bool capabilitiesProtocolConnectWss; - final bool capabilitiesProtocolAcceptWss; - final bool protectedStoreAllowInsecureFallback; - final bool protectedStoreAlwaysUseInsecureStorage; - final String protectedStoreInsecureFallbackDirectory; - final bool protectedStoreDelete; - final String tableStoreDirectory; - final bool tableStoreDelete; - final String blockStoreDirectory; - final bool blockStoreDelete; - final int networkMaxConnections; - final int networkConnectionInitialTimeoutMs; - final String networkNodeId; - final String networkNodeIdSecret; - final List networkBootstrap; - final bool networkUpnp; - final bool networkNatpmp; - final bool networkEnableLocalPeerScope; - final int networkRestrictedNatRetries; - final int networkRpcConcurrency; - final int networkRpcQueueSize; - final int? networkRpcMaxTimestampBehindMs; - final int? networkRpcMaxTimestampAheadMs; - final int networkRpcTimeoutMs; - final int networkRpcMaxRouteHopCount; - final int? networkDhtResolveNodeTimeoutMs; - final int networkDhtResolveNodeCount; - final int networkDhtResolveNodeFanout; - final int networkDhtMaxFindNodeCount; - final int? networkDhtGetValueTimeoutMs; - final int networkDhtGetValueCount; - final int networkDhtGetValueFanout; - final int? networkDhtSetValueTimeoutMs; - final int networkDhtSetValueCount; - final int networkDhtSetValueFanout; - final int networkDhtMinPeerCount; - final int networkDhtMinPeerRefreshTimeMs; - final int networkDhtValidateDialInfoReceiptTimeMs; - final bool networkProtocolUdpEnabled; - final int networkProtocolUdpSocketPoolSize; - final String networkProtocolUdpListenAddress; - final String? networkProtocolUdpPublicAddress; - final bool networkProtocolTcpConnect; - final bool networkProtocolTcpListen; - final int networkProtocolTcpMaxConnections; - final String networkProtocolTcpListenAddress; - final String? networkProtocolTcpPublicAddress; - final bool networkProtocolWsConnect; - final bool networkProtocolWsListen; - final int networkProtocolWsMaxConnections; - final String networkProtocolWsListenAddress; - final String networkProtocolWsPath; - final String? networkProtocolWsUrl; - final bool networkProtocolWssConnect; - final int networkProtocolWssMaxConnections; - final int networkLeasesMaxServerSignalLeases; - final int networkLeasesMaxServerRelayLeases; - final int networkLeasesMaxClientSignalLeases; - final int networkLeasesMaxClientRelayLeases; - - VeilidConfig({ - required this.programName, - required this.veilidNamespace, - required this.apiLogLevel, - required this.capabilitiesProtocolUdp, - required this.capabilitiesProtocolConnectTcp, - required this.capabilitiesProtocolAcceptTcp, - required this.capabilitiesProtocolConnectWs, - required this.capabilitiesProtocolAcceptWs, - required this.capabilitiesProtocolConnectWss, - required this.capabilitiesProtocolAcceptWss, - required this.protectedStoreAllowInsecureFallback, - required this.protectedStoreAlwaysUseInsecureStorage, - required this.protectedStoreInsecureFallbackDirectory, - required this.protectedStoreDelete, - required this.tableStoreDirectory, - required this.tableStoreDelete, - required this.blockStoreDirectory, - required this.blockStoreDelete, - required this.networkMaxConnections, - required this.networkConnectionInitialTimeoutMs, - required this.networkNodeId, - required this.networkNodeIdSecret, - required this.networkBootstrap, - required this.networkUpnp, - required this.networkNatpmp, - required this.networkEnableLocalPeerScope, - required this.networkRestrictedNatRetries, - required this.networkRpcConcurrency, - required this.networkRpcQueueSize, - this.networkRpcMaxTimestampBehindMs, - this.networkRpcMaxTimestampAheadMs, - required this.networkRpcTimeoutMs, - required this.networkRpcMaxRouteHopCount, - this.networkDhtResolveNodeTimeoutMs, - required this.networkDhtResolveNodeCount, - required this.networkDhtResolveNodeFanout, - required this.networkDhtMaxFindNodeCount, - this.networkDhtGetValueTimeoutMs, - required this.networkDhtGetValueCount, - required this.networkDhtGetValueFanout, - this.networkDhtSetValueTimeoutMs, - required this.networkDhtSetValueCount, - required this.networkDhtSetValueFanout, - required this.networkDhtMinPeerCount, - required this.networkDhtMinPeerRefreshTimeMs, - required this.networkDhtValidateDialInfoReceiptTimeMs, - required this.networkProtocolUdpEnabled, - required this.networkProtocolUdpSocketPoolSize, - required this.networkProtocolUdpListenAddress, - this.networkProtocolUdpPublicAddress, - required this.networkProtocolTcpConnect, - required this.networkProtocolTcpListen, - required this.networkProtocolTcpMaxConnections, - required this.networkProtocolTcpListenAddress, - this.networkProtocolTcpPublicAddress, - required this.networkProtocolWsConnect, - required this.networkProtocolWsListen, - required this.networkProtocolWsMaxConnections, - required this.networkProtocolWsListenAddress, - required this.networkProtocolWsPath, - this.networkProtocolWsUrl, - required this.networkProtocolWssConnect, - required this.networkProtocolWssMaxConnections, - required this.networkLeasesMaxServerSignalLeases, - required this.networkLeasesMaxServerRelayLeases, - required this.networkLeasesMaxClientSignalLeases, - required this.networkLeasesMaxClientRelayLeases, - }); -} - -enum VeilidLogLevel { - Error, - Warn, - Info, - Debug, - Trace, -} - -class VeilidState { - final AttachmentState attachment; - - VeilidState({ - required this.attachment, - }); -} - -@freezed -class VeilidUpdate with _$VeilidUpdate { - const factory VeilidUpdate.log({ - required VeilidLogLevel logLevel, - required String message, - }) = Log; - const factory VeilidUpdate.attachment( - AttachmentState field0, - ) = Attachment; -} - -class VeilidVersion { - final int major; - final int minor; - final int patch; - - VeilidVersion({ - required this.major, - required this.minor, - required this.patch, - }); -} - -class VeilidFlutterImpl extends FlutterRustBridgeBase - implements VeilidFlutter { - factory VeilidFlutterImpl(ffi.DynamicLibrary dylib) => - VeilidFlutterImpl.raw(VeilidFlutterWire(dylib)); - - VeilidFlutterImpl.raw(VeilidFlutterWire inner) : super(inner); - - Stream startupVeilidCore( - {required VeilidConfig config, dynamic hint}) => - executeStream(FlutterRustBridgeTask( - callFfi: (port_) => inner.wire_startup_veilid_core( - port_, _api2wire_box_autoadd_veilid_config(config)), - parseSuccessData: _wire2api_veilid_update, - constMeta: const FlutterRustBridgeTaskConstMeta( - debugName: "startup_veilid_core", - argNames: ["config"], - ), - argValues: [config], - hint: hint, - )); - - Future getVeilidState({dynamic hint}) => - executeNormal(FlutterRustBridgeTask( - callFfi: (port_) => inner.wire_get_veilid_state(port_), - parseSuccessData: _wire2api_veilid_state, - constMeta: const FlutterRustBridgeTaskConstMeta( - debugName: "get_veilid_state", - argNames: [], - ), - argValues: [], - hint: hint, - )); - - Future changeApiLogLevel( - {required VeilidLogLevel logLevel, dynamic hint}) => - executeNormal(FlutterRustBridgeTask( - callFfi: (port_) => inner.wire_change_api_log_level( - port_, _api2wire_veilid_log_level(logLevel)), - parseSuccessData: _wire2api_unit, - constMeta: const FlutterRustBridgeTaskConstMeta( - debugName: "change_api_log_level", - argNames: ["logLevel"], - ), - argValues: [logLevel], - hint: hint, - )); - - Future shutdownVeilidCore({dynamic hint}) => - executeNormal(FlutterRustBridgeTask( - callFfi: (port_) => inner.wire_shutdown_veilid_core(port_), - parseSuccessData: _wire2api_unit, - constMeta: const FlutterRustBridgeTaskConstMeta( - debugName: "shutdown_veilid_core", - argNames: [], - ), - argValues: [], - hint: hint, - )); - - Future veilidVersionString({dynamic hint}) => - executeNormal(FlutterRustBridgeTask( - callFfi: (port_) => inner.wire_veilid_version_string(port_), - parseSuccessData: _wire2api_String, - constMeta: const FlutterRustBridgeTaskConstMeta( - debugName: "veilid_version_string", - argNames: [], - ), - argValues: [], - hint: hint, - )); - - Future veilidVersion({dynamic hint}) => - executeNormal(FlutterRustBridgeTask( - callFfi: (port_) => inner.wire_veilid_version(port_), - parseSuccessData: _wire2api_veilid_version, - constMeta: const FlutterRustBridgeTaskConstMeta( - debugName: "veilid_version", - argNames: [], - ), - argValues: [], - hint: hint, - )); - - // Section: api2wire - ffi.Pointer _api2wire_String(String raw) { - return _api2wire_uint_8_list(utf8.encoder.convert(raw)); - } - - ffi.Pointer _api2wire_StringList(List raw) { - final ans = inner.new_StringList(raw.length); - for (var i = 0; i < raw.length; i++) { - ans.ref.ptr[i] = _api2wire_String(raw[i]); - } - return ans; - } - - int _api2wire_bool(bool raw) { - return raw ? 1 : 0; - } - - ffi.Pointer _api2wire_box_autoadd_u32(int raw) { - return inner.new_box_autoadd_u32(raw); - } - - ffi.Pointer _api2wire_box_autoadd_veilid_config( - VeilidConfig raw) { - final ptr = inner.new_box_autoadd_veilid_config(); - _api_fill_to_wire_veilid_config(raw, ptr.ref); - return ptr; - } - - ffi.Pointer _api2wire_opt_String(String? raw) { - return raw == null ? ffi.nullptr : _api2wire_String(raw); - } - - ffi.Pointer _api2wire_opt_box_autoadd_u32(int? raw) { - return raw == null ? ffi.nullptr : _api2wire_box_autoadd_u32(raw); - } - - int _api2wire_u32(int raw) { - return raw; - } - - int _api2wire_u8(int raw) { - return raw; - } - - ffi.Pointer _api2wire_uint_8_list(Uint8List raw) { - final ans = inner.new_uint_8_list(raw.length); - ans.ref.ptr.asTypedList(raw.length).setAll(0, raw); - return ans; - } - - int _api2wire_veilid_log_level(VeilidLogLevel raw) { - return raw.index; - } - - // Section: api_fill_to_wire - - void _api_fill_to_wire_box_autoadd_veilid_config( - VeilidConfig apiObj, ffi.Pointer wireObj) { - _api_fill_to_wire_veilid_config(apiObj, wireObj.ref); - } - - void _api_fill_to_wire_veilid_config( - VeilidConfig apiObj, wire_VeilidConfig wireObj) { - wireObj.program_name = _api2wire_String(apiObj.programName); - wireObj.veilid_namespace = _api2wire_String(apiObj.veilidNamespace); - wireObj.api_log_level = _api2wire_veilid_log_level(apiObj.apiLogLevel); - wireObj.capabilities__protocol_udp = - _api2wire_bool(apiObj.capabilitiesProtocolUdp); - wireObj.capabilities__protocol_connect_tcp = - _api2wire_bool(apiObj.capabilitiesProtocolConnectTcp); - wireObj.capabilities__protocol_accept_tcp = - _api2wire_bool(apiObj.capabilitiesProtocolAcceptTcp); - wireObj.capabilities__protocol_connect_ws = - _api2wire_bool(apiObj.capabilitiesProtocolConnectWs); - wireObj.capabilities__protocol_accept_ws = - _api2wire_bool(apiObj.capabilitiesProtocolAcceptWs); - wireObj.capabilities__protocol_connect_wss = - _api2wire_bool(apiObj.capabilitiesProtocolConnectWss); - wireObj.capabilities__protocol_accept_wss = - _api2wire_bool(apiObj.capabilitiesProtocolAcceptWss); - wireObj.protected_store__allow_insecure_fallback = - _api2wire_bool(apiObj.protectedStoreAllowInsecureFallback); - wireObj.protected_store__always_use_insecure_storage = - _api2wire_bool(apiObj.protectedStoreAlwaysUseInsecureStorage); - wireObj.protected_store__insecure_fallback_directory = - _api2wire_String(apiObj.protectedStoreInsecureFallbackDirectory); - wireObj.protected_store__delete = - _api2wire_bool(apiObj.protectedStoreDelete); - wireObj.table_store__directory = - _api2wire_String(apiObj.tableStoreDirectory); - wireObj.table_store__delete = _api2wire_bool(apiObj.tableStoreDelete); - wireObj.block_store__directory = - _api2wire_String(apiObj.blockStoreDirectory); - wireObj.block_store__delete = _api2wire_bool(apiObj.blockStoreDelete); - wireObj.network__max_connections = - _api2wire_u32(apiObj.networkMaxConnections); - wireObj.network__connection_initial_timeout_ms = - _api2wire_u32(apiObj.networkConnectionInitialTimeoutMs); - wireObj.network__node_id = _api2wire_String(apiObj.networkNodeId); - wireObj.network__node_id_secret = - _api2wire_String(apiObj.networkNodeIdSecret); - wireObj.network__bootstrap = _api2wire_StringList(apiObj.networkBootstrap); - wireObj.network__upnp = _api2wire_bool(apiObj.networkUpnp); - wireObj.network__natpmp = _api2wire_bool(apiObj.networkNatpmp); - wireObj.network__enable_local_peer_scope = - _api2wire_bool(apiObj.networkEnableLocalPeerScope); - wireObj.network__restricted_nat_retries = - _api2wire_u32(apiObj.networkRestrictedNatRetries); - wireObj.network__rpc__concurrency = - _api2wire_u32(apiObj.networkRpcConcurrency); - wireObj.network__rpc__queue_size = - _api2wire_u32(apiObj.networkRpcQueueSize); - wireObj.network__rpc__max_timestamp_behind_ms = - _api2wire_opt_box_autoadd_u32(apiObj.networkRpcMaxTimestampBehindMs); - wireObj.network__rpc__max_timestamp_ahead_ms = - _api2wire_opt_box_autoadd_u32(apiObj.networkRpcMaxTimestampAheadMs); - wireObj.network__rpc__timeout_ms = - _api2wire_u32(apiObj.networkRpcTimeoutMs); - wireObj.network__rpc__max_route_hop_count = - _api2wire_u8(apiObj.networkRpcMaxRouteHopCount); - wireObj.network__dht__resolve_node_timeout_ms = - _api2wire_opt_box_autoadd_u32(apiObj.networkDhtResolveNodeTimeoutMs); - wireObj.network__dht__resolve_node_count = - _api2wire_u32(apiObj.networkDhtResolveNodeCount); - wireObj.network__dht__resolve_node_fanout = - _api2wire_u32(apiObj.networkDhtResolveNodeFanout); - wireObj.network__dht__max_find_node_count = - _api2wire_u32(apiObj.networkDhtMaxFindNodeCount); - wireObj.network__dht__get_value_timeout_ms = - _api2wire_opt_box_autoadd_u32(apiObj.networkDhtGetValueTimeoutMs); - wireObj.network__dht__get_value_count = - _api2wire_u32(apiObj.networkDhtGetValueCount); - wireObj.network__dht__get_value_fanout = - _api2wire_u32(apiObj.networkDhtGetValueFanout); - wireObj.network__dht__set_value_timeout_ms = - _api2wire_opt_box_autoadd_u32(apiObj.networkDhtSetValueTimeoutMs); - wireObj.network__dht__set_value_count = - _api2wire_u32(apiObj.networkDhtSetValueCount); - wireObj.network__dht__set_value_fanout = - _api2wire_u32(apiObj.networkDhtSetValueFanout); - wireObj.network__dht__min_peer_count = - _api2wire_u32(apiObj.networkDhtMinPeerCount); - wireObj.network__dht__min_peer_refresh_time_ms = - _api2wire_u32(apiObj.networkDhtMinPeerRefreshTimeMs); - wireObj.network__dht__validate_dial_info_receipt_time_ms = - _api2wire_u32(apiObj.networkDhtValidateDialInfoReceiptTimeMs); - wireObj.network__protocol__udp__enabled = - _api2wire_bool(apiObj.networkProtocolUdpEnabled); - wireObj.network__protocol__udp__socket_pool_size = - _api2wire_u32(apiObj.networkProtocolUdpSocketPoolSize); - wireObj.network__protocol__udp__listen_address = - _api2wire_String(apiObj.networkProtocolUdpListenAddress); - wireObj.network__protocol__udp__public_address = - _api2wire_opt_String(apiObj.networkProtocolUdpPublicAddress); - wireObj.network__protocol__tcp__connect = - _api2wire_bool(apiObj.networkProtocolTcpConnect); - wireObj.network__protocol__tcp__listen = - _api2wire_bool(apiObj.networkProtocolTcpListen); - wireObj.network__protocol__tcp__max_connections = - _api2wire_u32(apiObj.networkProtocolTcpMaxConnections); - wireObj.network__protocol__tcp__listen_address = - _api2wire_String(apiObj.networkProtocolTcpListenAddress); - wireObj.network__protocol__tcp__public_address = - _api2wire_opt_String(apiObj.networkProtocolTcpPublicAddress); - wireObj.network__protocol__ws__connect = - _api2wire_bool(apiObj.networkProtocolWsConnect); - wireObj.network__protocol__ws__listen = - _api2wire_bool(apiObj.networkProtocolWsListen); - wireObj.network__protocol__ws__max_connections = - _api2wire_u32(apiObj.networkProtocolWsMaxConnections); - wireObj.network__protocol__ws__listen_address = - _api2wire_String(apiObj.networkProtocolWsListenAddress); - wireObj.network__protocol__ws__path = - _api2wire_String(apiObj.networkProtocolWsPath); - wireObj.network__protocol__ws__url = - _api2wire_opt_String(apiObj.networkProtocolWsUrl); - wireObj.network__protocol__wss__connect = - _api2wire_bool(apiObj.networkProtocolWssConnect); - wireObj.network__protocol__wss__max_connections = - _api2wire_u32(apiObj.networkProtocolWssMaxConnections); - wireObj.network__leases__max_server_signal_leases = - _api2wire_u32(apiObj.networkLeasesMaxServerSignalLeases); - wireObj.network__leases__max_server_relay_leases = - _api2wire_u32(apiObj.networkLeasesMaxServerRelayLeases); - wireObj.network__leases__max_client_signal_leases = - _api2wire_u32(apiObj.networkLeasesMaxClientSignalLeases); - wireObj.network__leases__max_client_relay_leases = - _api2wire_u32(apiObj.networkLeasesMaxClientRelayLeases); - } -} - -// Section: wire2api -String _wire2api_String(dynamic raw) { - return raw as String; -} - -AttachmentState _wire2api_attachment_state(dynamic raw) { - return AttachmentState.values[raw]; -} - -int _wire2api_u32(dynamic raw) { - return raw as int; -} - -int _wire2api_u8(dynamic raw) { - return raw as int; -} - -Uint8List _wire2api_uint_8_list(dynamic raw) { - return raw as Uint8List; -} - -void _wire2api_unit(dynamic raw) { - return; -} - -VeilidLogLevel _wire2api_veilid_log_level(dynamic raw) { - return VeilidLogLevel.values[raw]; -} - -VeilidState _wire2api_veilid_state(dynamic raw) { - final arr = raw as List; - if (arr.length != 1) - throw Exception('unexpected arr length: expect 1 but see ${arr.length}'); - return VeilidState( - attachment: _wire2api_attachment_state(arr[0]), - ); -} - -VeilidUpdate _wire2api_veilid_update(dynamic raw) { - switch (raw[0]) { - case 0: - return Log( - logLevel: _wire2api_veilid_log_level(raw[1]), - message: _wire2api_String(raw[2]), - ); - case 1: - return Attachment( - _wire2api_attachment_state(raw[1]), - ); - default: - throw Exception("unreachable"); - } -} - -VeilidVersion _wire2api_veilid_version(dynamic raw) { - final arr = raw as List; - if (arr.length != 3) - throw Exception('unexpected arr length: expect 3 but see ${arr.length}'); - return VeilidVersion( - major: _wire2api_u32(arr[0]), - minor: _wire2api_u32(arr[1]), - patch: _wire2api_u32(arr[2]), - ); -} - -// ignore_for_file: camel_case_types, non_constant_identifier_names, avoid_positional_boolean_parameters, annotate_overrides, constant_identifier_names - -// AUTO GENERATED FILE, DO NOT EDIT. -// -// Generated by `package:ffigen`. - -/// generated by flutter_rust_bridge -class VeilidFlutterWire implements FlutterRustBridgeWireBase { - /// Holds the symbol lookup function. - final ffi.Pointer Function(String symbolName) - _lookup; - - /// The symbols are looked up in [dynamicLibrary]. - VeilidFlutterWire(ffi.DynamicLibrary dynamicLibrary) - : _lookup = dynamicLibrary.lookup; - - /// The symbols are looked up with [lookup]. - VeilidFlutterWire.fromLookup( - ffi.Pointer Function(String symbolName) - lookup) - : _lookup = lookup; - - void wire_startup_veilid_core( - int port_, - ffi.Pointer config, - ) { - return _wire_startup_veilid_core( - port_, - config, - ); - } - - late final _wire_startup_veilid_corePtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Int64, - ffi.Pointer)>>('wire_startup_veilid_core'); - late final _wire_startup_veilid_core = _wire_startup_veilid_corePtr - .asFunction)>(); - - void wire_get_veilid_state( - int port_, - ) { - return _wire_get_veilid_state( - port_, - ); - } - - late final _wire_get_veilid_statePtr = - _lookup>( - 'wire_get_veilid_state'); - late final _wire_get_veilid_state = - _wire_get_veilid_statePtr.asFunction(); - - void wire_change_api_log_level( - int port_, - int log_level, - ) { - return _wire_change_api_log_level( - port_, - log_level, - ); - } - - late final _wire_change_api_log_levelPtr = - _lookup>( - 'wire_change_api_log_level'); - late final _wire_change_api_log_level = - _wire_change_api_log_levelPtr.asFunction(); - - void wire_shutdown_veilid_core( - int port_, - ) { - return _wire_shutdown_veilid_core( - port_, - ); - } - - late final _wire_shutdown_veilid_corePtr = - _lookup>( - 'wire_shutdown_veilid_core'); - late final _wire_shutdown_veilid_core = - _wire_shutdown_veilid_corePtr.asFunction(); - - void wire_veilid_version_string( - int port_, - ) { - return _wire_veilid_version_string( - port_, - ); - } - - late final _wire_veilid_version_stringPtr = - _lookup>( - 'wire_veilid_version_string'); - late final _wire_veilid_version_string = - _wire_veilid_version_stringPtr.asFunction(); - - void wire_veilid_version( - int port_, - ) { - return _wire_veilid_version( - port_, - ); - } - - late final _wire_veilid_versionPtr = - _lookup>( - 'wire_veilid_version'); - late final _wire_veilid_version = - _wire_veilid_versionPtr.asFunction(); - - ffi.Pointer new_StringList( - int len, - ) { - return _new_StringList( - len, - ); - } - - late final _new_StringListPtr = _lookup< - ffi.NativeFunction Function(ffi.Int32)>>( - 'new_StringList'); - late final _new_StringList = _new_StringListPtr - .asFunction Function(int)>(); - - ffi.Pointer new_box_autoadd_u32( - int value, - ) { - return _new_box_autoadd_u32( - value, - ); - } - - late final _new_box_autoadd_u32Ptr = - _lookup Function(ffi.Uint32)>>( - 'new_box_autoadd_u32'); - late final _new_box_autoadd_u32 = _new_box_autoadd_u32Ptr - .asFunction Function(int)>(); - - ffi.Pointer new_box_autoadd_veilid_config() { - return _new_box_autoadd_veilid_config(); - } - - late final _new_box_autoadd_veilid_configPtr = - _lookup Function()>>( - 'new_box_autoadd_veilid_config'); - late final _new_box_autoadd_veilid_config = _new_box_autoadd_veilid_configPtr - .asFunction Function()>(); - - ffi.Pointer new_uint_8_list( - int len, - ) { - return _new_uint_8_list( - len, - ); - } - - late final _new_uint_8_listPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Int32)>>('new_uint_8_list'); - late final _new_uint_8_list = _new_uint_8_listPtr - .asFunction Function(int)>(); - - void free_WireSyncReturnStruct( - WireSyncReturnStruct val, - ) { - return _free_WireSyncReturnStruct( - val, - ); - } - - late final _free_WireSyncReturnStructPtr = - _lookup>( - 'free_WireSyncReturnStruct'); - late final _free_WireSyncReturnStruct = _free_WireSyncReturnStructPtr - .asFunction(); - - void store_dart_post_cobject( - DartPostCObjectFnType ptr, - ) { - return _store_dart_post_cobject( - ptr, - ); - } - - late final _store_dart_post_cobjectPtr = - _lookup>( - 'store_dart_post_cobject'); - late final _store_dart_post_cobject = _store_dart_post_cobjectPtr - .asFunction(); -} - -class wire_uint_8_list extends ffi.Struct { - external ffi.Pointer ptr; - - @ffi.Int32() - external int len; -} - -class wire_StringList extends ffi.Struct { - external ffi.Pointer> ptr; - - @ffi.Int32() - external int len; -} - -class wire_VeilidConfig extends ffi.Struct { - external ffi.Pointer program_name; - - external ffi.Pointer veilid_namespace; - - @ffi.Int32() - external int api_log_level; - - @ffi.Uint8() - external int capabilities__protocol_udp; - - @ffi.Uint8() - external int capabilities__protocol_connect_tcp; - - @ffi.Uint8() - external int capabilities__protocol_accept_tcp; - - @ffi.Uint8() - external int capabilities__protocol_connect_ws; - - @ffi.Uint8() - external int capabilities__protocol_accept_ws; - - @ffi.Uint8() - external int capabilities__protocol_connect_wss; - - @ffi.Uint8() - external int capabilities__protocol_accept_wss; - - @ffi.Uint8() - external int protected_store__allow_insecure_fallback; - - @ffi.Uint8() - external int protected_store__always_use_insecure_storage; - - external ffi.Pointer - protected_store__insecure_fallback_directory; - - @ffi.Uint8() - external int protected_store__delete; - - external ffi.Pointer table_store__directory; - - @ffi.Uint8() - external int table_store__delete; - - external ffi.Pointer block_store__directory; - - @ffi.Uint8() - external int block_store__delete; - - @ffi.Uint32() - external int network__max_connections; - - @ffi.Uint32() - external int network__connection_initial_timeout_ms; - - external ffi.Pointer network__node_id; - - external ffi.Pointer network__node_id_secret; - - external ffi.Pointer network__bootstrap; - - @ffi.Uint8() - external int network__upnp; - - @ffi.Uint8() - external int network__natpmp; - - @ffi.Uint8() - external int network__enable_local_peer_scope; - - @ffi.Uint32() - external int network__restricted_nat_retries; - - @ffi.Uint32() - external int network__rpc__concurrency; - - @ffi.Uint32() - external int network__rpc__queue_size; - - external ffi.Pointer network__rpc__max_timestamp_behind_ms; - - external ffi.Pointer network__rpc__max_timestamp_ahead_ms; - - @ffi.Uint32() - external int network__rpc__timeout_ms; - - @ffi.Uint8() - external int network__rpc__max_route_hop_count; - - external ffi.Pointer network__dht__resolve_node_timeout_ms; - - @ffi.Uint32() - external int network__dht__resolve_node_count; - - @ffi.Uint32() - external int network__dht__resolve_node_fanout; - - @ffi.Uint32() - external int network__dht__max_find_node_count; - - external ffi.Pointer network__dht__get_value_timeout_ms; - - @ffi.Uint32() - external int network__dht__get_value_count; - - @ffi.Uint32() - external int network__dht__get_value_fanout; - - external ffi.Pointer network__dht__set_value_timeout_ms; - - @ffi.Uint32() - external int network__dht__set_value_count; - - @ffi.Uint32() - external int network__dht__set_value_fanout; - - @ffi.Uint32() - external int network__dht__min_peer_count; - - @ffi.Uint32() - external int network__dht__min_peer_refresh_time_ms; - - @ffi.Uint32() - external int network__dht__validate_dial_info_receipt_time_ms; - - @ffi.Uint8() - external int network__protocol__udp__enabled; - - @ffi.Uint32() - external int network__protocol__udp__socket_pool_size; - - external ffi.Pointer network__protocol__udp__listen_address; - - external ffi.Pointer network__protocol__udp__public_address; - - @ffi.Uint8() - external int network__protocol__tcp__connect; - - @ffi.Uint8() - external int network__protocol__tcp__listen; - - @ffi.Uint32() - external int network__protocol__tcp__max_connections; - - external ffi.Pointer network__protocol__tcp__listen_address; - - external ffi.Pointer network__protocol__tcp__public_address; - - @ffi.Uint8() - external int network__protocol__ws__connect; - - @ffi.Uint8() - external int network__protocol__ws__listen; - - @ffi.Uint32() - external int network__protocol__ws__max_connections; - - external ffi.Pointer network__protocol__ws__listen_address; - - external ffi.Pointer network__protocol__ws__path; - - external ffi.Pointer network__protocol__ws__url; - - @ffi.Uint8() - external int network__protocol__wss__connect; - - @ffi.Uint32() - external int network__protocol__wss__max_connections; - - @ffi.Uint32() - external int network__leases__max_server_signal_leases; - - @ffi.Uint32() - external int network__leases__max_server_relay_leases; - - @ffi.Uint32() - external int network__leases__max_client_signal_leases; - - @ffi.Uint32() - external int network__leases__max_client_relay_leases; -} - -typedef DartPostCObjectFnType = ffi.Pointer< - ffi.NativeFunction)>>; -typedef DartPort = ffi.Int64; diff --git a/veilid-flutter/lib/veilid.dart b/veilid-flutter/lib/veilid.dart index 9afcebe1..448e18a9 100644 --- a/veilid-flutter/lib/veilid.dart +++ b/veilid-flutter/lib/veilid.dart @@ -1,69 +1,336 @@ import 'dart:async'; -import 'dart:typed_data'; +import 'dart:convert'; -import 'package:flutter/services.dart'; -import 'package:flutter/material.dart'; -import 'package:oxidized/oxidized.dart'; +import 'package:change_case/change_case.dart'; import 'veilid_stub.dart' - if (dart.library.io) 'veilid_ffi.dart' - if (dart.library.js) 'veilid_js.dart'; + if (dart.library.io) 'veilid_ffi.dart' + if (dart.library.js) 'veilid_js.dart'; ////////////////////////////////////////////////////////// -enum AttachmentState { - Detached, - Attaching, - AttachedWeak, - AttachedGood, - AttachedStrong, - FullyAttached, - OverAttached, - Detaching, +////////////////////////////////////// +/// JSON Encode Helper +Object? veilidApiToEncodable(Object? value) { + if (value == null) { + return value; + } + switch (value.runtimeType) { + case AttachmentState: + return (value as AttachmentState).json; + case VeilidLogLevel: + return (value as VeilidLogLevel).json; + } + throw UnsupportedError('Cannot convert to JSON: $value'); } +////////////////////////////////////// +/// AttachmentState + +enum AttachmentState { + detached, + attaching, + attachedWeak, + attachedGood, + attachedStrong, + fullyAttached, + overAttached, + detaching, +} + +extension AttachmentStateExt on AttachmentState { + String get json { + return name.toPascalCase(); + } +} + +AttachmentState attachmentStateFromJson(String j) { + return AttachmentState.values.byName(j.toCamelCase()); +} + +////////////////////////////////////// +/// VeilidLogLevel + enum VeilidLogLevel { - Error, - Warn, - Info, - Debug, - Trace, + error, + warn, + info, + debug, + trace, } -// VeilidVersion +extension VeilidLogLevelExt on VeilidLogLevel { + String get json { + return name.toPascalCase(); + } +} -class VeilidVersion { - final int major; - final int minor; - final int patch; +VeilidLogLevel veilidLogLevelFromJson(String j) { + return VeilidLogLevel.values.byName(j.toCamelCase()); +} - VeilidVersion({ - required this.major, - required this.minor, - required this.patch, +////////////////////////////////////// +/// VeilidConfig + +class VeilidConfig { + String programName; + String veilidNamespace; + VeilidLogLevel apiLogLevel; + bool capabilitiesProtocolUdp; + bool capabilitiesProtocolConnectTcp; + bool capabilitiesProtocolAcceptTcp; + bool capabilitiesProtocolConnectWs; + bool capabilitiesProtocolAcceptWs; + bool capabilitiesProtocolConnectWss; + bool capabilitiesProtocolAcceptWss; + bool protectedStoreAllowInsecureFallback; + bool protectedStoreAlwaysUseInsecureStorage; + String protectedStoreInsecureFallbackDirectory; + bool protectedStoreDelete; + String tableStoreDirectory; + bool tableStoreDelete; + String blockStoreDirectory; + bool blockStoreDelete; + int networkMaxConnections; + int networkConnectionInitialTimeoutMs; + String networkNodeId; + String networkNodeIdSecret; + List networkBootstrap; + bool networkUpnp; + bool networkNatpmp; + bool networkEnableLocalPeerScope; + int networkRestrictedNatRetries; + int networkRpcConcurrency; + int networkRpcQueueSize; + int? networkRpcMaxTimestampBehindMs; + int? networkRpcMaxTimestampAheadMs; + int networkRpcTimeoutMs; + int networkRpcMaxRouteHopCount; + int? networkDhtResolveNodeTimeoutMs; + int networkDhtResolveNodeCount; + int networkDhtResolveNodeFanout; + int networkDhtMaxFindNodeCount; + int? networkDhtGetValueTimeoutMs; + int networkDhtGetValueCount; + int networkDhtGetValueFanout; + int? networkDhtSetValueTimeoutMs; + int networkDhtSetValueCount; + int networkDhtSetValueFanout; + int networkDhtMinPeerCount; + int networkDhtMinPeerRefreshTimeMs; + int networkDhtValidateDialInfoReceiptTimeMs; + bool networkProtocolUdpEnabled; + int networkProtocolUdpSocketPoolSize; + String networkProtocolUdpListenAddress; + String? networkProtocolUdpPublicAddress; + bool networkProtocolTcpConnect; + bool networkProtocolTcpListen; + int networkProtocolTcpMaxConnections; + String networkProtocolTcpListenAddress; + String? networkProtocolTcpPublicAddress; + bool networkProtocolWsConnect; + bool networkProtocolWsListen; + int networkProtocolWsMaxConnections; + String networkProtocolWsListenAddress; + String networkProtocolWsPath; + String? networkProtocolWsUrl; + bool networkProtocolWssConnect; + int networkProtocolWssMaxConnections; + int networkLeasesMaxServerSignalLeases; + int networkLeasesMaxServerRelayLeases; + int networkLeasesMaxClientSignalLeases; + int networkLeasesMaxClientRelayLeases; + + VeilidConfig({ + required this.programName, + required this.veilidNamespace, + required this.apiLogLevel, + required this.capabilitiesProtocolUdp, + required this.capabilitiesProtocolConnectTcp, + required this.capabilitiesProtocolAcceptTcp, + required this.capabilitiesProtocolConnectWs, + required this.capabilitiesProtocolAcceptWs, + required this.capabilitiesProtocolConnectWss, + required this.capabilitiesProtocolAcceptWss, + required this.protectedStoreAllowInsecureFallback, + required this.protectedStoreAlwaysUseInsecureStorage, + required this.protectedStoreInsecureFallbackDirectory, + required this.protectedStoreDelete, + required this.tableStoreDirectory, + required this.tableStoreDelete, + required this.blockStoreDirectory, + required this.blockStoreDelete, + required this.networkMaxConnections, + required this.networkConnectionInitialTimeoutMs, + required this.networkNodeId, + required this.networkNodeIdSecret, + required this.networkBootstrap, + required this.networkUpnp, + required this.networkNatpmp, + required this.networkEnableLocalPeerScope, + required this.networkRestrictedNatRetries, + required this.networkRpcConcurrency, + required this.networkRpcQueueSize, + this.networkRpcMaxTimestampBehindMs, + this.networkRpcMaxTimestampAheadMs, + required this.networkRpcTimeoutMs, + required this.networkRpcMaxRouteHopCount, + this.networkDhtResolveNodeTimeoutMs, + required this.networkDhtResolveNodeCount, + required this.networkDhtResolveNodeFanout, + required this.networkDhtMaxFindNodeCount, + this.networkDhtGetValueTimeoutMs, + required this.networkDhtGetValueCount, + required this.networkDhtGetValueFanout, + this.networkDhtSetValueTimeoutMs, + required this.networkDhtSetValueCount, + required this.networkDhtSetValueFanout, + required this.networkDhtMinPeerCount, + required this.networkDhtMinPeerRefreshTimeMs, + required this.networkDhtValidateDialInfoReceiptTimeMs, + required this.networkProtocolUdpEnabled, + required this.networkProtocolUdpSocketPoolSize, + required this.networkProtocolUdpListenAddress, + this.networkProtocolUdpPublicAddress, + required this.networkProtocolTcpConnect, + required this.networkProtocolTcpListen, + required this.networkProtocolTcpMaxConnections, + required this.networkProtocolTcpListenAddress, + this.networkProtocolTcpPublicAddress, + required this.networkProtocolWsConnect, + required this.networkProtocolWsListen, + required this.networkProtocolWsMaxConnections, + required this.networkProtocolWsListenAddress, + required this.networkProtocolWsPath, + this.networkProtocolWsUrl, + required this.networkProtocolWssConnect, + required this.networkProtocolWssMaxConnections, + required this.networkLeasesMaxServerSignalLeases, + required this.networkLeasesMaxServerRelayLeases, + required this.networkLeasesMaxClientSignalLeases, + required this.networkLeasesMaxClientRelayLeases, }); + + String get json { + return ""; + } + + factory VeilidConfig.fromJson(String json) { + var parsed = jsonDecode(json); + VeilidConfig({ + programName: parsed["program_name"], + veilidNamespace: parsed["veilid_namespace"], + apiLogLevel: veilidLogLevelFromJson(parsed["api_log_level"]), + capabilitiesProtocolUdp: parsed["capabilities__protocol_udp"], + capabilitiesProtocolConnectTcp: parsed["capabilities__protocol_connect_tcp"], + capabilitiesProtocolAcceptTcp: parsed["capabilities__protocol_accept_tcp"], + capabilitiesProtocolConnectWs: parsed["capabilities__protocol_connect_ws"], + capabilitiesProtocolAcceptWs: parsed["capabilities__protocol_accept_ws"], + capabilitiesProtocolConnectWss: parsed["capabilities__protocol_connect_wss"] + // required this.capabilitiesProtocolAcceptWss, + // required this.protectedStoreAllowInsecureFallback, + // required this.protectedStoreAlwaysUseInsecureStorage, + // required this.protectedStoreInsecureFallbackDirectory, + // required this.protectedStoreDelete, + // required this.tableStoreDirectory, + // required this.tableStoreDelete, + // required this.blockStoreDirectory, + // required this.blockStoreDelete, + // required this.networkMaxConnections, + // required this.networkConnectionInitialTimeoutMs, + // required this.networkNodeId, + // required this.networkNodeIdSecret, + // required this.networkBootstrap, + // required this.networkUpnp, + // required this.networkNatpmp, + // required this.networkEnableLocalPeerScope, + // required this.networkRestrictedNatRetries, + // required this.networkRpcConcurrency, + // required this.networkRpcQueueSize, + // this.networkRpcMaxTimestampBehindMs, + // this.networkRpcMaxTimestampAheadMs, + // required this.networkRpcTimeoutMs, + // required this.networkRpcMaxRouteHopCount, + // this.networkDhtResolveNodeTimeoutMs, + // required this.networkDhtResolveNodeCount, + // required this.networkDhtResolveNodeFanout, + // required this.networkDhtMaxFindNodeCount, + // this.networkDhtGetValueTimeoutMs, + // required this.networkDhtGetValueCount, + // required this.networkDhtGetValueFanout, + // this.networkDhtSetValueTimeoutMs, + // required this.networkDhtSetValueCount, + // required this.networkDhtSetValueFanout, + // required this.networkDhtMinPeerCount, + // required this.networkDhtMinPeerRefreshTimeMs, + // required this.networkDhtValidateDialInfoReceiptTimeMs, + // required this.networkProtocolUdpEnabled, + // required this.networkProtocolUdpSocketPoolSize, + // required this.networkProtocolUdpListenAddress, + // this.networkProtocolUdpPublicAddress, + // required this.networkProtocolTcpConnect, + // required this.networkProtocolTcpListen, + // required this.networkProtocolTcpMaxConnections, + // required this.networkProtocolTcpListenAddress, + // this.networkProtocolTcpPublicAddress, + // required this.networkProtocolWsConnect, + // required this.networkProtocolWsListen, + // required this.networkProtocolWsMaxConnections, + // required this.networkProtocolWsListenAddress, + // required this.networkProtocolWsPath, + // this.networkProtocolWsUrl, + // required this.networkProtocolWssConnect, + // required this.networkProtocolWssMaxConnections, + // required this.networkLeasesMaxServerSignalLeases, + // required this.networkLeasesMaxServerRelayLeases, + // required this.networkLeasesMaxClientSignalLeases, + // required this.networkLeasesMaxClientRelayLeases, + }) + + } } -// VeilidUpdate +////////////////////////////////////// +/// VeilidUpdate abstract class VeilidUpdate { - VeilidUpdateKind get kind; + factory VeilidUpdate.fromJson(String json) { + var parsed = jsonDecode(json); + switch (parsed["kind"]) { + case "Log": + { + return VeilidUpdateLog( + veilidLogLevelFromJson(parsed["log_level"]), parsed["message"]); + } + case "Attachment": + { + return VeilidUpdateAttachment( + attachmentStateFromJson(parsed["state"])); + } + default: + { + throw VeilidAPIExceptionInternal( + "Invalid VeilidAPIException type: ${parsed['kind']}"); + } + } + } } class VeilidUpdateLog implements VeilidUpdate { final VeilidLogLevel logLevel; final String message; - + // VeilidUpdateLog(this.logLevel, this.message); } class VeilidUpdateAttachment implements VeilidUpdate { final AttachmentState state; - + // VeilidUpdateAttachment(this.state); } -// VeilidState +////////////////////////////////////// +/// VeilidState class VeilidState { final AttachmentState attachment; @@ -71,22 +338,206 @@ class VeilidState { VeilidState(this.attachment); } +////////////////////////////////////// +/// VeilidAPIException +abstract class VeilidAPIException implements Exception { + factory VeilidAPIException.fromJson(String json) { + var parsed = jsonDecode(json); + switch (parsed["kind"]) { + case "NotInitialized": + { + return VeilidAPIExceptionNotInitialized(); + } + case "AlreadyInitialized": + { + return VeilidAPIExceptionAlreadyInitialized(); + } + case "Timeout": + { + return VeilidAPIExceptionTimeout(); + } + case "Shutdown": + { + return VeilidAPIExceptionShutdown(); + } + case "NodeNotFound": + { + return VeilidAPIExceptionNodeNotFound(parsed["node_id"]); + } + case "NoDialInfo": + { + return VeilidAPIExceptionNoDialInfo(parsed["node_id"]); + } + case "Internal": + { + return VeilidAPIExceptionInternal(parsed["message"]); + } + case "Unimplemented": + { + return VeilidAPIExceptionUnimplemented(parsed["unimplemented"]); + } + case "ParseError": + { + return VeilidAPIExceptionParseError( + parsed["message"], parsed["value"]); + } + case "InvalidArgument": + { + return VeilidAPIExceptionInvalidArgument( + parsed["context"], parsed["argument"], parsed["value"]); + } + case "MissingArgument": + { + return VeilidAPIExceptionMissingArgument( + parsed["context"], parsed["argument"]); + } + default: + { + throw VeilidAPIExceptionInternal( + "Invalid VeilidAPIException type: ${parsed['kind']}"); + } + } + } +} -// Veilid singleton factory +class VeilidAPIExceptionNotInitialized implements VeilidAPIException { + @override + String toString() { + return "VeilidAPIException: NotInitialized"; + } +} -abstract class Veilid { - static Veilid _instance; +class VeilidAPIExceptionAlreadyInitialized implements VeilidAPIException { + @override + String toString() { + return "VeilidAPIException: AlreadyInitialized"; + } +} - static Veilid get instance { - _instance ??= getVeilid(); - return _instance; +class VeilidAPIExceptionTimeout implements VeilidAPIException { + @override + String toString() { + return "VeilidAPIException: Timeout"; + } +} + +class VeilidAPIExceptionShutdown implements VeilidAPIException { + @override + String toString() { + return "VeilidAPIException: Shutdown"; + } +} + +class VeilidAPIExceptionNodeNotFound implements VeilidAPIException { + final String nodeId; + + @override + String toString() { + return "VeilidAPIException: NodeNotFound (nodeId: $nodeId)"; } - Stream startupVeilidCore(String config); - Future> getVeilidState(); - Future> changeApiLogLevel(VeilidLogLevel logLevel); - Future> shutdownVeilidCore(); + // + VeilidAPIExceptionNodeNotFound(this.nodeId); +} + +class VeilidAPIExceptionNoDialInfo implements VeilidAPIException { + final String nodeId; + + @override + String toString() { + return "VeilidAPIException: NoDialInfo (nodeId: $nodeId)"; + } + + // + VeilidAPIExceptionNoDialInfo(this.nodeId); +} + +class VeilidAPIExceptionInternal implements VeilidAPIException { + final String message; + + @override + String toString() { + return "VeilidAPIException: Internal ($message)"; + } + + // + VeilidAPIExceptionInternal(this.message); +} + +class VeilidAPIExceptionUnimplemented implements VeilidAPIException { + final String message; + + @override + String toString() { + return "VeilidAPIException: Unimplemented ($message)"; + } + + // + VeilidAPIExceptionUnimplemented(this.message); +} + +class VeilidAPIExceptionParseError implements VeilidAPIException { + final String message; + final String value; + + @override + String toString() { + return "VeilidAPIException: ParseError ($message)\n value: $value"; + } + + // + VeilidAPIExceptionParseError(this.message, this.value); +} + +class VeilidAPIExceptionInvalidArgument implements VeilidAPIException { + final String context; + final String argument; + final String value; + + @override + String toString() { + return "VeilidAPIException: InvalidArgument ($context:$argument)\n value: $value"; + } + + // + VeilidAPIExceptionInvalidArgument(this.context, this.argument, this.value); +} + +class VeilidAPIExceptionMissingArgument implements VeilidAPIException { + final String context; + final String argument; + + @override + String toString() { + return "VeilidAPIException: MissingArgument ($context:$argument)"; + } + + // + VeilidAPIExceptionMissingArgument(this.context, this.argument); +} + +////////////////////////////////////// +/// VeilidVersion + +class VeilidVersion { + final int major; + final int minor; + final int patch; + + VeilidVersion(this.major, this.minor, this.patch); +} + +////////////////////////////////////// +/// Veilid singleton factory + +abstract class Veilid { + static late Veilid instance = getVeilid(); + + Stream startupVeilidCore(VeilidConfig config); + Future getVeilidState(); + Future changeApiLogLevel(VeilidLogLevel logLevel); + Future shutdownVeilidCore(); String veilidVersionString(); VeilidVersion veilidVersion(); } diff --git a/veilid-flutter/lib/veilid_ffi.dart b/veilid-flutter/lib/veilid_ffi.dart index 37c11e61..9faea64c 100644 --- a/veilid-flutter/lib/veilid_ffi.dart +++ b/veilid-flutter/lib/veilid_ffi.dart @@ -1,12 +1,12 @@ import 'dart:async'; -import 'dart:ffi' as ffi; +import 'dart:ffi'; import 'dart:io'; -import 'dart:typed_data'; +import 'dart:isolate'; +import 'dart:convert'; import 'package:ffi/ffi.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter/material.dart'; -import 'package:oxidized/oxidized.dart'; + +import 'veilid.dart'; ////////////////////////////////////////////////////////// @@ -17,16 +17,19 @@ final _path = Platform.isWindows : Platform.isMacOS ? 'lib$_base.dylib' : 'lib$_base.so'; -late final _dylib = Platform.isIOS ? DynamicLibrary.process() : DynamicLibrary.open(_path); +late final _dylib = + Platform.isIOS ? DynamicLibrary.process() : DynamicLibrary.open(_path); // Linkage for initialization -typedef _dart_postCObject = NativeFunction)>; +typedef _dart_postCObject + = NativeFunction)>; // fn free_string(s: *mut std::os::raw::c_char) typedef _free_string_C = Void Function(Pointer); typedef _free_string_Dart = void Function(Pointer); // fn initialize_veilid_flutter(dart_post_c_object_ptr: ffi::DartPostCObjectFnType) typedef _initializeVeilidFlutter_C = Void Function(Pointer<_dart_postCObject>); -typedef _initializeVeilidFlutter_Dart = void Function(Pointer<_dart_postCObject>); +typedef _initializeVeilidFlutter_Dart = void Function( + Pointer<_dart_postCObject>); // fn startup_veilid_core(port: i64, config: FfiStr) typedef _startup_veilid_core_C = Void Function(Int64, Pointer); typedef _startup_veilid_core_Dart = void Function(int, Pointer); @@ -42,8 +45,9 @@ typedef _shutdown_veilid_core_Dart = void Function(int); // fn veilid_version_string() -> *mut c_char typedef _veilid_version_string_C = Pointer Function(); typedef _veilid_version_string_Dart = Pointer Function(); + // fn veilid_version() -> VeilidVersion -class VeilidVersion extends Struct { +class VeilidVersionFFI extends Struct { @Uint32() external int major; @Uint32() @@ -51,14 +55,115 @@ class VeilidVersion extends Struct { @Uint32() external int patch; } -typedef _veilid_version_C = VeilidVersion Function(); -typedef _veilid_version_Dart = VeilidVersion Function(); + +typedef _veilid_version_C = VeilidVersionFFI Function(); +typedef _veilid_version_Dart = VeilidVersionFFI Function(); + +// Async message types +const int MESSAGE_OK = 0; +const int MESSAGE_ERR = 1; +const int MESSAGE_OK_JSON = 2; +const int MESSAGE_ERR_JSON = 3; +const int MESSAGE_STREAM_ITEM = 4; +const int MESSAGE_STREAM_ITEM_JSON = 5; +const int MESSAGE_STREAM_ABORT = 6; +const int MESSAGE_STREAM_ABORT_JSON = 7; +const int MESSAGE_STREAM_CLOSE = 8; // Interface factory for high level Veilid API Veilid getVeilid() => VeilidFFI(_dylib); +// Parse handle async returns +Future processSingleAsyncReturn(Future future) async { + return future.then((value) { + final list = value as List; + switch (list[0] as int) { + case MESSAGE_OK: + { + if (list[1] != null) { + throw VeilidAPIExceptionInternal( + "Unexpected MESSAGE_OK value '${list[1]}' where null expected"); + } + return list[1] as T; + } + case MESSAGE_ERR: + { + throw VeilidAPIExceptionInternal("Internal API Error: ${value[1]}"); + } + case MESSAGE_OK_JSON: + { + var ret = jsonDecode(list[1] as String); + if (ret != null) { + throw VeilidAPIExceptionInternal( + "Unexpected MESSAGE_OK_JSON value '$ret' where null expected"); + } + return ret as T; + } + case MESSAGE_ERR_JSON: + { + throw VeilidAPIException.fromJson(value[1] as String); + } + default: + { + throw VeilidAPIExceptionInternal( + "Unexpected async return message type: ${value[0]}"); + } + } + }).catchError((e) { + // Wrap all other errors in VeilidAPIExceptionInternal + throw VeilidAPIExceptionInternal(e.toString()); + }, test: (e) { + // Pass errors that are already VeilidAPIException through without wrapping + return e is! VeilidAPIException; + }); +} + +Future processSingleAsyncVoid(Future future) async { + return future.then((value) { + final list = value as List; + switch (list[0] as int) { + case MESSAGE_OK: + { + if (list[1] != null) { + throw VeilidAPIExceptionInternal( + "Unexpected MESSAGE_OK value '${list[1]}' where null expected"); + } + return; + } + case MESSAGE_ERR: + { + throw VeilidAPIExceptionInternal("Internal API Error: ${value[1]}"); + } + case MESSAGE_OK_JSON: + { + var ret = jsonDecode(list[1] as String); + if (ret != null) { + throw VeilidAPIExceptionInternal( + "Unexpected MESSAGE_OK_JSON value '$ret' where null expected"); + } + return; + } + case MESSAGE_ERR_JSON: + { + throw VeilidAPIException.fromJson(value[1] as String); + } + default: + { + throw VeilidAPIExceptionInternal( + "Unexpected async return message type: ${value[0]}"); + } + } + }).catchError((e) { + // Wrap all other errors in VeilidAPIExceptionInternal + throw VeilidAPIExceptionInternal(e.toString()); + }, test: (e) { + // Pass errors that are already VeilidAPIException through without wrapping + return e is! VeilidAPIException; + }); +} + // FFI implementation of high level Veilid API -class VeilidFFI { +class VeilidFFI implements Veilid { // veilid_core shared library final DynamicLibrary _dylib; @@ -69,38 +174,77 @@ class VeilidFFI { final _change_api_log_level_Dart _changeApiLogLevel; final _shutdown_veilid_core_Dart _shutdownVeilidCore; final _veilid_version_string_Dart _veilidVersionString; - final _veilid_version_Dat _veilidVersion; + final _veilid_version_Dart _veilidVersion; - VeilidFFI(DynamicLibrary dylib): _dylib = dylib { - var initializeVeilidFlutter = _dylib.lookupFunction<_initializeVeilidFlutter_C, _initializeVeilidFlutter_Dart>('initialize_veilid_flutter'); + VeilidFFI(DynamicLibrary dylib) + : _dylib = dylib, + _freeString = dylib + .lookupFunction<_free_string_C, _free_string_Dart>('free_string'), + _startupVeilidCore = dylib.lookupFunction<_startup_veilid_core_C, + _startup_veilid_core_Dart>('startup_veilid_core'), + _getVeilidState = + dylib.lookupFunction<_get_veilid_state_C, _get_veilid_state_Dart>( + 'get_veilid_state'), + _changeApiLogLevel = dylib.lookupFunction<_change_api_log_level_C, + _change_api_log_level_Dart>('change_api_log_level'), + _shutdownVeilidCore = dylib.lookupFunction<_shutdown_veilid_core_C, + _shutdown_veilid_core_Dart>('shutdown_veilid_core'), + _veilidVersionString = dylib.lookupFunction<_veilid_version_string_C, + _veilid_version_string_Dart>('veilid_version_string'), + _veilidVersion = + dylib.lookupFunction<_veilid_version_C, _veilid_version_Dart>( + 'veilid_version') { + // Get veilid_flutter initializer + var initializeVeilidFlutter = _dylib.lookupFunction< + _initializeVeilidFlutter_C, + _initializeVeilidFlutter_Dart>('initialize_veilid_flutter'); initializeVeilidFlutter(NativeApi.postCObject); - - // Look up shared library functions - _freeString = dylib.lookupFunction<_free_string_C, _free_string_Dart>('free_string'); - _startupVeilidCore = dylib.lookupFunction<_startup_veilid_core_C, _startup_veilid_core_Dart>('startup_veilid_core'); - _getveilidState = dylib.lookupFunction<_get_veilid_state_C, _get_veilid_state_Dart>('get_veilid_state'); - _changeApiLogLevel = dylib.lookupFunction<_change_api_log_level_C, _change_api_log_level_Dart>('change_api_log_level'); - _shutdownVeilidCore = dylib.lookupFunction<_shutdown_veilid_core_C, _shutdown_veilid_core_Dart>('shutdown_veilid_core'); - _veilidVersionString = dylib.lookupFunction<_veilid_version_string_C, _veilid_version_string_Dart>('veilid_version_string'); - _veilidVersion = dylib.lookupFunction<_veilid_version_C, _veilid_version_Dart>('veilid_version'); } - Stream startupVeilidCore(String config); - Future> getVeilidState(); - Future> changeApiLogLevel(VeilidLogLevel logLevel); - Future> shutdownVeilidCore() async { - // xxx continue here + @override + Stream startupVeilidCore(VeilidConfig config) async* {} + + @override + Future getVeilidState() async { + final recv_port = ReceivePort("shutdown_veilid_core"); + final send_port = recv_port.sendPort; + _shutdownVeilidCore(send_port.nativePort); + processSingleAsyncReturn(recv_port.single); } + @override + Future changeApiLogLevel(VeilidLogLevel logLevel) async { + var nativeLogLevel = jsonEncode(logLevel).toNativeUtf8(); + final recv_port = ReceivePort("change_api_log_level"); + final send_port = recv_port.sendPort; + _changeApiLogLevel(send_port.nativePort, nativeLogLevel); + malloc.free(nativeLogLevel); + processSingleAsyncVoid(recv_port.single); + } + + @override + Future shutdownVeilidCore() async { + final recv_port = ReceivePort("shutdown_veilid_core"); + final send_port = recv_port.sendPort; + _shutdownVeilidCore(send_port.nativePort); + processSingleAsyncVoid(recv_port.single); + } + + @override String veilidVersionString() { - final version_string = _veilidVersionString(); - String ret = version_string.toDartString(); - _freeString(version_string); - return version_string; + final versionString = _veilidVersionString(); + String ret = versionString.toDartString(); + _freeString(versionString); + return ret; } + @override VeilidVersion veilidVersion() { - return _veilidVersion(); + final version = _veilidVersion(); + return VeilidVersion( + version.major, + version.minor, + version.patch, + ); } - } diff --git a/veilid-flutter/lib/veilid_js.dart b/veilid-flutter/lib/veilid_js.dart index 0b83aaeb..9261e81e 100644 --- a/veilid-flutter/lib/veilid_js.dart +++ b/veilid-flutter/lib/veilid_js.dart @@ -6,14 +6,12 @@ import 'dart:typed_data'; import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; -import 'package:oxidized/oxidized.dart'; ////////////////////////////////////////////////////////// Veilid getVeilid() => VeilidJS(); class VeilidJS { - Stream startupVeilidCore(Object? configCallback(String key)) { throw UnimplementedError(); } @@ -25,7 +23,7 @@ class VeilidJS { Future changeApiLogLevel(VeilidLogLevel logLevel) { throw UnimplementedError(); } - + Future shutdownVeilidCore() { throw UnimplementedError(); } @@ -37,5 +35,4 @@ class VeilidJS { Future veilidVersion() { throw UnimplementedError(); } - } diff --git a/veilid-flutter/lib/veilid_stub.dart b/veilid-flutter/lib/veilid_stub.dart index 1c56bed6..1606518d 100644 --- a/veilid-flutter/lib/veilid_stub.dart +++ b/veilid-flutter/lib/veilid_stub.dart @@ -1,3 +1,3 @@ -import 'veilid.dart' +import 'veilid.dart'; Veilid getVeilid() => throw UnsupportedError('Cannot create Veilid object'); diff --git a/veilid-flutter/pubspec.yaml b/veilid-flutter/pubspec.yaml index c4b747c7..994ea6d7 100644 --- a/veilid-flutter/pubspec.yaml +++ b/veilid-flutter/pubspec.yaml @@ -13,20 +13,13 @@ dependencies: sdk: flutter flutter_web_plugins: sdk: flutter - flutter_rust_bridge: ^1.14.0 - freezed_annotation: ^1.1.0 - oxidized: ^5.1.0 ffi: ^1.1.2 + change_case: ^1.0.1 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^1.0.0 - build_runner: ^2.1.7 - freezed: ^1.1.0 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter. flutter: diff --git a/veilid-server/src/client_api.rs b/veilid-server/src/client_api.rs index fd050c47..3c7cf607 100644 --- a/veilid-server/src/client_api.rs +++ b/veilid-server/src/client_api.rs @@ -42,7 +42,7 @@ fn convert_update( } => { panic!("Should not be logging to api in server!"); } - veilid_core::VeilidUpdate::Attachment(state) => { + veilid_core::VeilidUpdate::Attachment { state } => { let mut att = rpc_update.init_attachment(); att.set_state(convert_attachment_state(state)); } diff --git a/veilid-server/src/server.rs b/veilid-server/src/server.rs index 2194d12b..4876e419 100644 --- a/veilid-server/src/server.rs +++ b/veilid-server/src/server.rs @@ -31,22 +31,20 @@ pub async fn run_veilid_server(settings: Settings, logs: VeilidLogs) -> Result<( ) = bounded(1); // Create VeilidCore setup - let vcs = veilid_core::VeilidCoreSetup { - update_callback: Arc::new( - move |change: veilid_core::VeilidUpdate| -> veilid_core::SystemPinBoxFuture<()> { - let sender = sender.clone(); - Box::pin(async move { - if sender.send(change).await.is_err() { - error!("error sending veilid update callback"); - } - }) - }, - ), - config_callback: settings.get_core_config_callback(), - }; + let update_callback = Arc::new( + move |change: veilid_core::VeilidUpdate| -> veilid_core::SystemPinBoxFuture<()> { + let sender = sender.clone(); + Box::pin(async move { + if sender.send(change).await.is_err() { + error!("error sending veilid update callback"); + } + }) + }, + ); + let config_callback = settings.get_core_config_callback(); // Start Veilid Core and get API - let veilid_api = veilid_core::api_startup(vcs) + let veilid_api = veilid_core::api_startup(update_callback, config_callback) .await .map_err(|e| format!("VeilidCore startup failed: {}", e))?;