From 90036e06535562c99162f486c2233a64e3c7611d Mon Sep 17 00:00:00 2001 From: Christien Rioux Date: Wed, 26 Feb 2025 15:34:31 +0000 Subject: [PATCH] Fixed for attach speed and futures optimizations --- Cargo.toml | 16 + clippy.toml | 3 + veilid-cli/Cargo.toml | 3 + veilid-cli/src/client_api_connection.rs | 10 +- veilid-cli/src/command_processor.rs | 10 +- veilid-cli/src/main.rs | 5 +- veilid-core/Cargo.toml | 3 + veilid-core/src/component.rs | 18 +- veilid-core/src/crypto/envelope.rs | 2 + veilid-core/src/crypto/guard.rs | 5 + veilid-core/src/crypto/mod.rs | 5 +- veilid-core/src/crypto/receipt.rs | 2 + veilid-core/src/crypto/tests/test_crypto.rs | 8 +- .../src/crypto/tests/test_envelope_receipt.rs | 2 +- veilid-core/src/crypto/tests/test_types.rs | 8 +- .../src/crypto/types/byte_array_types.rs | 5 + veilid-core/src/crypto/types/crypto_typed.rs | 1 + .../src/crypto/types/crypto_typed_group.rs | 7 + veilid-core/src/crypto/types/keypair.rs | 1 + veilid-core/src/crypto/types/mod.rs | 2 + veilid-core/src/crypto/vld0/mod.rs | 1 + veilid-core/src/intf/native/block_store.rs | 14 +- .../src/intf/native/protected_store.rs | 29 +- veilid-core/src/intf/native/system.rs | 5 +- veilid-core/src/intf/wasm/block_store.rs | 11 + veilid-core/src/intf/wasm/protected_store.rs | 39 +- veilid-core/src/intf/wasm/system.rs | 4 + veilid-core/src/lib.rs | 15 +- veilid-core/src/logging/api_tracing_layer.rs | 1 + veilid-core/src/logging/fmt_strip_fields.rs | 1 + .../src/logging/veilid_layer_filter.rs | 4 + .../src/network_manager/connection_manager.rs | 6 +- .../src/network_manager/connection_table.rs | 7 +- .../src/network_manager/direct_boot.rs | 7 +- veilid-core/src/network_manager/mod.rs | 98 +-- .../native/discovery_context.rs | 591 ++++++++++++------ veilid-core/src/network_manager/native/mod.rs | 2 +- .../network_manager/native/protocol/tcp.rs | 2 +- .../src/network_manager/native/protocol/ws.rs | 2 +- .../native/tasks/network_interfaces_task.rs | 6 +- .../native/tasks/update_network_class_task.rs | 44 +- .../src/network_manager/network_connection.rs | 4 +- .../node_contact_method_cache.rs | 132 ++++ .../src/network_manager/receipt_manager.rs | 17 +- veilid-core/src/network_manager/send_data.rs | 528 ++++++++-------- veilid-core/src/network_manager/stats.rs | 18 +- .../tests/test_signed_node_info.rs | 4 +- .../network_manager/types/dial_info_class.rs | 5 +- veilid-core/src/network_manager/wasm/mod.rs | 1 + veilid-core/src/routing_table/mod.rs | 11 +- .../src/routing_table/route_spec_store/mod.rs | 1 + .../route_spec_store_cache.rs | 15 +- .../route_spec_store_content.rs | 2 +- .../routing_table/routing_table_inner/mod.rs | 1 + .../routing_domains/editor.rs | 4 +- .../routing_domains/local_network/editor.rs | 4 +- .../routing_domains/public_internet/editor.rs | 4 +- .../src/routing_table/tasks/bootstrap.rs | 20 +- .../src/routing_table/tasks/ping_validator.rs | 6 +- .../tests/test_serialize_routing_table.rs | 4 +- .../src/rpc_processor/fanout/fanout_call.rs | 25 +- veilid-core/src/rpc_processor/mod.rs | 141 +++-- veilid-core/src/rpc_processor/rpc_status.rs | 13 +- .../rpc_processor/rpc_validate_dial_info.rs | 4 +- veilid-core/src/storage_manager/debug.rs | 11 +- veilid-core/src/storage_manager/get_value.rs | 14 +- .../src/storage_manager/inspect_value.rs | 40 +- veilid-core/src/storage_manager/mod.rs | 11 +- veilid-core/src/storage_manager/set_value.rs | 14 +- .../types/signed_value_descriptor.rs | 2 +- .../src/storage_manager/watch_value.rs | 48 +- veilid-core/src/table_store/mod.rs | 18 +- veilid-core/src/table_store/native.rs | 3 + veilid-core/src/table_store/table_db.rs | 4 + veilid-core/src/table_store/wasm.rs | 1 + .../src/tests/common/test_protected_store.rs | 70 +-- .../src/tests/common/test_veilid_config.rs | 27 +- veilid-core/src/veilid_api/api.rs | 13 +- veilid-core/src/veilid_api/debug.rs | 197 +++--- veilid-core/src/veilid_api/error.rs | 1 + .../src/veilid_api/json_api/process.rs | 24 +- veilid-core/src/veilid_api/routing_context.rs | 42 +- .../veilid_api/tests/test_serialize_json.rs | 73 +-- .../src/veilid_api/tests/test_types.rs | 58 +- .../src/veilid_api/tests/test_types_dht.rs | 6 +- .../veilid_api/tests/test_types_dht_schema.rs | 8 +- .../src/veilid_api/types/aligned_u64.rs | 2 + .../src/veilid_api/types/app_message_call.rs | 8 + .../types/dht/dht_record_descriptor.rs | 2 + .../veilid_api/types/dht/dht_record_report.rs | 3 + .../src/veilid_api/types/dht/schema/dflt.rs | 7 + .../src/veilid_api/types/dht/schema/mod.rs | 6 + .../src/veilid_api/types/dht/schema/smpl.rs | 8 + .../src/veilid_api/types/dht/value_data.rs | 5 + .../types/dht/value_subkey_range_set.rs | 5 + veilid-core/src/veilid_api/types/fourcc.rs | 1 + veilid-core/src/veilid_api/types/safety.rs | 5 +- .../src/veilid_api/types/veilid_log.rs | 3 + .../src/veilid_api/types/veilid_state.rs | 11 + veilid-core/src/veilid_config.rs | 60 +- veilid-flutter/lib/veilid.dart | 11 - veilid-flutter/rust/Cargo.toml | 3 + veilid-flutter/rust/src/lib.rs | 3 - veilid-python/tests/test_dht.py | 18 +- veilid-python/veilid/json_api.py | 3 +- veilid-server/Cargo.toml | 3 + veilid-server/src/client_api.rs | 6 +- veilid-server/src/main.rs | 5 +- veilid-server/src/tools.rs | 10 +- veilid-tools/Cargo.toml | 4 +- veilid-tools/src/assembly_buffer.rs | 1 + veilid-tools/src/async_tag_lock.rs | 3 + veilid-tools/src/deferred_stream_processor.rs | 13 +- veilid-tools/src/event_bus.rs | 9 +- veilid-tools/src/eventual.rs | 4 + veilid-tools/src/eventual_value.rs | 3 + veilid-tools/src/eventual_value_clone.rs | 3 + veilid-tools/src/interval.rs | 4 +- veilid-tools/src/ip_addr_port.rs | 5 + veilid-tools/src/ip_extra.rs | 31 + veilid-tools/src/ipc/ipc_async_std/unix.rs | 3 +- veilid-tools/src/ipc/ipc_tokio/unix.rs | 4 +- veilid-tools/src/ipc/ipc_tokio/windows.rs | 6 +- veilid-tools/src/lib.rs | 12 +- veilid-tools/src/must_join_handle.rs | 5 + veilid-tools/src/must_join_single_future.rs | 1 + veilid-tools/src/network_interfaces/apple.rs | 5 +- veilid-tools/src/network_interfaces/mod.rs | 20 + .../src/network_interfaces/openbsd.rs | 5 +- .../src/network_interfaces/sockaddr_tools.rs | 2 +- veilid-tools/src/network_interfaces/wasm.rs | 1 + veilid-tools/src/pin.rs | 45 ++ veilid-tools/src/random.rs | 2 + veilid-tools/src/socket_tools.rs | 1 + veilid-tools/src/split_url.rs | 1 + veilid-tools/src/startup_lock.rs | 1 + .../src/tests/common/test_event_bus.rs | 18 +- .../src/tests/common/test_host_interface.rs | 26 +- veilid-tools/src/tick_task.rs | 34 +- veilid-tools/src/timeout_or.rs | 1 + veilid-tools/src/timestamp.rs | 6 + veilid-tools/src/tools.rs | 14 +- .../src/virtual_network/router_server/mod.rs | 8 +- .../router_server/server_processor.rs | 2 +- .../virtual_tcp_listener_stream.rs | 2 +- .../src/virtual_network/virtual_tcp_stream.rs | 6 +- veilid-tools/src/wasm.rs | 2 + veilid-wasm/Cargo.toml | 3 + veilid-wasm/src/lib.rs | 20 +- veilid-wasm/src/veilid_client_js.rs | 5 + veilid-wasm/src/veilid_crypto_js.rs | 18 + veilid-wasm/src/veilid_routing_context_js.rs | 1 + veilid-wasm/src/veilid_table_db_js.rs | 2 + 153 files changed, 2037 insertions(+), 1167 deletions(-) create mode 100644 clippy.toml create mode 100644 veilid-core/src/network_manager/node_contact_method_cache.rs create mode 100644 veilid-tools/src/pin.rs diff --git a/Cargo.toml b/Cargo.toml index 2a37196a..04a37bf9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,3 +61,19 @@ debug-assertions = false [profile.dev.package.chacha20] opt-level = 3 debug-assertions = false + +[workspace.lints.clippy] +all = { level = "deny", priority = -1 } +must_use_candidate = "deny" +large_futures = "deny" +large_stack_arrays = "deny" +large_stack_frames = "deny" +large_types_passed_by_value = "deny" +unused_async = "deny" +ptr_cast_constness = "deny" +comparison_chain = "allow" +upper_case_acronyms = "allow" + +[workspace.lints.rust] +unused_must_use = "deny" +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tokio_unstable)'] } diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 00000000..d97544cc --- /dev/null +++ b/clippy.toml @@ -0,0 +1,3 @@ +future-size-threshold = 8192 +array-size-threshold = 8192 +stack-size-threshold = 128000 diff --git a/veilid-cli/Cargo.toml b/veilid-cli/Cargo.toml index 4b3b87ca..d219ed1a 100644 --- a/veilid-cli/Cargo.toml +++ b/veilid-cli/Cargo.toml @@ -77,3 +77,6 @@ console = "0.15.8" [dev-dependencies] serial_test = "^2" + +[lints] +workspace = true diff --git a/veilid-cli/src/client_api_connection.rs b/veilid-cli/src/client_api_connection.rs index 9124764a..a45356f8 100644 --- a/veilid-cli/src/client_api_connection.rs +++ b/veilid-cli/src/client_api_connection.rs @@ -51,7 +51,7 @@ impl ClientApiConnection { inner.reply_channels.clear(); } - async fn process_veilid_state<'a>(&self, state: &json::JsonValue) { + fn process_veilid_state(&self, state: &json::JsonValue) { let comproc = self.inner.lock().comproc.clone(); comproc.update_attachment(&state["attachment"]); comproc.update_network_status(&state["network"]); @@ -77,7 +77,7 @@ impl ClientApiConnection { } } - async fn process_veilid_update(&self, update: json::JsonValue) { + fn process_veilid_update(&self, update: json::JsonValue) { let comproc = self.inner.lock().comproc.clone(); let Some(kind) = update["kind"].as_str() else { comproc.log_message(Level::Error, &format!("missing update kind: {}", update)); @@ -164,7 +164,7 @@ impl ClientApiConnection { }; if j["type"] == "Update" { - this.process_veilid_update(j).await; + this.process_veilid_update(j); } else if j["type"] == "Response" { this.process_response(j).await; } @@ -198,7 +198,7 @@ impl ClientApiConnection { error!("failed to get state: {}", resp["error"]); return; } - capi.process_veilid_state(&resp["value"]).await; + capi.process_veilid_state(&resp["value"]); }); // Send and receive until we're done or a stop is requested @@ -420,7 +420,7 @@ impl ClientApiConnection { } // End Client API connection - pub async fn disconnect(&self) { + pub fn disconnect(&self) { trace!("ClientApiConnection::disconnect"); let mut inner = self.inner.lock(); if inner.disconnector.is_some() { diff --git a/veilid-cli/src/command_processor.rs b/veilid-cli/src/command_processor.rs index b802dfd6..ef0b7dab 100644 --- a/veilid-cli/src/command_processor.rs +++ b/veilid-cli/src/command_processor.rs @@ -182,7 +182,7 @@ Core Debug Commands: let capi = self.capi(); let ui = self.ui_sender(); spawn_detached_local("cmd disconnect", async move { - capi.disconnect().await; + capi.disconnect(); ui.send_callback(callback); }); Ok(()) @@ -195,7 +195,7 @@ Core Debug Commands: let this = self.clone(); spawn_detached_local("cmd connect", async move { - capi.disconnect().await; + capi.disconnect(); if let Some(rest) = rest { if let Ok(subnode_index) = u16::from_str(&rest) { @@ -690,7 +690,7 @@ Core Debug Commands: //////////////////////////////////////////// pub fn start_connection(&self) { self.inner_mut().reconnect = true; - self.inner_mut().connection_waker.resolve(); + drop(self.inner_mut().connection_waker.resolve()); } // pub fn stop_connection(&self) { // self.inner_mut().reconnect = false; @@ -701,12 +701,12 @@ Core Debug Commands: // } pub fn cancel_reconnect(&self) { self.inner_mut().reconnect = false; - self.inner_mut().connection_waker.resolve(); + drop(self.inner_mut().connection_waker.resolve()); } pub fn quit(&self) { self.inner_mut().finished = true; self.inner_mut().reconnect = false; - self.inner_mut().connection_waker.resolve(); + drop(self.inner_mut().connection_waker.resolve()); } // called by ui diff --git a/veilid-cli/src/main.rs b/veilid-cli/src/main.rs index fe540eb4..0ae8f147 100644 --- a/veilid-cli/src/main.rs +++ b/veilid-cli/src/main.rs @@ -1,6 +1,3 @@ -#![deny(clippy::all)] -#![allow(clippy::comparison_chain, clippy::upper_case_acronyms)] -#![deny(unused_must_use)] #![recursion_limit = "256"] use crate::{tools::*, ui::*}; @@ -290,7 +287,7 @@ fn main() -> Result<(), String> { // When UI quits, close connection and command processor cleanly comproc2.quit(); - capi.disconnect().await; + capi.disconnect(); }; cfg_if! { diff --git a/veilid-core/Cargo.toml b/veilid-core/Cargo.toml index e51167d1..d8b72852 100644 --- a/veilid-core/Cargo.toml +++ b/veilid-core/Cargo.toml @@ -286,3 +286,6 @@ reqwest = { version = "0.11", features = ["blocking"], optional = true } [package.metadata.wasm-pack.profile.release] wasm-opt = ["-O", "--enable-mutable-globals"] + +[lints] +workspace = true diff --git a/veilid-core/src/component.rs b/veilid-core/src/component.rs index 6d8cf78d..5a4e55c5 100644 --- a/veilid-core/src/component.rs +++ b/veilid-core/src/component.rs @@ -16,10 +16,10 @@ pub trait VeilidComponent: AsAnyArcSendSync + VeilidComponentRegistryAccessor + core::fmt::Debug { fn name(&self) -> &'static str; - fn init(&self) -> SendPinBoxFutureLifetime<'_, EyreResult<()>>; - fn post_init(&self) -> SendPinBoxFutureLifetime<'_, EyreResult<()>>; - fn pre_terminate(&self) -> SendPinBoxFutureLifetime<'_, ()>; - fn terminate(&self) -> SendPinBoxFutureLifetime<'_, ()>; + fn init(&self) -> PinBoxFuture<'_, EyreResult<()>>; + fn post_init(&self) -> PinBoxFuture<'_, EyreResult<()>>; + fn pre_terminate(&self) -> PinBoxFuture<'_, ()>; + fn terminate(&self) -> PinBoxFuture<'_, ()>; } pub trait VeilidComponentRegistryAccessor { @@ -171,7 +171,7 @@ impl VeilidComponentRegistry { } // Event bus starts up early - self.event_bus.startup().await?; + self.event_bus.startup()?; // Process components in initialization order let init_order = self.get_init_order(); @@ -320,19 +320,19 @@ macro_rules! impl_veilid_component { stringify!($component_name) } - fn init(&self) -> SendPinBoxFutureLifetime<'_, EyreResult<()>> { + fn init(&self) -> PinBoxFuture<'_, EyreResult<()>> { Box::pin(async { self.init_async().await }) } - fn post_init(&self) -> SendPinBoxFutureLifetime<'_, EyreResult<()>> { + fn post_init(&self) -> PinBoxFuture<'_, EyreResult<()>> { Box::pin(async { self.post_init_async().await }) } - fn pre_terminate(&self) -> SendPinBoxFutureLifetime<'_, ()> { + fn pre_terminate(&self) -> PinBoxFuture<'_, ()> { Box::pin(async { self.pre_terminate_async().await }) } - fn terminate(&self) -> SendPinBoxFutureLifetime<'_, ()> { + fn terminate(&self) -> PinBoxFuture<'_, ()> { Box::pin(async { self.terminate_async().await }) } } diff --git a/veilid-core/src/crypto/envelope.rs b/veilid-core/src/crypto/envelope.rs index b05f4a6a..b495ec18 100644 --- a/veilid-core/src/crypto/envelope.rs +++ b/veilid-core/src/crypto/envelope.rs @@ -45,6 +45,7 @@ pub struct Envelope { } impl Envelope { + #[must_use] pub fn new( version: EnvelopeVersion, crypto_kind: CryptoKind, @@ -314,6 +315,7 @@ impl Envelope { Ok(data) } + #[must_use] pub fn get_version(&self) -> u8 { self.version } diff --git a/veilid-core/src/crypto/guard.rs b/veilid-core/src/crypto/guard.rs index abd9e9da..6e52822a 100644 --- a/veilid-core/src/crypto/guard.rs +++ b/veilid-core/src/crypto/guard.rs @@ -1,6 +1,7 @@ use super::*; /// Guard to access a particular cryptosystem +#[must_use] pub struct CryptoSystemGuard<'a> { crypto_system: Arc, _phantom: core::marker::PhantomData<&'a (dyn CryptoSystem + Send + Sync)>, @@ -27,6 +28,7 @@ impl<'a> core::ops::Deref for CryptoSystemGuard<'a> { } /// Async cryptosystem guard to help break up heavy blocking operations +#[must_use] pub struct AsyncCryptoSystemGuard<'a> { guard: CryptoSystemGuard<'a>, } @@ -42,6 +44,7 @@ impl<'a> AsyncCryptoSystemGuard<'a> { pub fn kind(&self) -> CryptoKind { self.guard.kind() } + #[must_use] pub fn crypto(&self) -> VeilidComponentGuard<'_, Crypto> { self.guard.crypto() } @@ -59,6 +62,7 @@ impl<'a> AsyncCryptoSystemGuard<'a> { pub async fn random_bytes(&self, len: u32) -> Vec { yielding(|| self.guard.random_bytes(len)).await } + #[must_use] pub fn default_salt_length(&self) -> u32 { self.guard.default_salt_length() } @@ -160,6 +164,7 @@ impl<'a> AsyncCryptoSystemGuard<'a> { } // AEAD Encrypt/Decrypt + #[must_use] pub fn aead_overhead(&self) -> usize { self.guard.aead_overhead() } diff --git a/veilid-core/src/crypto/mod.rs b/veilid-core/src/crypto/mod.rs index 71b2b897..49671d8d 100644 --- a/veilid-core/src/crypto/mod.rs +++ b/veilid-core/src/crypto/mod.rs @@ -67,13 +67,14 @@ pub const VALID_ENVELOPE_VERSIONS: [EnvelopeVersion; 1] = [0u8]; /// Number of envelope versions to keep on structures if many are present beyond the ones we consider valid pub const MAX_ENVELOPE_VERSIONS: usize = 3; /// Return the best envelope version we support +#[must_use] pub fn best_envelope_version() -> EnvelopeVersion { VALID_ENVELOPE_VERSIONS[0] } struct CryptoInner { dh_cache: DHCache, - flush_future: Option>, + flush_future: Option>, } impl fmt::Debug for CryptoInner { @@ -88,6 +89,7 @@ impl fmt::Debug for CryptoInner { } /// Crypto factory implementation +#[must_use] pub struct Crypto { registry: VeilidComponentRegistry, inner: Mutex, @@ -221,6 +223,7 @@ impl Crypto { }; } + #[expect(clippy::unused_async)] async fn terminate_async(&self) { // Nothing to terminate at this time } diff --git a/veilid-core/src/crypto/receipt.rs b/veilid-core/src/crypto/receipt.rs index 5231154f..02dca5c0 100644 --- a/veilid-core/src/crypto/receipt.rs +++ b/veilid-core/src/crypto/receipt.rs @@ -196,6 +196,7 @@ impl Receipt { Ok(data) } + #[must_use] pub fn get_version(&self) -> u8 { self.version } @@ -216,6 +217,7 @@ impl Receipt { TypedKey::new(self.crypto_kind, self.sender_id) } + #[must_use] pub fn get_extra_data(&self) -> &[u8] { &self.extra_data } diff --git a/veilid-core/src/crypto/tests/test_crypto.rs b/veilid-core/src/crypto/tests/test_crypto.rs index bb9d7539..a356c9e8 100644 --- a/veilid-core/src/crypto/tests/test_crypto.rs +++ b/veilid-core/src/crypto/tests/test_crypto.rs @@ -221,11 +221,11 @@ pub async fn test_generation(vcrypto: &AsyncCryptoSystemGuard<'_>) { let pstr5 = vcrypto.hash_password(b"abc124", b"qwerasdg").await.unwrap(); assert_ne!(pstr3, pstr5); - vcrypto + let _ = vcrypto .hash_password(b"abc123", b"qwe") .await .expect_err("should reject short salt"); - vcrypto + let _ = vcrypto .hash_password( b"abc123", b"qwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerz", @@ -249,11 +249,11 @@ pub async fn test_generation(vcrypto: &AsyncCryptoSystemGuard<'_>) { let ss5 = vcrypto.derive_shared_secret(b"abc124", b"qwerasdg").await; assert_ne!(ss3, ss5); - vcrypto + let _ = vcrypto .derive_shared_secret(b"abc123", b"qwe") .await .expect_err("should reject short salt"); - vcrypto + let _ = vcrypto .derive_shared_secret( b"abc123", b"qwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerz", diff --git a/veilid-core/src/crypto/tests/test_envelope_receipt.rs b/veilid-core/src/crypto/tests/test_envelope_receipt.rs index fda3a1a3..8022b250 100644 --- a/veilid-core/src/crypto/tests/test_envelope_receipt.rs +++ b/veilid-core/src/crypto/tests/test_envelope_receipt.rs @@ -91,7 +91,7 @@ pub async fn test_receipt_round_trip( // Should not validate even when a single bit is changed enc_data[5] = 0x01; - Receipt::from_signed_data(&crypto, &enc_data) + let _ = Receipt::from_signed_data(&crypto, &enc_data) .expect_err("should have failed to decrypt using wrong secret"); // Compare receipts diff --git a/veilid-core/src/crypto/tests/test_types.rs b/veilid-core/src/crypto/tests/test_types.rs index 2d21c892..004f585e 100644 --- a/veilid-core/src/crypto/tests/test_types.rs +++ b/veilid-core/src/crypto/tests/test_types.rs @@ -253,7 +253,7 @@ pub async fn test_encode_decode(vcrypto: &AsyncCryptoSystemGuard<'_>) { assert!(f2.is_err()); } -pub async fn test_typed_convert(vcrypto: &AsyncCryptoSystemGuard<'_>) { +pub fn test_typed_convert(vcrypto: &AsyncCryptoSystemGuard<'_>) { let tks1 = format!( "{}:7lxDEabK_qgjbe38RtBa3IZLrud84P6NhGP-pRTZzdQ", vcrypto.kind() @@ -381,7 +381,7 @@ async fn test_operations(vcrypto: &AsyncCryptoSystemGuard<'_>) { assert_eq!(d4.first_nonzero_bit(), Some(0)); } -pub async fn test_crypto_key_ordering() { +pub fn test_crypto_key_ordering() { let k1 = CryptoKey::new([ 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -413,7 +413,7 @@ pub async fn test_all() { let api = crypto_tests_startup().await; let crypto = api.crypto().unwrap(); - test_crypto_key_ordering().await; + test_crypto_key_ordering(); // Test versions for v in VALID_CRYPTO_KINDS { @@ -423,7 +423,7 @@ pub async fn test_all() { test_sign_and_verify(&vcrypto).await; test_key_conversions(&vcrypto).await; test_encode_decode(&vcrypto).await; - test_typed_convert(&vcrypto).await; + test_typed_convert(&vcrypto); test_hash(&vcrypto).await; test_operations(&vcrypto).await; } diff --git a/veilid-core/src/crypto/types/byte_array_types.rs b/veilid-core/src/crypto/types/byte_array_types.rs index a176d5f9..840b3444 100644 --- a/veilid-core/src/crypto/types/byte_array_types.rs +++ b/veilid-core/src/crypto/types/byte_array_types.rs @@ -83,6 +83,7 @@ macro_rules! byte_array_type { derive(Tsify), tsify(into_wasm_abi) )] + #[must_use] pub struct $name { pub bytes: [u8; $size], } @@ -124,6 +125,7 @@ macro_rules! byte_array_type { } // Big endian bit ordering + #[must_use] pub fn bit(&self, index: usize) -> bool { assert!(index < ($size * 8)); let bi = index / 8; @@ -131,6 +133,7 @@ macro_rules! byte_array_type { ((self.bytes[bi] >> ti) & 1) != 0 } + #[must_use] pub fn first_nonzero_bit(&self) -> Option { for i in 0..$size { let b = self.bytes[i]; @@ -147,6 +150,7 @@ macro_rules! byte_array_type { } // Big endian nibble ordering + #[must_use] pub fn nibble(&self, index: usize) -> u8 { assert!(index < ($size * 2)); let bi = index / 2; @@ -157,6 +161,7 @@ macro_rules! byte_array_type { } } + #[must_use] pub fn first_nonzero_nibble(&self) -> Option<(usize, u8)> { for i in 0..($size * 2) { let n = self.nibble(i); diff --git a/veilid-core/src/crypto/types/crypto_typed.rs b/veilid-core/src/crypto/types/crypto_typed.rs index 740f888c..714fd615 100644 --- a/veilid-core/src/crypto/types/crypto_typed.rs +++ b/veilid-core/src/crypto/types/crypto_typed.rs @@ -1,6 +1,7 @@ use super::*; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[must_use] pub struct CryptoTyped where K: Clone diff --git a/veilid-core/src/crypto/types/crypto_typed_group.rs b/veilid-core/src/crypto/types/crypto_typed_group.rs index a83931ed..364c8483 100644 --- a/veilid-core/src/crypto/types/crypto_typed_group.rs +++ b/veilid-core/src/crypto/types/crypto_typed_group.rs @@ -33,9 +33,11 @@ where + Hash + Encodable, { + #[must_use] pub fn new() -> Self { Self { items: Vec::new() } } + #[must_use] pub fn with_capacity(cap: usize) -> Self { Self { items: Vec::with_capacity(cap), @@ -49,6 +51,7 @@ where out.sort_by(compare_crypto_kind); out } + #[must_use] pub fn keys(&self) -> Vec { let mut out = Vec::new(); for tk in &self.items { @@ -56,6 +59,7 @@ where } out } + #[must_use] pub fn get(&self, kind: CryptoKind) -> Option> { self.items.iter().find(|x| x.kind == kind).copied() } @@ -93,15 +97,18 @@ where } } /// Return preferred typed key of our supported crypto kinds + #[must_use] pub fn best(&self) -> Option> { self.items .first() .copied() .filter(|k| VALID_CRYPTO_KINDS.contains(&k.kind)) } + #[must_use] pub fn is_empty(&self) -> bool { self.items.is_empty() } + #[must_use] pub fn len(&self) -> usize { self.items.len() } diff --git a/veilid-core/src/crypto/types/keypair.rs b/veilid-core/src/crypto/types/keypair.rs index 8bdb6c9d..ae5367ae 100644 --- a/veilid-core/src/crypto/types/keypair.rs +++ b/veilid-core/src/crypto/types/keypair.rs @@ -6,6 +6,7 @@ use super::*; derive(Tsify), tsify(from_wasm_abi, into_wasm_abi) )] +#[must_use] pub struct KeyPair { pub key: PublicKey, pub secret: SecretKey, diff --git a/veilid-core/src/crypto/types/mod.rs b/veilid-core/src/crypto/types/mod.rs index 536df17b..19ab37d9 100644 --- a/veilid-core/src/crypto/types/mod.rs +++ b/veilid-core/src/crypto/types/mod.rs @@ -11,6 +11,7 @@ pub type CryptoKind = FourCC; /// Sort best crypto kinds first /// Better crypto kinds are 'less', ordered toward the front of a list +#[must_use] pub fn compare_crypto_kind(a: &CryptoKind, b: &CryptoKind) -> cmp::Ordering { let a_idx = VALID_CRYPTO_KINDS.iter().position(|k| k == a); let b_idx = VALID_CRYPTO_KINDS.iter().position(|k| k == b); @@ -32,6 +33,7 @@ pub fn compare_crypto_kind(a: &CryptoKind, b: &CryptoKind) -> cmp::Ordering { } /// Intersection of crypto kind vectors +#[must_use] pub fn common_crypto_kinds(a: &[CryptoKind], b: &[CryptoKind]) -> Vec { let mut out = Vec::new(); for ack in a { diff --git a/veilid-core/src/crypto/vld0/mod.rs b/veilid-core/src/crypto/vld0/mod.rs index da94e0bd..0c0d9fc6 100644 --- a/veilid-core/src/crypto/vld0/mod.rs +++ b/veilid-core/src/crypto/vld0/mod.rs @@ -52,6 +52,7 @@ pub struct CryptoSystemVLD0 { } impl CryptoSystemVLD0 { + #[must_use] pub fn new(registry: VeilidComponentRegistry) -> Self { Self { registry } } diff --git a/veilid-core/src/intf/native/block_store.rs b/veilid-core/src/intf/native/block_store.rs index fe0b8475..9e1b4fde 100644 --- a/veilid-core/src/intf/native/block_store.rs +++ b/veilid-core/src/intf/native/block_store.rs @@ -13,6 +13,7 @@ impl fmt::Debug for BlockStoreInner { } #[derive(Debug)] +#[must_use] pub struct BlockStore { registry: VeilidComponentRegistry, inner: Mutex, @@ -31,12 +32,19 @@ impl BlockStore { } } + #[instrument(level = "debug", skip(self))] async fn init_async(&self) -> EyreResult<()> { - // Ensure permissions are correct - // ensure_file_private_owner(&dbpath)?; - Ok(()) } + #[instrument(level = "debug", skip(self), err)] + async fn post_init_async(&self) -> EyreResult<()> { + Ok(()) + } + + #[instrument(level = "debug", skip(self))] + async fn pre_terminate_async(&self) {} + + #[instrument(level = "debug", skip(self))] async fn terminate_async(&self) {} } diff --git a/veilid-core/src/intf/native/protected_store.rs b/veilid-core/src/intf/native/protected_store.rs index 5df36993..fbce53b4 100644 --- a/veilid-core/src/intf/native/protected_store.rs +++ b/veilid-core/src/intf/native/protected_store.rs @@ -15,6 +15,7 @@ impl fmt::Debug for ProtectedStoreInner { } #[derive(Debug)] +#[must_use] pub struct ProtectedStore { registry: VeilidComponentRegistry, inner: Mutex, @@ -37,9 +38,9 @@ impl ProtectedStore { } #[instrument(level = "trace", skip(self), err)] - pub async fn delete_all(&self) -> EyreResult<()> { + pub fn delete_all(&self) -> EyreResult<()> { for kpsk in &KNOWN_PROTECTED_STORE_KEYS { - if let Err(e) = self.remove_user_secret(kpsk).await { + if let Err(e) = self.remove_user_secret(kpsk) { error!("failed to delete '{}': {}", kpsk, e); } else { veilid_log!(self debug "deleted table '{}'", kpsk); @@ -103,7 +104,7 @@ impl ProtectedStore { }; if delete { - self.delete_all().await?; + self.delete_all()?; } Ok(()) @@ -133,7 +134,7 @@ impl ProtectedStore { } #[instrument(level = "trace", skip(self, value), ret, err)] - pub async fn save_user_secret_string + fmt::Debug, V: AsRef + fmt::Debug>( + pub fn save_user_secret_string + fmt::Debug, V: AsRef + fmt::Debug>( &self, key: K, value: V, @@ -152,7 +153,7 @@ impl ProtectedStore { } #[instrument(level = "trace", skip(self), err)] - pub async fn load_user_secret_string + fmt::Debug>( + pub fn load_user_secret_string + fmt::Debug>( &self, key: K, ) -> EyreResult> { @@ -170,22 +171,22 @@ impl ProtectedStore { } #[instrument(level = "trace", skip(self, value))] - pub async fn save_user_secret_json(&self, key: K, value: &T) -> EyreResult + pub fn save_user_secret_json(&self, key: K, value: &T) -> EyreResult where K: AsRef + fmt::Debug, T: serde::Serialize, { let v = serde_json::to_vec(value)?; - self.save_user_secret(&key, &v).await + self.save_user_secret(&key, &v) } #[instrument(level = "trace", skip(self))] - pub async fn load_user_secret_json(&self, key: K) -> EyreResult> + pub fn load_user_secret_json(&self, key: K) -> EyreResult> where K: AsRef + fmt::Debug, T: for<'de> serde::de::Deserialize<'de>, { - let out = self.load_user_secret(key).await?; + let out = self.load_user_secret(key)?; let b = match out { Some(v) => v, None => { @@ -198,7 +199,7 @@ impl ProtectedStore { } #[instrument(level = "trace", skip(self, value), ret, err)] - pub async fn save_user_secret + fmt::Debug>( + pub fn save_user_secret + fmt::Debug>( &self, key: K, value: &[u8], @@ -206,15 +207,15 @@ impl ProtectedStore { let mut s = BASE64URL_NOPAD.encode(value); s.push('!'); - self.save_user_secret_string(key, s.as_str()).await + self.save_user_secret_string(key, s.as_str()) } #[instrument(level = "trace", skip(self), err)] - pub async fn load_user_secret + fmt::Debug>( + pub fn load_user_secret + fmt::Debug>( &self, key: K, ) -> EyreResult>> { - let mut s = match self.load_user_secret_string(key).await? { + let mut s = match self.load_user_secret_string(key)? { Some(s) => s, None => { return Ok(None); @@ -244,7 +245,7 @@ impl ProtectedStore { } #[instrument(level = "trace", skip(self), ret, err)] - pub async fn remove_user_secret + fmt::Debug>(&self, key: K) -> EyreResult { + pub fn remove_user_secret + fmt::Debug>(&self, key: K) -> EyreResult { let inner = self.inner.lock(); match inner .keyring_manager diff --git a/veilid-core/src/intf/native/system.rs b/veilid-core/src/intf/native/system.rs index 3bab9ad9..81b5d073 100644 --- a/veilid-core/src/intf/native/system.rs +++ b/veilid-core/src/intf/native/system.rs @@ -1,5 +1,6 @@ use super::*; +#[expect(clippy::unused_async)] pub async fn get_outbound_relay_peer( _routing_domain: routing_table::RoutingDomain, ) -> Option> { @@ -22,6 +23,7 @@ cfg_if! { } else if #[cfg(feature="rt-tokio")] { use hickory_resolver::{config, TokioAsyncResolver as AsyncResolver, system_conf::read_system_conf}; + #[expect(clippy::unused_async)] async fn resolver( config: config::ResolverConfig, options: config::ResolverOpts, @@ -48,7 +50,7 @@ cfg_if! { cfg_if! { if #[cfg(not(target_os = "windows"))] { - async fn with_resolvers) -> SendPinBoxFuture>(closure: F) -> R { + async fn with_resolvers) -> PinBoxFutureStatic>(closure: F) -> R { let mut resolvers_lock = RESOLVERS.lock().await; if let Some(r) = &*resolvers_lock { return closure(r.clone()).await; @@ -232,6 +234,7 @@ pub async fn ptr_lookup(ip_addr: IpAddr) -> EyreResult { } } +#[must_use] pub fn env_variable_is_defined>(s: S) -> bool { match std::env::var(s.as_ref()) { Ok(v) => !v.is_empty(), diff --git a/veilid-core/src/intf/wasm/block_store.rs b/veilid-core/src/intf/wasm/block_store.rs index 95af0f2d..9e1b4fde 100644 --- a/veilid-core/src/intf/wasm/block_store.rs +++ b/veilid-core/src/intf/wasm/block_store.rs @@ -13,6 +13,7 @@ impl fmt::Debug for BlockStoreInner { } #[derive(Debug)] +#[must_use] pub struct BlockStore { registry: VeilidComponentRegistry, inner: Mutex, @@ -31,9 +32,19 @@ impl BlockStore { } } + #[instrument(level = "debug", skip(self))] async fn init_async(&self) -> EyreResult<()> { Ok(()) } + #[instrument(level = "debug", skip(self), err)] + async fn post_init_async(&self) -> EyreResult<()> { + Ok(()) + } + + #[instrument(level = "debug", skip(self))] + async fn pre_terminate_async(&self) {} + + #[instrument(level = "debug", skip(self))] async fn terminate_async(&self) {} } diff --git a/veilid-core/src/intf/wasm/protected_store.rs b/veilid-core/src/intf/wasm/protected_store.rs index 7a15f60a..25295ab1 100644 --- a/veilid-core/src/intf/wasm/protected_store.rs +++ b/veilid-core/src/intf/wasm/protected_store.rs @@ -6,6 +6,7 @@ use web_sys::*; impl_veilid_log_facility!("pstore"); #[derive(Debug)] +#[must_use] pub struct ProtectedStore { registry: VeilidComponentRegistry, } @@ -18,9 +19,9 @@ impl ProtectedStore { } #[instrument(level = "trace", skip(self), err)] - pub async fn delete_all(&self) -> EyreResult<()> { + pub fn delete_all(&self) -> EyreResult<()> { for kpsk in &KNOWN_PROTECTED_STORE_KEYS { - if let Err(e) = self.remove_user_secret(kpsk).await { + if let Err(e) = self.remove_user_secret(kpsk) { error!("failed to delete '{}': {}", kpsk, e); } else { veilid_log!(self debug "deleted table '{}'", kpsk); @@ -30,20 +31,20 @@ impl ProtectedStore { } #[instrument(level = "debug", skip(self), err)] - pub(crate) async fn init_async(&self) -> EyreResult<()> { + async fn init_async(&self) -> EyreResult<()> { Ok(()) } #[instrument(level = "debug", skip(self), err)] - pub(crate) async fn post_init_async(&self) -> EyreResult<()> { + async fn post_init_async(&self) -> EyreResult<()> { Ok(()) } #[instrument(level = "debug", skip(self))] - pub(crate) async fn pre_terminate_async(&self) {} + async fn pre_terminate_async(&self) {} #[instrument(level = "debug", skip(self))] - pub(crate) async fn terminate_async(&self) {} + async fn terminate_async(&self) {} fn browser_key_name(&self, key: &str) -> String { let config = self.config(); @@ -55,8 +56,8 @@ impl ProtectedStore { } } - //#[instrument(level = "trace", skip(self, value), ret, err)] - pub async fn save_user_secret_string + fmt::Debug, V: AsRef + fmt::Debug>( + #[instrument(level = "trace", skip(self, key, value))] + pub fn save_user_secret_string + fmt::Debug, V: AsRef + fmt::Debug>( &self, key: K, value: V, @@ -98,8 +99,8 @@ impl ProtectedStore { } } - #[instrument(level = "trace", skip(self), err)] - pub async fn load_user_secret_string + fmt::Debug>( + #[instrument(level = "trace", skip(self, key))] + pub fn load_user_secret_string + fmt::Debug>( &self, key: K, ) -> EyreResult> { @@ -133,22 +134,22 @@ impl ProtectedStore { } #[instrument(level = "trace", skip(self, value))] - pub async fn save_user_secret_json(&self, key: K, value: &T) -> EyreResult + pub fn save_user_secret_json(&self, key: K, value: &T) -> EyreResult where K: AsRef + fmt::Debug, T: serde::Serialize, { let v = serde_json::to_vec(value)?; - self.save_user_secret(key, &v).await + self.save_user_secret(key, &v) } #[instrument(level = "trace", skip(self))] - pub async fn load_user_secret_json(&self, key: K) -> EyreResult> + pub fn load_user_secret_json(&self, key: K) -> EyreResult> where K: AsRef + fmt::Debug, T: for<'de> serde::de::Deserialize<'de>, { - let out = self.load_user_secret(key).await?; + let out = self.load_user_secret(key)?; let b = match out { Some(v) => v, None => { @@ -161,7 +162,7 @@ impl ProtectedStore { } #[instrument(level = "trace", skip(self, value), ret, err)] - pub async fn save_user_secret + fmt::Debug>( + pub fn save_user_secret + fmt::Debug>( &self, key: K, value: &[u8], @@ -169,15 +170,15 @@ impl ProtectedStore { let mut s = BASE64URL_NOPAD.encode(value); s.push('!'); - self.save_user_secret_string(key, s.as_str()).await + self.save_user_secret_string(key, s.as_str()) } #[instrument(level = "trace", skip(self), err)] - pub async fn load_user_secret + fmt::Debug>( + pub fn load_user_secret + fmt::Debug>( &self, key: K, ) -> EyreResult>> { - let mut s = match self.load_user_secret_string(key).await? { + let mut s = match self.load_user_secret_string(key)? { Some(s) => s, None => { return Ok(None); @@ -207,7 +208,7 @@ impl ProtectedStore { } #[instrument(level = "trace", skip(self), ret, err)] - pub async fn remove_user_secret + fmt::Debug>(&self, key: K) -> EyreResult { + pub fn remove_user_secret + fmt::Debug>(&self, key: K) -> EyreResult { if is_browser() { let win = match window() { Some(w) => w, diff --git a/veilid-core/src/intf/wasm/system.rs b/veilid-core/src/intf/wasm/system.rs index 49b48c4d..656c3520 100644 --- a/veilid-core/src/intf/wasm/system.rs +++ b/veilid-core/src/intf/wasm/system.rs @@ -2,6 +2,7 @@ use super::*; //use js_sys::*; +#[expect(clippy::unused_async)] pub async fn get_outbound_relay_peer( _routing_domain: routing_table::RoutingDomain, ) -> Option> { @@ -34,14 +35,17 @@ pub async fn get_outbound_relay_peer( // } // } +#[expect(clippy::unused_async)] pub async fn txt_lookup>(_host: S) -> EyreResult> { bail!("wasm does not support txt lookup") } +#[expect(clippy::unused_async)] pub async fn ptr_lookup(_ip_addr: IpAddr) -> EyreResult { bail!("wasm does not support ptr lookup") } +#[must_use] pub fn env_variable_is_defined>(_s: S) -> bool { false } diff --git a/veilid-core/src/lib.rs b/veilid-core/src/lib.rs index e3af62e5..503264ee 100644 --- a/veilid-core/src/lib.rs +++ b/veilid-core/src/lib.rs @@ -22,9 +22,6 @@ //! * `default-wasm` - When building for the `wasm32` architecture, use this to enable `wasm-bindgen-futures` as the async runtime. //! -#![deny(clippy::all)] -#![allow(clippy::comparison_chain, clippy::upper_case_acronyms)] -#![deny(unused_must_use)] #![recursion_limit = "256"] cfg_if::cfg_if! { @@ -73,6 +70,16 @@ pub use veilid_tools as tools; /// The on-the-wire serialization format for Veilid RPC. pub mod veilid_capnp { + #![allow( + clippy::all, + clippy::must_use_candidate, + clippy::large_futures, + clippy::large_stack_arrays, + clippy::large_stack_frames, + clippy::large_types_passed_by_value, + clippy::unused_async, + clippy::ptr_cast_constness + )] include!("../proto/veilid_capnp.rs"); } @@ -80,11 +87,13 @@ pub mod veilid_capnp { pub mod tests; /// Return the cargo package version of veilid-core in string format. +#[must_use] pub fn veilid_version_string() -> String { env!("CARGO_PKG_VERSION").to_owned() } /// Return the cargo package version of veilid-core in tuple format. +#[must_use] pub fn veilid_version() -> (u32, u32, u32) { ( u32::from_str(env!("CARGO_PKG_VERSION_MAJOR")).unwrap(), diff --git a/veilid-core/src/logging/api_tracing_layer.rs b/veilid-core/src/logging/api_tracing_layer.rs index e45689de..8647ca20 100644 --- a/veilid-core/src/logging/api_tracing_layer.rs +++ b/veilid-core/src/logging/api_tracing_layer.rs @@ -20,6 +20,7 @@ struct ApiTracingLayerInner { /// with many copies of Veilid running. #[derive(Clone)] +#[must_use] pub struct ApiTracingLayer {} static API_LOGGER_INNER: Mutex> = Mutex::new(None); diff --git a/veilid-core/src/logging/fmt_strip_fields.rs b/veilid-core/src/logging/fmt_strip_fields.rs index 84076f9f..0c1f1de3 100644 --- a/veilid-core/src/logging/fmt_strip_fields.rs +++ b/veilid-core/src/logging/fmt_strip_fields.rs @@ -7,6 +7,7 @@ use tracing_subscriber::{ }, }; +#[must_use] pub struct FmtStripFields { /// The inner formatter that will be used to format fields fmt: DefaultFields, diff --git a/veilid-core/src/logging/veilid_layer_filter.rs b/veilid-core/src/logging/veilid_layer_filter.rs index f997e063..dbd9026f 100644 --- a/veilid-core/src/logging/veilid_layer_filter.rs +++ b/veilid-core/src/logging/veilid_layer_filter.rs @@ -11,6 +11,7 @@ struct VeilidLayerFilterInner { } #[derive(Clone)] +#[must_use] pub struct VeilidLayerFilter { inner: Arc>, } @@ -19,6 +20,7 @@ pub const VEILID_LOG_KEY_FIELD: &str = "__VEILID_LOG_KEY"; pub type VeilidLayerLogKeyFilter = Arc bool + Send + Sync>; impl VeilidLayerFilter { + #[must_use] pub fn make_veilid_log_key(program_name: &str, namespace: &str) -> &'static str { if namespace.is_empty() { program_name.to_static_str() @@ -66,6 +68,7 @@ impl VeilidLayerFilter { VeilidConfigLogLevel::from_tracing_level_filter(inner.max_level) } + #[must_use] pub fn ignore_list(&self) -> Vec { let inner = self.inner.read(); inner.ignore_list.clone() @@ -113,6 +116,7 @@ impl VeilidLayerFilter { true } + #[must_use] pub fn apply_ignore_change(ignore_list: &[String], target_change: String) -> Vec { let mut ignore_list = ignore_list.to_vec(); let target_change = target_change diff --git a/veilid-core/src/network_manager/connection_manager.rs b/veilid-core/src/network_manager/connection_manager.rs index 6e60df83..71eef5ab 100644 --- a/veilid-core/src/network_manager/connection_manager.rs +++ b/veilid-core/src/network_manager/connection_manager.rs @@ -131,7 +131,7 @@ impl ConnectionManager { self.arc.connection_inactivity_timeout_ms } - pub async fn startup(&self) -> EyreResult<()> { + pub fn startup(&self) -> EyreResult<()> { let guard = self.arc.startup_lock.startup()?; veilid_log!(self debug "startup connection manager"); @@ -158,7 +158,7 @@ impl ConnectionManager { } // Spawn the reconnection processor - self.arc.reconnection_processor.init().await; + self.arc.reconnection_processor.init(); guard.success(); @@ -696,7 +696,7 @@ impl ConnectionManager { ); } - pub async fn debug_print(&self) -> String { + pub fn debug_print(&self) -> String { //let inner = self.arc.inner.lock(); format!( "Connection Table:\n\n{}", diff --git a/veilid-core/src/network_manager/connection_table.rs b/veilid-core/src/network_manager/connection_table.rs index 57bda87f..c1ef484e 100644 --- a/veilid-core/src/network_manager/connection_table.rs +++ b/veilid-core/src/network_manager/connection_table.rs @@ -455,13 +455,16 @@ impl ConnectionTable { let conn = inner.conn_by_id[protocol_index].remove(&id).unwrap(); // id_by_flow let flow = conn.flow(); - inner.id_by_flow.remove(&flow).unwrap(); + let _ = inner + .id_by_flow + .remove(&flow) + .expect("must have removed something here"); // ids_by_remote let remote = flow.remote(); let ids = inner.ids_by_remote.get_mut(&remote).unwrap(); for (n, elem) in ids.iter().enumerate() { if *elem == id { - ids.remove(n); + let _ = ids.remove(n); if ids.is_empty() { inner.ids_by_remote.remove(&remote).unwrap(); } diff --git a/veilid-core/src/network_manager/direct_boot.rs b/veilid-core/src/network_manager/direct_boot.rs index c00f4ee4..e6c4aa9f 100644 --- a/veilid-core/src/network_manager/direct_boot.rs +++ b/veilid-core/src/network_manager/direct_boot.rs @@ -17,11 +17,8 @@ impl NetworkManager { let json_bytes = serialize_json(bootstrap_peerinfo).as_bytes().to_vec(); // Reply with a chunk of signed routing table - match self - .net() - .send_data_to_existing_flow(flow, json_bytes) - .await? - { + let net = self.net(); + match pin_future_closure!(net.send_data_to_existing_flow(flow, json_bytes)).await? { SendDataToExistingFlowResult::Sent(_) => { // Bootstrap reply was sent Ok(NetworkResult::value(())) diff --git a/veilid-core/src/network_manager/mod.rs b/veilid-core/src/network_manager/mod.rs index e8551852..1deba764 100644 --- a/veilid-core/src/network_manager/mod.rs +++ b/veilid-core/src/network_manager/mod.rs @@ -12,6 +12,7 @@ mod connection_manager; mod connection_table; mod direct_boot; mod network_connection; +mod node_contact_method_cache; mod receipt_manager; mod send_data; mod stats; @@ -25,6 +26,7 @@ pub mod tests; pub use connection_manager::*; pub use network_connection::*; +pub(crate) use node_contact_method_cache::*; pub use receipt_manager::*; pub use stats::*; pub(crate) use types::*; @@ -55,7 +57,6 @@ pub const MAX_MESSAGE_SIZE: usize = MAX_ENVELOPE_SIZE; pub const IPADDR_TABLE_SIZE: usize = 1024; pub const IPADDR_MAX_INACTIVE_DURATION_US: TimestampDuration = TimestampDuration::new(300_000_000u64); // 5 minutes -pub const NODE_CONTACT_METHOD_CACHE_SIZE: usize = 1024; pub const ADDRESS_FILTER_TASK_INTERVAL_SECS: u32 = 60; pub const BOOT_MAGIC: &[u8; 4] = b"BOOT"; pub const HOLE_PUNCH_DELAY_MS: u32 = 100; @@ -75,20 +76,32 @@ struct ClientAllowlistEntry { } #[derive(Clone, Debug)] -pub struct SendDataMethod { +pub struct SendDataResult { /// How the data was sent, possibly to a relay - pub contact_method: NodeContactMethod, - /// Pre-relayed contact method - pub opt_relayed_contact_method: Option, + opt_contact_method: Option, + /// Original contact method for the destination if it was relayed + opt_relayed_contact_method: Option, /// The specific flow used to send the data - pub unique_flow: UniqueFlow, + unique_flow: UniqueFlow, +} + +impl SendDataResult { + pub fn is_direct(&self) -> bool { + self.opt_relayed_contact_method.is_none() + && matches!( + &self.opt_contact_method, + Some(ncm) if ncm.is_direct() + ) + } + + pub fn unique_flow(&self) -> UniqueFlow { + self.unique_flow + } } /// Mechanism required to contact another node #[derive(Clone, Debug)] -pub enum NodeContactMethod { - /// Node is not reachable by any means - Unreachable, +pub enum NodeContactMethodKind { /// Connection should have already existed Existing, /// Contact the node directly @@ -102,14 +115,29 @@ pub enum NodeContactMethod { /// Must use outbound relay to reach the node OutboundRelay(FilteredNodeRef), } -#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] -struct NodeContactMethodCacheKey { - node_ids: TypedKeyGroup, - own_node_info_ts: Timestamp, - target_node_info_ts: Timestamp, - target_node_ref_filter: NodeRefFilter, - target_node_ref_sequencing: Sequencing, - dial_info_failures_map: BTreeMap, + +#[derive(Clone, Debug)] +pub struct NodeContactMethod { + ncm_key: NodeContactMethodCacheKey, + ncm_kind: NodeContactMethodKind, +} + +impl NodeContactMethod { + pub fn is_direct(&self) -> bool { + matches!(self.ncm_kind, NodeContactMethodKind::Direct(_)) + } + pub fn direct_dial_info(&self) -> Option { + match &self.ncm_kind { + NodeContactMethodKind::Direct(v) => Some(v.clone()), + _ => None, + } + } + // pub fn kind(&self) -> &NodeContactMethodKind { + // &self.ncm_kind + // } + // pub fn into_kind(self) -> NodeContactMethodKind { + // self.ncm_kind + // } } enum SendDataToExistingFlowResult { @@ -146,7 +174,7 @@ impl Default for NetworkManagerStartupContext { struct NetworkManagerInner { stats: NetworkManagerStats, client_allowlist: LruCache, - node_contact_method_cache: LruCache, + node_contact_method_cache: NodeContactMethodCache, address_check: Option, peer_info_change_subscription: Option, socket_address_change_subscription: Option, @@ -181,9 +209,6 @@ impl fmt::Debug for NetworkManager { //.field("registry", &self.registry) .field("inner", &self.inner) .field("address_filter", &self.address_filter) - // .field("components", &self.components) - // .field("rolling_transfers_task", &self.rolling_transfers_task) - // .field("address_filter_task", &self.address_filter_task) .field("network_key", &self.network_key) .field("startup_context", &self.startup_context) .finish() @@ -195,7 +220,7 @@ impl NetworkManager { NetworkManagerInner { stats: NetworkManagerStats::default(), client_allowlist: LruCache::new_unbounded(), - node_contact_method_cache: LruCache::new(NODE_CONTACT_METHOD_CACHE_SIZE), + node_contact_method_cache: NodeContactMethodCache::new(), address_check: None, peer_info_change_subscription: None, socket_address_change_subscription: None, @@ -300,10 +325,12 @@ impl NetworkManager { Ok(()) } + #[expect(clippy::unused_async)] async fn post_init_async(&self) -> EyreResult<()> { Ok(()) } + #[expect(clippy::unused_async)] async fn pre_terminate_async(&self) {} #[instrument(level = "debug", skip_all)] @@ -347,7 +374,7 @@ impl NetworkManager { } // Start network components - connection_manager.startup().await?; + connection_manager.startup()?; match net.startup().await? { StartupDisposition::Success => {} StartupDisposition::BindRetry => { @@ -355,7 +382,7 @@ impl NetworkManager { } } - receipt_manager.startup().await?; + receipt_manager.startup()?; veilid_log!(self trace "NetworkManager::internal_startup end"); @@ -823,7 +850,7 @@ impl NetworkManager { node_ref: FilteredNodeRef, destination_node_ref: Option, body: B, - ) -> EyreResult> { + ) -> EyreResult> { let Ok(_guard) = self.startup_context.startup_lock.enter() else { return Ok(NetworkResult::no_connection_other("network is not started")); }; @@ -890,7 +917,7 @@ impl NetworkManager { // Called when a packet potentially containing an RPC envelope is received by a low-level // network protocol handler. Processes the envelope, authenticates and decrypts the RPC message // and passes it to the RPC handler - #[instrument(level = "trace", target = "net", skip_all)] + //#[instrument(level = "trace", target = "net", skip_all)] async fn on_recv_envelope(&self, data: &mut [u8], flow: Flow) -> EyreResult { let Ok(_guard) = self.startup_context.startup_lock.enter() else { return Ok(false); @@ -931,13 +958,13 @@ impl NetworkManager { // Is this a direct bootstrap request instead of an envelope? if data[0..4] == *BOOT_MAGIC { - network_result_value_or_log!(self self.handle_boot_request(flow).await? => [ format!(": flow={:?}", flow) ] {}); + network_result_value_or_log!(self pin_future!(self.handle_boot_request(flow)).await? => [ format!(": flow={:?}", flow) ] {}); return Ok(true); } // Is this an out-of-band receipt instead of an envelope? if data[0..3] == *RECEIPT_MAGIC { - network_result_value_or_log!(self self.handle_out_of_band_receipt(data).await => [ format!(": data.len={}", data.len()) ] {}); + network_result_value_or_log!(self pin_future!(self.handle_out_of_band_receipt(data)).await => [ format!(": data.len={}", data.len()) ] {}); return Ok(true); } @@ -1071,18 +1098,9 @@ impl NetworkManager { // Relay the packet to the desired destination veilid_log!(self trace "relaying {} bytes to {}", data.len(), relay_nr); - - network_result_value_or_log!(self match self.send_data(relay_nr, data.to_vec()) - .await { - Ok(v) => v, - Err(e) => { - veilid_log!(self debug "failed to forward envelope: {}" ,e); - return Ok(false); - } - } => [ format!(": relay_nr={}, data.len={}", relay_nr, data.len()) ] { - return Ok(false); - } - ); + if let Err(e) = pin_future!(self.send_data(relay_nr, data.to_vec())).await { + veilid_log!(self debug "failed to relay envelope: {}" ,e); + } } // Inform caller that we dealt with the envelope, but did not process it locally return Ok(false); diff --git a/veilid-core/src/network_manager/native/discovery_context.rs b/veilid-core/src/network_manager/native/discovery_context.rs index bdadd399..b2b221ed 100644 --- a/veilid-core/src/network_manager/native/discovery_context.rs +++ b/veilid-core/src/network_manager/native/discovery_context.rs @@ -3,12 +3,15 @@ use super::*; use futures_util::stream::FuturesUnordered; use igd_manager::{IGDAddressType, IGDProtocolType}; +use stop_token::future::FutureExt as _; impl_veilid_log_facility!("net"); const PORT_MAP_VALIDATE_TRY_COUNT: usize = 3; const PORT_MAP_VALIDATE_DELAY_MS: u32 = 500; const PORT_MAP_TRY_COUNT: usize = 3; +const EXTERNAL_INFO_NODE_COUNT: usize = 20; +const EXTERNAL_INFO_CONCURRENCY: usize = 20; const EXTERNAL_INFO_VALIDATIONS: usize = 5; // Detection result of dial info detection futures @@ -26,6 +29,82 @@ pub struct DetectionResult { pub external_address_types: AddressTypeSet, } +#[derive(Clone, Debug)] +enum DetectionResultKind { + Result { + result: DetectionResult, + possibilities: Vec, + }, + Failure { + possibilities: Vec, + }, +} +//////////////////////////////////////////////////////////////////////////// + +type DialInfoClassPossibility = (DialInfoClass, usize); + +#[derive(Debug)] +struct DialInfoClassAllPossibilities { + remaining: BTreeMap, +} + +impl DialInfoClassAllPossibilities { + pub fn new() -> Self { + Self { + remaining: BTreeMap::new(), + } + } + + pub fn add(&mut self, possibilities: &[DialInfoClassPossibility]) { + for (k, v) in possibilities { + *self.remaining.entry(*k).or_default() += v; + } + } + pub fn remove(&mut self, possibilities: &[DialInfoClassPossibility]) { + for (k, v) in possibilities { + *self.remaining.entry(*k).or_default() -= v; + } + } + pub fn any_better(&mut self, dial_info_class: DialInfoClass) -> bool { + let best_available_order: [DialInfoClassSet; 4] = [ + DialInfoClass::Mapped.into(), + DialInfoClass::Direct | DialInfoClass::Blocked, + DialInfoClass::FullConeNAT.into(), + DialInfoClass::AddressRestrictedNAT | DialInfoClass::PortRestrictedNAT, + ]; + + for bestdicset in best_available_order { + // Already got the best we've checked so far? + if bestdicset.contains(dial_info_class) { + // We can just stop here since nothing else is going to be better + return false; + } + + // Get the total remaining possibilities left at this level + let mut remaining = 0usize; + for bestdic in bestdicset { + remaining += self.remaining.get(&bestdic).copied().unwrap_or_default() + } + + if remaining > 0 { + // There's some things worth waiting for that could be better than dial_info_class + return true; + } + } + + // Nothing left to wait for + false + } +} + +impl Default for DialInfoClassAllPossibilities { + fn default() -> Self { + Self::new() + } +} + +//////////////////////////////////////////////////////////////////////////// + #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct DiscoveryContextConfig { pub protocol_type: ProtocolType, @@ -57,6 +136,7 @@ pub(super) struct DiscoveryContext { registry: VeilidComponentRegistry, unlocked_inner: Arc, inner: Arc>, + stop_token: StopToken, } impl_veilid_component_registry_accessor!(DiscoveryContext); @@ -70,7 +150,11 @@ impl core::ops::Deref for DiscoveryContext { } impl DiscoveryContext { - pub fn new(registry: VeilidComponentRegistry, config: DiscoveryContextConfig) -> Self { + pub fn new( + registry: VeilidComponentRegistry, + config: DiscoveryContextConfig, + stop_token: StopToken, + ) -> Self { let routing_table = registry.routing_table(); let intf_addrs = Self::get_local_addresses(&routing_table, config.protocol_type, config.address_type); @@ -81,6 +165,7 @@ impl DiscoveryContext { inner: Arc::new(Mutex::new(DiscoveryContextInner { external_info: Vec::new(), })), + stop_token, } } @@ -147,9 +232,7 @@ impl DiscoveryContext { // This is done over the normal port using RPC #[instrument(level = "trace", skip(self), ret)] async fn discover_external_addresses(&self) -> bool { - let node_count = self - .config() - .with(|c| c.network.dht.max_find_node_count as usize); + let node_count = EXTERNAL_INFO_NODE_COUNT; let routing_domain = RoutingDomain::PublicInternet; let protocol_type = self.config.protocol_type; @@ -211,7 +294,6 @@ impl DiscoveryContext { } // For each peer, ask them for our public address, filtering on desired dial info - let get_public_address_func = |node: NodeRef| { let this = self.clone(); let node = node.custom_filtered( @@ -242,24 +324,55 @@ impl DiscoveryContext { unord.push(gpa_future); // Always process N at a time so we get all addresses in parallel if possible - if unord.len() == EXTERNAL_INFO_VALIDATIONS { + if unord.len() == EXTERNAL_INFO_CONCURRENCY { // Process one - if let Some(Some(ei)) = unord.next().in_current_span().await { - external_address_infos.push(ei); - if external_address_infos.len() == EXTERNAL_INFO_VALIDATIONS { - break; + match unord + .next() + .timeout_at(self.stop_token.clone()) + .in_current_span() + .await + { + Ok(Some(Some(ei))) => { + external_address_infos.push(ei); + if external_address_infos.len() == EXTERNAL_INFO_VALIDATIONS { + break; + } + } + Ok(Some(None)) => { + // Found no public address from this node + } + Ok(None) => { + // Should never happen in this loop + unreachable!(); + } + Err(_) => { + // stop requested + return false; } } } } // Finish whatever is left if we need to - if external_address_infos.len() < EXTERNAL_INFO_VALIDATIONS { - while let Some(res) = unord.next().in_current_span().await { - if let Some(ei) = res { + while external_address_infos.len() < EXTERNAL_INFO_VALIDATIONS { + match unord + .next() + .timeout_at(self.stop_token.clone()) + .in_current_span() + .await + { + Ok(Some(Some(ei))) => { external_address_infos.push(ei); - if external_address_infos.len() == EXTERNAL_INFO_VALIDATIONS { - break; - } + } + Ok(Some(None)) => { + // Found no public address from this node + } + Ok(None) => { + // No nodes left to wait for + break; + } + Err(_) => { + // stop requested + return false; } } } @@ -414,16 +527,21 @@ impl DiscoveryContext { // If we know we are not behind NAT, check our firewall status #[instrument(level = "trace", skip(self), ret)] - async fn protocol_process_no_nat( + fn protocol_process_no_nat( &self, - unord: &mut FuturesUnordered>>, + all_possibilities: &mut DialInfoClassAllPossibilities, + unord: &mut FuturesUnordered>, ) { let external_infos = self.inner.lock().external_info.clone(); // Have all the external validator nodes check us for external_info in external_infos { let this = self.clone(); - let do_no_nat_fut: SendPinBoxFuture> = Box::pin(async move { + + let possibilities = vec![(DialInfoClass::Direct, 1), (DialInfoClass::Blocked, 1)]; + all_possibilities.add(&possibilities); + + let do_no_nat_fut: PinBoxFutureStatic = Box::pin(async move { // Do a validate_dial_info on the external address from a redirected node if this .validate_dial_info( @@ -434,47 +552,55 @@ impl DiscoveryContext { .await { // Add public dial info with Direct dialinfo class - Some(DetectionResult { - config: this.config, - ddi: DetectedDialInfo::Detected(DialInfoDetail { - dial_info: external_info.dial_info.clone(), - class: DialInfoClass::Direct, - }), - external_address_types: AddressTypeSet::only( - external_info.address.address_type(), - ), - }) + DetectionResultKind::Result { + possibilities, + result: DetectionResult { + config: this.config, + ddi: DetectedDialInfo::Detected(DialInfoDetail { + dial_info: external_info.dial_info.clone(), + class: DialInfoClass::Direct, + }), + external_address_types: AddressTypeSet::only( + external_info.address.address_type(), + ), + }, + } } else { // Add public dial info with Blocked dialinfo class - Some(DetectionResult { - config: this.config, - ddi: DetectedDialInfo::Detected(DialInfoDetail { - dial_info: external_info.dial_info.clone(), - class: DialInfoClass::Blocked, - }), - external_address_types: AddressTypeSet::only( - external_info.address.address_type(), - ), - }) + DetectionResultKind::Result { + possibilities, + result: DetectionResult { + config: this.config, + ddi: DetectedDialInfo::Detected(DialInfoDetail { + dial_info: external_info.dial_info.clone(), + class: DialInfoClass::Blocked, + }), + external_address_types: AddressTypeSet::only( + external_info.address.address_type(), + ), + }, + } } }); + unord.push(do_no_nat_fut); } } // If we know we are behind NAT check what kind #[instrument(level = "trace", skip(self), ret)] - async fn protocol_process_nat( + fn protocol_process_nat( &self, - unord: &mut FuturesUnordered>>, + all_possibilities: &mut DialInfoClassAllPossibilities, + unord: &mut FuturesUnordered>, ) { + // Get the external dial info histogram for our use here let external_info = { let inner = self.inner.lock(); inner.external_info.clone() }; let local_port = self.config.port; - // Get the external dial info histogram for our use here let mut external_info_addr_port_hist = HashMap::::new(); let mut external_info_addr_hist = HashMap::::new(); for ei in &external_info { @@ -525,15 +651,21 @@ impl DiscoveryContext { // then we consider this a symmetric NAT if different_addresses || !same_address_has_popular_port { let this = self.clone(); - let do_symmetric_nat_fut: SendPinBoxFuture> = + let do_symmetric_nat_fut: PinBoxFutureStatic = Box::pin(async move { - Some(DetectionResult { - config: this.config, - ddi: DetectedDialInfo::SymmetricNAT, - external_address_types, - }) + DetectionResultKind::Result { + // Don't bother tracking possibilities for SymmetricNAT + // it's never going to be 'better than' anything else + possibilities: vec![], + result: DetectionResult { + config: this.config, + ddi: DetectedDialInfo::SymmetricNAT, + external_address_types, + }, + } }); unord.push(do_symmetric_nat_fut); + return; } @@ -545,23 +677,28 @@ impl DiscoveryContext { if local_port_matching_external_info.is_none() && best_external_info.is_some() { let c_external_1 = best_external_info.as_ref().unwrap().clone(); let c_this = this.clone(); - let do_manual_map_fut: SendPinBoxFuture> = - Box::pin(async move { - // Do a validate_dial_info on the external address, but with the same port as the local port of local interface, from a redirected node - // This test is to see if a node had manual port forwarding done with the same port number as the local listener - let mut external_1_dial_info_with_local_port = c_external_1.dial_info.clone(); - external_1_dial_info_with_local_port.set_port(local_port); - if this - .validate_dial_info( - c_external_1.node.clone(), - external_1_dial_info_with_local_port.clone(), - true, - ) - .await - { - // Add public dial info with Direct dialinfo class - return Some(DetectionResult { + let possibilities = vec![(DialInfoClass::Direct, 1)]; + all_possibilities.add(&possibilities); + + let do_manual_map_fut: PinBoxFutureStatic = Box::pin(async move { + // Do a validate_dial_info on the external address, but with the same port as the local port of local interface, from a redirected node + // This test is to see if a node had manual port forwarding done with the same port number as the local listener + let mut external_1_dial_info_with_local_port = c_external_1.dial_info.clone(); + external_1_dial_info_with_local_port.set_port(local_port); + + if this + .validate_dial_info( + c_external_1.node.clone(), + external_1_dial_info_with_local_port.clone(), + true, + ) + .await + { + // Add public dial info with Direct dialinfo class + return DetectionResultKind::Result { + possibilities, + result: DetectionResult { config: c_this.config, ddi: DetectedDialInfo::Detected(DialInfoDetail { dial_info: external_1_dial_info_with_local_port, @@ -570,80 +707,99 @@ impl DiscoveryContext { external_address_types: AddressTypeSet::only( c_external_1.address.address_type(), ), - }); - } + }, + }; + } - None - }); + DetectionResultKind::Failure { possibilities } + }); unord.push(do_manual_map_fut); } // NAT Detection /////////// + let retry_count = self.config().with(|c| c.network.restricted_nat_retries); + // Full Cone NAT Detection /////////// - let this = self.clone(); - let do_nat_detect_fut: SendPinBoxFuture> = Box::pin(async move { - let mut retry_count = this.config().with(|c| c.network.restricted_nat_retries); - // Loop for restricted NAT retries + let c_this = self.clone(); + let c_external_1 = external_info.first().cloned().unwrap(); + let possibilities = vec![(DialInfoClass::FullConeNAT, 1)]; + all_possibilities.add(&possibilities); + let do_full_cone_fut: PinBoxFutureStatic = Box::pin(async move { + let mut retry_count = retry_count; + + // Let's see what kind of NAT we have + // Does a redirected dial info validation from a different address and a random port find us? loop { - let mut ord = FuturesOrdered::new(); + if c_this + .validate_dial_info( + c_external_1.node.clone(), + c_external_1.dial_info.clone(), + true, + ) + .await + { + // Yes, another machine can use the dial info directly, so Full Cone + // Add public dial info with full cone NAT network class - let c_this = this.clone(); - let c_external_1 = external_info.first().cloned().unwrap(); - let do_full_cone_fut: SendPinBoxFuture> = - Box::pin(async move { - // Let's see what kind of NAT we have - // Does a redirected dial info validation from a different address and a random port find us? - if c_this - .validate_dial_info( - c_external_1.node.clone(), - c_external_1.dial_info.clone(), - true, - ) - .await - { - // Yes, another machine can use the dial info directly, so Full Cone - // Add public dial info with full cone NAT network class + return DetectionResultKind::Result { + possibilities, + result: DetectionResult { + config: c_this.config, + ddi: DetectedDialInfo::Detected(DialInfoDetail { + dial_info: c_external_1.dial_info, + class: DialInfoClass::FullConeNAT, + }), + external_address_types: AddressTypeSet::only( + c_external_1.address.address_type(), + ), + }, + }; + } + if retry_count == 0 { + break; + } + retry_count -= 1; + } - return Some(DetectionResult { - config: c_this.config, - ddi: DetectedDialInfo::Detected(DialInfoDetail { - dial_info: c_external_1.dial_info, - class: DialInfoClass::FullConeNAT, - }), - external_address_types: AddressTypeSet::only( - c_external_1.address.address_type(), - ), - }); - } - None - }); - ord.push_back(do_full_cone_fut); + DetectionResultKind::Failure { possibilities } + }); + unord.push(do_full_cone_fut); - let c_this = this.clone(); - let c_external_1 = external_info.first().cloned().unwrap(); - let c_external_2 = external_info.get(1).cloned().unwrap(); - let do_restricted_cone_fut: SendPinBoxFuture> = - Box::pin(async move { - // We are restricted, determine what kind of restriction + let c_this = self.clone(); + let c_external_1 = external_info.first().cloned().unwrap(); + let c_external_2 = external_info.get(1).cloned().unwrap(); + let possibilities = vec![ + (DialInfoClass::AddressRestrictedNAT, 1), + (DialInfoClass::PortRestrictedNAT, 1), + ]; + all_possibilities.add(&possibilities); + let do_restricted_cone_fut: PinBoxFutureStatic = + Box::pin(async move { + let mut retry_count = retry_count; - // If we're going to end up as a restricted NAT of some sort - // Address is the same, so it's address or port restricted + // We are restricted, determine what kind of restriction - // Do a validate_dial_info on the external address from a random port - if c_this - .validate_dial_info( - c_external_2.node.clone(), - c_external_1.dial_info.clone(), - false, - ) - .await - { - // Got a reply from a non-default port, which means we're only address restricted - return Some(DetectionResult { + // If we're going to end up as a restricted NAT of some sort + // Address is the same, so it's address or port restricted + + loop { + // Do a validate_dial_info on the external address from a random port + if c_this + .validate_dial_info( + c_external_2.node.clone(), + c_external_1.dial_info.clone(), + false, + ) + .await + { + // Got a reply from a non-default port, which means we're only address restricted + return DetectionResultKind::Result { + possibilities, + result: DetectionResult { config: c_this.config, ddi: DetectedDialInfo::Detected(DialInfoDetail { dial_info: c_external_1.dial_info.clone(), @@ -652,87 +808,85 @@ impl DiscoveryContext { external_address_types: AddressTypeSet::only( c_external_1.address.address_type(), ), - }); - } - // Didn't get a reply from a non-default port, which means we are also port restricted - Some(DetectionResult { - config: c_this.config, - ddi: DetectedDialInfo::Detected(DialInfoDetail { - dial_info: c_external_1.dial_info.clone(), - class: DialInfoClass::PortRestrictedNAT, - }), - external_address_types: AddressTypeSet::only( - c_external_1.address.address_type(), - ), - }) - }); - ord.push_back(do_restricted_cone_fut); + }, + }; + } - // Return the first result we get - let mut some_dr = None; - while let Some(res) = ord.next().await { - if let Some(dr) = res { - some_dr = Some(dr); + if retry_count == 0 { break; } + retry_count -= 1; } - if let Some(dr) = some_dr { - if let DetectedDialInfo::Detected(did) = &dr.ddi { - // If we got something better than restricted NAT or we're done retrying - if did.class < DialInfoClass::AddressRestrictedNAT || retry_count == 0 { - return Some(dr); - } - } + // Didn't get a reply from a non-default port, which means we are also port restricted + DetectionResultKind::Result { + possibilities, + result: DetectionResult { + config: c_this.config, + ddi: DetectedDialInfo::Detected(DialInfoDetail { + dial_info: c_external_1.dial_info.clone(), + class: DialInfoClass::PortRestrictedNAT, + }), + external_address_types: AddressTypeSet::only( + c_external_1.address.address_type(), + ), + }, } - if retry_count == 0 { - break; - } - retry_count -= 1; - } - - None - }); - unord.push(do_nat_detect_fut); + }); + unord.push(do_restricted_cone_fut); } - /// Add discovery futures to an unordered set that may detect dialinfo when they complete + /// Run a discovery for a particular context + /// Returns None if no detection was possible + /// Returns Some(DetectionResult) with the best detection result for this context #[instrument(level = "trace", skip(self))] - pub async fn discover( - &self, - unord: &mut FuturesUnordered>>, - ) { - let enable_upnp = self.config().with(|c| c.network.upnp); - + pub async fn discover(self) -> Option { // Do this right away because it's fast and every detection is going to need it - // Get our external addresses from two fast nodes + // Get our external addresses from a bunch of fast nodes if !self.discover_external_addresses().await { // If we couldn't get an external address, then we should just try the whole network class detection again later - return; + return None; } + // The set of futures we're going to wait on to determine dial info class for this context + let mut unord = FuturesUnordered::>::new(); + + // Used to determine what is still worth waiting for since we always want to return the + // best available dial info class. Once there are no better options in our waiting set + // we can just return what we've got. + let mut all_possibilities = DialInfoClassAllPossibilities::new(); + // UPNP Automatic Mapping /////////// + + let enable_upnp = self.config().with(|c| c.network.upnp); if enable_upnp { let this = self.clone(); - let do_mapped_fut: SendPinBoxFuture> = Box::pin(async move { + + let possibilities = vec![(DialInfoClass::Mapped, 1)]; + all_possibilities.add(&possibilities); + + let do_mapped_fut: PinBoxFutureStatic = Box::pin(async move { // Attempt a port mapping via all available and enabled mechanisms // Try this before the direct mapping in the event that we are restarting // and may not have recorded a mapping created the last time if let Some(external_mapped_dial_info) = this.try_upnp_port_mapping().await { // Got a port mapping, let's use it - return Some(DetectionResult { - config: this.config, - ddi: DetectedDialInfo::Detected(DialInfoDetail { - dial_info: external_mapped_dial_info.clone(), - class: DialInfoClass::Mapped, - }), - external_address_types: AddressTypeSet::only( - external_mapped_dial_info.address_type(), - ), - }); + return DetectionResultKind::Result { + possibilities, + result: DetectionResult { + config: this.config, + ddi: DetectedDialInfo::Detected(DialInfoDetail { + dial_info: external_mapped_dial_info.clone(), + class: DialInfoClass::Mapped, + }), + external_address_types: AddressTypeSet::only( + external_mapped_dial_info.address_type(), + ), + }, + }; } - None + DetectionResultKind::Failure { possibilities } }); unord.push(do_mapped_fut); } @@ -750,9 +904,84 @@ impl DiscoveryContext { .unwrap_or_default(); if local_address_in_external_info { - self.protocol_process_no_nat(unord).await; + self.protocol_process_no_nat(&mut all_possibilities, &mut unord); } else { - self.protocol_process_nat(unord).await; + self.protocol_process_nat(&mut all_possibilities, &mut unord); } + + // Wait for the best detection result to roll in + let mut opt_best_detection_result: Option = None; + loop { + match unord + .next() + .timeout_at(self.stop_token.clone()) + .in_current_span() + .await + { + Ok(Some(DetectionResultKind::Result { + result, + possibilities, + })) => { + // Remove possible dial info classes from our available set + all_possibilities.remove(&possibilities); + + // Get best detection result for each discovery context config + if let Some(best_detection_result) = &mut opt_best_detection_result { + let ddi = &mut best_detection_result.ddi; + // Upgrade existing dialinfo + match ddi { + DetectedDialInfo::SymmetricNAT => { + // Whatever we got is better than or equal to symmetric + *ddi = result.ddi; + } + DetectedDialInfo::Detected(cur_did) => match result.ddi { + DetectedDialInfo::SymmetricNAT => { + // Nothing is worse than this + } + DetectedDialInfo::Detected(did) => { + // Pick the best dial info class we detected + // because some nodes could be degenerate and if any node can validate a + // better dial info class we should go with it and leave the + // degenerate nodes in the dust to fade into obscurity + if did.class < cur_did.class { + cur_did.class = did.class; + } + } + }, + } + best_detection_result.external_address_types |= + result.external_address_types; + } else { + opt_best_detection_result = Some(result); + } + } + Ok(Some(DetectionResultKind::Failure { possibilities })) => { + // Found no dial info for this protocol/address combination + + // Remove possible dial info classes from our available set + all_possibilities.remove(&possibilities); + } + Ok(None) => { + // All done, normally + break; + } + Err(_) => { + // Stop token, exit early without error propagation + return None; + } + } + + // See if there's any better results worth waiting for + if let Some(best_detection_result) = &opt_best_detection_result { + if let DetectedDialInfo::Detected(did) = &best_detection_result.ddi { + // If nothing else is going to be a better result, just stop here + if !all_possibilities.any_better(did.class) { + break; + } + } + } + } + + opt_best_detection_result } } diff --git a/veilid-core/src/network_manager/native/mod.rs b/veilid-core/src/network_manager/native/mod.rs index 423f97d5..c3de6093 100644 --- a/veilid-core/src/network_manager/native/mod.rs +++ b/veilid-core/src/network_manager/native/mod.rs @@ -318,7 +318,7 @@ impl Network { .routing_table() .routing_domain_for_address(dial_info.address()); - let network_result = fut.await?; + let network_result = pin_future_closure!(fut).await?; if matches!(network_result, NetworkResult::NoConnection(_)) { // Dial info failure self.network_manager() diff --git a/veilid-core/src/network_manager/native/protocol/tcp.rs b/veilid-core/src/network_manager/native/protocol/tcp.rs index 7bf03368..bfb14f36 100644 --- a/veilid-core/src/network_manager/native/protocol/tcp.rs +++ b/veilid-core/src/network_manager/native/protocol/tcp.rs @@ -211,7 +211,7 @@ impl ProtocolAcceptHandler for RawTcpProtocolHandler { stream: AsyncPeekStream, peer_addr: SocketAddr, local_addr: SocketAddr, - ) -> SendPinBoxFuture>> { + ) -> PinBoxFutureStatic>> { Box::pin(self.clone().on_accept_async(stream, peer_addr, local_addr)) } } diff --git a/veilid-core/src/network_manager/native/protocol/ws.rs b/veilid-core/src/network_manager/native/protocol/ws.rs index 60869bc8..7253d45a 100644 --- a/veilid-core/src/network_manager/native/protocol/ws.rs +++ b/veilid-core/src/network_manager/native/protocol/ws.rs @@ -410,7 +410,7 @@ impl ProtocolAcceptHandler for WebsocketProtocolHandler { stream: AsyncPeekStream, peer_addr: SocketAddr, local_addr: SocketAddr, - ) -> SendPinBoxFuture>> { + ) -> PinBoxFutureStatic>> { Box::pin(self.clone().on_accept_async(stream, peer_addr, local_addr)) } } diff --git a/veilid-core/src/network_manager/native/tasks/network_interfaces_task.rs b/veilid-core/src/network_manager/native/tasks/network_interfaces_task.rs index 508e3869..c3c64df3 100644 --- a/veilid-core/src/network_manager/native/tasks/network_interfaces_task.rs +++ b/veilid-core/src/network_manager/native/tasks/network_interfaces_task.rs @@ -11,9 +11,9 @@ impl Network { // Network lock ensures only one task operating on the low level network state // can happen at the same time. Try lock is here to give preference to other longer // running processes like update_network_class_task. - let _guard = match self.network_task_lock.try_lock() { - Ok(v) => v, - Err(_) => { + let _guard = match asyncmutex_try_lock!(self.network_task_lock) { + Some(v) => v, + None => { // If we can't get the lock right now, then return Ok(()); } diff --git a/veilid-core/src/network_manager/native/tasks/update_network_class_task.rs b/veilid-core/src/network_manager/native/tasks/update_network_class_task.rs index b39669b9..e6d54a33 100644 --- a/veilid-core/src/network_manager/native/tasks/update_network_class_task.rs +++ b/veilid-core/src/network_manager/native/tasks/update_network_class_task.rs @@ -88,7 +88,7 @@ impl Network { &self, stop_token: StopToken, _l: Timestamp, - _t: Timestamp, + cur_ts: Timestamp, ) -> EyreResult { // Figure out if we can optimize TCP/WS checking since they are often on the same port let (protocol_config, inbound_protocol_map) = { @@ -153,8 +153,8 @@ impl Network { port, }; context_configs.insert(dcc); - let discovery_context = DiscoveryContext::new(self.registry(), dcc); - discovery_context.discover(&mut unord).await; + let discovery_context = DiscoveryContext::new(self.registry(), dcc, stop_token.clone()); + unord.push(discovery_context.discover()); } // Wait for all discovery futures to complete and apply discoverycontexts @@ -174,34 +174,8 @@ impl Network { // Add the external address kinds to the set we've seen external_address_types |= dr.external_address_types; - // Get best detection result for each discovery context config - if let Some(cur_dr) = detection_results.get_mut(&dr.config) { - let ddi = &mut cur_dr.ddi; - // Upgrade existing dialinfo - match ddi { - DetectedDialInfo::SymmetricNAT => { - // Whatever we got is better than or equal to symmetric - *ddi = dr.ddi; - } - DetectedDialInfo::Detected(cur_did) => match dr.ddi { - DetectedDialInfo::SymmetricNAT => { - // Nothing is worse than this - } - DetectedDialInfo::Detected(did) => { - // Pick the best dial info class we detected - // because some nodes could be degenerate and if any node can validate a - // better dial info class we should go with it and leave the - // degenerate nodes in the dust to fade into obscurity - if did.class < cur_did.class { - cur_did.class = did.class; - } - } - }, - } - cur_dr.external_address_types |= dr.external_address_types; - } else { - detection_results.insert(dr.config, dr); - } + // Save best detection result for each discovery context config + detection_results.insert(dr.config, dr); } Ok(Some(None)) => { // Found no dial info for this protocol/address combination @@ -223,9 +197,11 @@ impl Network { self.update_with_detection_result(&mut editor, &inbound_protocol_map, dr); } + let end_ts = Timestamp::now(); + // If we got no external address types, try again if external_address_types.is_empty() { - veilid_log!(self debug "Network class discovery failed, trying again, got no external address types"); + veilid_log!(self debug "Network class discovery failed in {}, trying again, got no external address types", end_ts - cur_ts); return Ok(false); } @@ -240,12 +216,12 @@ impl Network { } if !success { - veilid_log!(self debug "Network class discovery failed, trying again, needed {:?}", context_configs); + veilid_log!(self debug "Network class discovery failed in {}, trying again, needed {:?}", end_ts - cur_ts, context_configs); return Ok(false); } // All done - veilid_log!(self debug "Network class discovery finished with address_types {:?}", external_address_types); + veilid_log!(self debug "Network class discovery finished in {} with address_types {:?}", end_ts - cur_ts, external_address_types); // Set the address types we've seen and confirm the network class editor.setup_network( diff --git a/veilid-core/src/network_manager/network_connection.rs b/veilid-core/src/network_manager/network_connection.rs index 7caaf8ac..d52a43a2 100644 --- a/veilid-core/src/network_manager/network_connection.rs +++ b/veilid-core/src/network_manager/network_connection.rs @@ -17,7 +17,7 @@ cfg_if::cfg_if! { stream: AsyncPeekStream, peer_addr: SocketAddr, local_addr: SocketAddr, - ) -> SendPinBoxFuture>>; + ) -> PinBoxFutureStatic>>; } pub(crate) trait ProtocolAcceptHandlerClone { @@ -328,7 +328,7 @@ impl NetworkConnection { receiver: flume::Receiver<(Option, Vec)>, protocol_connection: ProtocolNetworkConnection, stats: Arc>, - ) -> SendPinBoxFuture<()> { + ) -> PinBoxFutureStatic<()> { Box::pin(async move { let registry = connection_manager.registry(); diff --git a/veilid-core/src/network_manager/node_contact_method_cache.rs b/veilid-core/src/network_manager/node_contact_method_cache.rs new file mode 100644 index 00000000..7017587a --- /dev/null +++ b/veilid-core/src/network_manager/node_contact_method_cache.rs @@ -0,0 +1,132 @@ +use super::*; + +pub const NODE_CONTACT_METHOD_CACHE_SIZE: usize = 1024; + +#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] +pub struct NodeContactMethodCacheKey { + pub node_ids: TypedKeyGroup, + pub own_node_info_ts: Timestamp, + pub target_node_info_ts: Timestamp, + pub target_node_ref_filter: NodeRefFilter, + pub target_node_ref_sequencing: Sequencing, + pub dial_info_failures_map: BTreeMap, +} + +#[derive(Copy, Clone, Default, Debug)] +pub struct HitMissStats { + pub hit: usize, + pub miss: usize, +} + +#[derive(Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] +enum ContactMethodKind { + Unreachable, + Existing, + Direct, + SignalReverse, + SignalHolePunch, + InboundRelay, + OutboundRelay, +} +impl From> for ContactMethodKind { + fn from(value: Option<&NodeContactMethodKind>) -> Self { + match value { + None => ContactMethodKind::Unreachable, + Some(NodeContactMethodKind::Existing) => ContactMethodKind::Existing, + Some(NodeContactMethodKind::Direct(_)) => ContactMethodKind::Direct, + Some(NodeContactMethodKind::SignalReverse(_, _)) => ContactMethodKind::SignalReverse, + Some(NodeContactMethodKind::SignalHolePunch(_, _)) => { + ContactMethodKind::SignalHolePunch + } + Some(NodeContactMethodKind::InboundRelay(_)) => ContactMethodKind::InboundRelay, + Some(NodeContactMethodKind::OutboundRelay(_)) => ContactMethodKind::OutboundRelay, + } + } +} + +impl HitMissStats { + pub fn percentage(&self) -> f32 { + (self.hit as f32 * 100.0f32) / ((self.hit + self.miss) as f32) + } +} + +impl fmt::Display for HitMissStats { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}/{} {:.2}%", + self.hit, + self.hit + self.miss, + self.percentage() + ) + } +} + +pub struct NodeContactMethodCache { + cache: LruCache, + + // Statistics for cache hits/misses + cache_stats: HitMissStats, + + // Recorded stats for contact method success + contact_method_kind_stats: HashMap, +} + +impl fmt::Debug for NodeContactMethodCache { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("NodeContactMethodCache") + //.field("cache", &self.cache) + .field("cache_stats", &self.cache_stats) + .field("contact_method_kind_stats", &self.contact_method_kind_stats) + .finish() + } +} + +impl NodeContactMethodCache { + pub fn new() -> Self { + Self { + cache: LruCache::new(NODE_CONTACT_METHOD_CACHE_SIZE), + cache_stats: HitMissStats::default(), + contact_method_kind_stats: HashMap::new(), + } + } + pub fn insert(&mut self, ncm_key: NodeContactMethodCacheKey, ncm_kind: NodeContactMethodKind) { + // Cache this + self.cache.insert(ncm_key, ncm_kind); + } + + pub fn get(&mut self, ncm_key: &NodeContactMethodCacheKey) -> Option { + if let Some(ncm_kind) = self.cache.get(ncm_key) { + self.cache_stats.hit += 1; + + return Some(ncm_kind.clone()); + } + // Record miss + self.cache_stats.miss += 1; + None + } + + pub fn record_contact_method_success(&mut self, ncm_kind: Option<&NodeContactMethodKind>) { + let cmk = ContactMethodKind::from(ncm_kind); + self.contact_method_kind_stats.entry(cmk).or_default().hit += 1; + } + pub fn record_contact_method_failure(&mut self, ncm_kind: Option<&NodeContactMethodKind>) { + let cmk = ContactMethodKind::from(ncm_kind); + self.contact_method_kind_stats.entry(cmk).or_default().miss += 1; + } + + pub fn debug(&self) -> String { + let mut out = format!( + "Cache size: {}\nCache hits: {}\nContact methods:\n", + self.cache.len(), + self.cache_stats + ); + let mut sorted_kinds: Vec<_> = self.contact_method_kind_stats.keys().collect(); + sorted_kinds.sort(); + for kind in sorted_kinds { + let kindstats = self.contact_method_kind_stats.get(kind).unwrap(); + out += &format!(" {:?}: {}\n", kind, kindstats); + } + out + } +} diff --git a/veilid-core/src/network_manager/receipt_manager.rs b/veilid-core/src/network_manager/receipt_manager.rs index 2e3048a6..d6a7adc5 100644 --- a/veilid-core/src/network_manager/receipt_manager.rs +++ b/veilid-core/src/network_manager/receipt_manager.rs @@ -38,7 +38,7 @@ pub trait ReceiptCallback: Send + 'static { receipt: Receipt, returns_so_far: u32, expected_returns: u32, - ) -> SendPinBoxFuture<()>; + ) -> PinBoxFutureStatic<()>; } impl ReceiptCallback for T where @@ -51,7 +51,7 @@ where receipt: Receipt, returns_so_far: u32, expected_returns: u32, - ) -> SendPinBoxFuture<()> { + ) -> PinBoxFutureStatic<()> { Box::pin(self(event, receipt, returns_so_far, expected_returns)) } } @@ -184,17 +184,12 @@ impl ReceiptManager { } } - pub async fn startup(&self) -> EyreResult<()> { + pub fn startup(&self) -> EyreResult<()> { let guard = self.unlocked_inner.startup_lock.startup()?; veilid_log!(self debug "startup receipt manager"); - // Retrieve config - { - // let config = self.core().config(); - // let c = config.get(); - let mut inner = self.inner.lock(); - inner.stop_source = Some(StopSource::new()); - } + let mut inner = self.inner.lock(); + inner.stop_source = Some(StopSource::new()); guard.success(); Ok(()) @@ -204,7 +199,7 @@ impl ReceiptManager { fn perform_callback( evt: ReceiptEvent, record_mut: &mut ReceiptRecord, - ) -> Option> { + ) -> Option> { match &mut record_mut.receipt_callback { ReceiptRecordCallbackType::Normal(callback) => Some(callback.call( evt, diff --git a/veilid-core/src/network_manager/send_data.rs b/veilid-core/src/network_manager/send_data.rs index 77a07fda..808633b5 100644 --- a/veilid-core/src/network_manager/send_data.rs +++ b/veilid-core/src/network_manager/send_data.rs @@ -1,12 +1,6 @@ use super::*; use stop_token::future::FutureExt as _; -// global debugging statistics for hole punch success -static HOLE_PUNCH_SUCCESS: AtomicUsize = AtomicUsize::new(0); -static HOLE_PUNCH_FAILURE: AtomicUsize = AtomicUsize::new(0); -static REVERSE_CONNECT_SUCCESS: AtomicUsize = AtomicUsize::new(0); -static REVERSE_CONNECT_FAILURE: AtomicUsize = AtomicUsize::new(0); - impl NetworkManager { /// Send raw data to a node /// @@ -20,141 +14,227 @@ impl NetworkManager { &self, destination_node_ref: FilteredNodeRef, data: Vec, - ) -> EyreResult> { + ) -> EyreResult> { // Get the best way to contact this node - let possibly_relayed_contact_method = + let mut opt_node_contact_method = self.get_node_contact_method(destination_node_ref.clone())?; - self.try_possibly_relayed_contact_method( - possibly_relayed_contact_method, - destination_node_ref, - data, - ) - .await + // Retry loop + loop { + // Boxed because calling rpc_call_signal() is recursive to send_data() + let nres = pin_future_closure!(self.try_node_contact_method( + opt_node_contact_method.clone(), + destination_node_ref.clone(), + data.clone(), + )) + .await?; + + match &nres { + NetworkResult::Timeout => { + // Record contact method failure statistics + self.inner + .lock() + .node_contact_method_cache + .record_contact_method_failure( + opt_node_contact_method.as_ref().map(|x| &x.ncm_kind), + ); + + // Timeouts may retry with a different method + match opt_node_contact_method { + Some(NodeContactMethod { + ncm_key, + ncm_kind: + NodeContactMethodKind::SignalReverse(relay_nr, _target_node_ref), + }) => { + // Try again with a different method + opt_node_contact_method = Some(NodeContactMethod { + ncm_key, + ncm_kind: NodeContactMethodKind::InboundRelay(relay_nr), + }); + continue; + } + Some(NodeContactMethod { + ncm_key, + ncm_kind: + NodeContactMethodKind::SignalHolePunch(relay_nr, _target_node_ref), + }) => { + // Try again with a different method + opt_node_contact_method = Some(NodeContactMethod { + ncm_key, + ncm_kind: NodeContactMethodKind::InboundRelay(relay_nr), + }); + continue; + } + _ => { + // Don't retry any other contact methods, and don't cache a timeout + break Ok(nres); + } + } + } + NetworkResult::ServiceUnavailable(_) + | NetworkResult::NoConnection(_) + | NetworkResult::AlreadyExists(_) + | NetworkResult::InvalidMessage(_) => { + // Record contact method failure statistics + self.inner + .lock() + .node_contact_method_cache + .record_contact_method_failure( + opt_node_contact_method.as_ref().map(|x| &x.ncm_kind), + ); + + // Other network results don't cache, just directly return the result + break Ok(nres); + } + NetworkResult::Value(v) => { + // Successful network result gets to cache the node contact method + if let Some(ncm) = &v.opt_contact_method { + // Cache the contact method + self.cache_node_contact_method(ncm.clone()); + } + if let Some(ncm) = &v.opt_relayed_contact_method { + // Cache the relayed contact method + self.cache_node_contact_method(ncm.clone()); + } + + // Record cache insertion as a success + self.inner + .lock() + .node_contact_method_cache + .record_contact_method_success( + v.opt_contact_method.as_ref().map(|x| &x.ncm_kind), + ); + // If relayed contact method was specified, then it wasn't unreachable + // (must have been relay type or it wouldnt be here, and if this is None + // then the contact method was not relayed) + if v.opt_relayed_contact_method.is_some() { + self.inner + .lock() + .node_contact_method_cache + .record_contact_method_success( + v.opt_relayed_contact_method.as_ref().map(|x| &x.ncm_kind), + ); + } + + break Ok(nres); + } + } + } } #[instrument(level = "trace", target = "net", skip_all)] - pub fn try_possibly_relayed_contact_method( + async fn try_node_contact_method( &self, - possibly_relayed_contact_method: NodeContactMethod, + opt_node_contact_method: Option, destination_node_ref: FilteredNodeRef, data: Vec, - ) -> SendPinBoxFuture>> { - let registry = self.registry(); - Box::pin( - async move { - let this = registry.network_manager(); + ) -> EyreResult> { + // If we need to relay, do it + let (opt_contact_method, target_node_ref, opt_relayed_contact_method) = + match opt_node_contact_method.clone().map(|x| x.ncm_kind) { + Some(NodeContactMethodKind::OutboundRelay(relay_nr)) + | Some(NodeContactMethodKind::InboundRelay(relay_nr)) => { + let opt_contact_method = self.get_node_contact_method(relay_nr.clone())?; + (opt_contact_method, relay_nr, opt_node_contact_method) + } + _ => (opt_node_contact_method, destination_node_ref.clone(), None), + }; - // If we need to relay, do it - let (contact_method, target_node_ref, opt_relayed_contact_method) = match possibly_relayed_contact_method.clone() { - NodeContactMethod::OutboundRelay(relay_nr) - | NodeContactMethod::InboundRelay(relay_nr) => { - let cm = this.get_node_contact_method(relay_nr.clone())?; - (cm, relay_nr, Some(possibly_relayed_contact_method)) - } - cm => (cm, destination_node_ref.clone(), None), - }; + #[cfg(feature = "verbose-tracing")] + veilid_log!(self debug + "ContactMethod: {:?} for {:?}", + opt_contact_method, destination_node_ref + ); - #[cfg(feature = "verbose-tracing")] - veilid_log!(self debug - "ContactMethod: {:?} for {:?}", - contact_method, destination_node_ref - ); - - // Try the contact method - let mut send_data_method = match contact_method { - NodeContactMethod::OutboundRelay(relay_nr) => { - // Relay loop or multiple relays - bail!( + // Try the contact method + let unique_flow = match &opt_contact_method { + None => { + // If a node is unreachable it may still have an existing inbound connection + // Try that, but don't cache anything + network_result_try!( + pin_future_closure!(self.send_data_ncm_existing(target_node_ref, data)).await? + ) + } + Some(NodeContactMethod { + ncm_key: _, + ncm_kind: NodeContactMethodKind::Existing, + }) => { + // The node must have an existing connection, for example connecting to your own + // relay is something that must always have a connection already + network_result_try!( + pin_future_closure!(self.send_data_ncm_existing(target_node_ref, data)).await? + ) + } + Some(NodeContactMethod { + ncm_key: _, + ncm_kind: NodeContactMethodKind::OutboundRelay(relay_nr), + }) => { + // Relay loop or multiple relays + bail!( "Outbound relay loop or multiple relays detected: destination {} resolved to target {} via extraneous relay {}", destination_node_ref, target_node_ref, relay_nr, ); - } - | NodeContactMethod::InboundRelay(relay_nr) => { - // Relay loop or multiple relays - bail!( + } + Some(NodeContactMethod { + ncm_key: _, + ncm_kind: NodeContactMethodKind::InboundRelay(relay_nr), + }) => { + // Relay loop or multiple relays + bail!( "Inbound relay loop or multiple relays detected: destination {} resolved to target {} via extraneous relay {}", destination_node_ref, target_node_ref, relay_nr, ); - } - NodeContactMethod::Direct(dial_info) => { - network_result_try!( - this.send_data_ncm_direct(target_node_ref, dial_info, data).await? - ) - } - NodeContactMethod::SignalReverse(relay_nr, target_node_ref) => { - let nres = - this.send_data_ncm_signal_reverse(relay_nr.clone(), target_node_ref.clone(), data.clone()) - .await?; - if matches!(nres, NetworkResult::Timeout) { - // Failed to reverse-connect, fallback to inbound relay - let success = REVERSE_CONNECT_SUCCESS.load(Ordering::Acquire); - let failure = REVERSE_CONNECT_FAILURE.fetch_add(1, Ordering::AcqRel) + 1; - let rate = (success as f64 * 100.0) / ((success + failure) as f64); - - veilid_log!(this debug target:"network_result", "Reverse connection failed ({:.2}% success) to {}, falling back to inbound relay via {}", rate, target_node_ref, relay_nr); - network_result_try!(this.try_possibly_relayed_contact_method(NodeContactMethod::InboundRelay(relay_nr), destination_node_ref, data).await?) - } else { - if let NetworkResult::Value(sdm) = &nres { - if matches!(sdm.contact_method, NodeContactMethod::SignalReverse(_,_)) { - - let success = REVERSE_CONNECT_SUCCESS.fetch_add(1, Ordering::AcqRel) + 1; - let failure = REVERSE_CONNECT_FAILURE.load(Ordering::Acquire); - let rate = (success as f64 * 100.0) / ((success + failure) as f64); - - veilid_log!(this debug target:"network_result", "Reverse connection successful ({:.2}% success) to {} via {}", rate, target_node_ref, relay_nr); - } - } - network_result_try!(nres) - } - } - NodeContactMethod::SignalHolePunch(relay_nr, target_node_ref) => { - let nres = - this.send_data_ncm_signal_hole_punch(relay_nr.clone(), target_node_ref.clone(), data.clone()) - .await?; - if matches!(nres, NetworkResult::Timeout) { - // Failed to holepunch, fallback to inbound relay - let success = HOLE_PUNCH_SUCCESS.load(Ordering::Acquire); - let failure = HOLE_PUNCH_FAILURE.fetch_add(1, Ordering::AcqRel) + 1; - let rate = (success as f64 * 100.0) / ((success + failure) as f64); - - veilid_log!(this debug target:"network_result", "Hole punch failed ({:.2}% success) to {} , falling back to inbound relay via {}", rate, target_node_ref , relay_nr); - network_result_try!(this.try_possibly_relayed_contact_method(NodeContactMethod::InboundRelay(relay_nr), destination_node_ref, data).await?) - } else { - if let NetworkResult::Value(sdm) = &nres { - if matches!(sdm.contact_method, NodeContactMethod::SignalHolePunch(_,_)) { - let success = HOLE_PUNCH_SUCCESS.fetch_add(1, Ordering::AcqRel) + 1; - let failure = HOLE_PUNCH_FAILURE.load(Ordering::Acquire); - let rate = (success as f64 * 100.0) / ((success + failure) as f64); - - veilid_log!(this debug target:"network_result", "Hole punch successful ({:.2}% success) to {} via {}", rate, target_node_ref, relay_nr); - } - } - network_result_try!(nres) - } - } - NodeContactMethod::Existing => { - network_result_try!( - this.send_data_ncm_existing(target_node_ref, data).await? - ) - } - NodeContactMethod::Unreachable => { - network_result_try!( - this.send_data_ncm_unreachable(target_node_ref, data) - .await? - ) - } - }; - send_data_method.opt_relayed_contact_method = opt_relayed_contact_method; - - Ok(NetworkResult::value(send_data_method)) } - .in_current_span() - ) + Some(NodeContactMethod { + ncm_key: _, + ncm_kind: NodeContactMethodKind::Direct(dial_info), + }) => { + network_result_try!( + pin_future_closure!(self.send_data_ncm_direct( + target_node_ref, + dial_info.clone(), + data + )) + .await? + ) + } + Some(NodeContactMethod { + ncm_key: _, + ncm_kind: NodeContactMethodKind::SignalReverse(relay_nr, target_node_ref), + }) => { + network_result_try!( + pin_future_closure!(self.send_data_ncm_signal_reverse( + relay_nr.clone(), + target_node_ref.clone(), + data.clone() + )) + .await? + ) + } + Some(NodeContactMethod { + ncm_key: _, + ncm_kind: NodeContactMethodKind::SignalHolePunch(relay_nr, target_node_ref), + }) => { + network_result_try!( + pin_future_closure!(self.send_data_ncm_signal_hole_punch( + relay_nr.clone(), + target_node_ref.clone(), + data.clone() + )) + .await? + ) + } + }; + + Ok(NetworkResult::value(SendDataResult { + opt_contact_method, + opt_relayed_contact_method, + unique_flow, + })) } /// Send data using NodeContactMethod::Existing @@ -163,7 +243,7 @@ impl NetworkManager { &self, target_node_ref: FilteredNodeRef, data: Vec, - ) -> EyreResult> { + ) -> EyreResult> { // First try to send data to the last connection we've seen this peer on let Some(flow) = target_node_ref.last_flow() else { return Ok(NetworkResult::no_connection_other(format!( @@ -172,7 +252,8 @@ impl NetworkManager { ))); }; - let unique_flow = match self.net().send_data_to_existing_flow(flow, data).await? { + let net = self.net(); + let unique_flow = match pin_future!(net.send_data_to_existing_flow(flow, data)).await? { SendDataToExistingFlowResult::Sent(unique_flow) => unique_flow, SendDataToExistingFlowResult::NotSent(_) => { return Ok(NetworkResult::no_connection_other( @@ -184,46 +265,7 @@ impl NetworkManager { // Update timestamp for this last connection since we just sent to it self.set_last_flow(target_node_ref.unfiltered(), flow, Timestamp::now()); - Ok(NetworkResult::value(SendDataMethod { - contact_method: NodeContactMethod::Existing, - opt_relayed_contact_method: None, - unique_flow, - })) - } - - /// Send data using NodeContactMethod::Unreachable - #[instrument(level = "trace", target = "net", skip_all, err)] - async fn send_data_ncm_unreachable( - &self, - target_node_ref: FilteredNodeRef, - data: Vec, - ) -> EyreResult> { - // Try to send data to the last flow we've seen this peer on - let Some(flow) = target_node_ref.last_flow() else { - return Ok(NetworkResult::no_connection_other(format!( - "Node is not reachable and has no existing connection: {}", - target_node_ref - ))); - }; - - let unique_flow = match self.net().send_data_to_existing_flow(flow, data).await? { - SendDataToExistingFlowResult::Sent(unique_flow) => unique_flow, - SendDataToExistingFlowResult::NotSent(_) => { - return Ok(NetworkResult::no_connection_other(format!( - "failed to send to unreachable node over existing connection: {:?}", - flow - ))); - } - }; - - // Update timestamp for this last connection since we just sent to it - self.set_last_flow(target_node_ref.unfiltered(), flow, Timestamp::now()); - - Ok(NetworkResult::value(SendDataMethod { - contact_method: NodeContactMethod::Existing, - opt_relayed_contact_method: None, - unique_flow, - })) + Ok(NetworkResult::value(unique_flow)) } /// Send data using NodeContactMethod::SignalReverse @@ -233,7 +275,7 @@ impl NetworkManager { relay_nr: FilteredNodeRef, target_node_ref: FilteredNodeRef, data: Vec, - ) -> EyreResult> { + ) -> EyreResult> { // Make a noderef that meets the sequencing requirements // But is not protocol-specific, or address-family-specific // as a signalled node gets to choose its own dial info for the reverse connection. @@ -252,16 +294,13 @@ impl NetworkManager { // First try to send data to the last flow we've seen this peer on let data = if let Some(flow) = seq_target_node_ref.last_flow() { - match self.net().send_data_to_existing_flow(flow, data).await? { + let net = self.net(); + match pin_future!(net.send_data_to_existing_flow(flow, data)).await? { SendDataToExistingFlowResult::Sent(unique_flow) => { // Update timestamp for this last connection since we just sent to it self.set_last_flow(target_node_ref.unfiltered(), flow, Timestamp::now()); - return Ok(NetworkResult::value(SendDataMethod { - contact_method: NodeContactMethod::Existing, - opt_relayed_contact_method: None, - unique_flow, - })); + return Ok(NetworkResult::value(unique_flow)); } SendDataToExistingFlowResult::NotSent(data) => { // Couldn't send data to existing connection @@ -281,14 +320,10 @@ impl NetworkManager { }; let unique_flow = network_result_try!( - self.do_reverse_connect(relay_nr.clone(), target_node_ref.clone(), data) + pin_future!(self.do_reverse_connect(relay_nr.clone(), target_node_ref.clone(), data)) .await? ); - Ok(NetworkResult::value(SendDataMethod { - contact_method: NodeContactMethod::SignalReverse(relay_nr, target_node_ref), - opt_relayed_contact_method: None, - unique_flow, - })) + Ok(NetworkResult::value(unique_flow)) } /// Send data using NodeContactMethod::SignalHolePunch @@ -298,19 +333,16 @@ impl NetworkManager { relay_nr: FilteredNodeRef, target_node_ref: FilteredNodeRef, data: Vec, - ) -> EyreResult> { + ) -> EyreResult> { // First try to send data to the last flow we've seen this peer on let data = if let Some(flow) = target_node_ref.last_flow() { - match self.net().send_data_to_existing_flow(flow, data).await? { + let net = self.net(); + match pin_future!(net.send_data_to_existing_flow(flow, data)).await? { SendDataToExistingFlowResult::Sent(unique_flow) => { // Update timestamp for this last connection since we just sent to it self.set_last_flow(target_node_ref.unfiltered(), flow, Timestamp::now()); - return Ok(NetworkResult::value(SendDataMethod { - contact_method: NodeContactMethod::Existing, - opt_relayed_contact_method: None, - unique_flow, - })); + return Ok(NetworkResult::value(unique_flow)); } SendDataToExistingFlowResult::NotSent(data) => { // Couldn't send data to existing connection @@ -330,14 +362,11 @@ impl NetworkManager { }; let unique_flow = network_result_try!( - self.do_hole_punch(relay_nr.clone(), target_node_ref.clone(), data) + pin_future!(self.do_hole_punch(relay_nr.clone(), target_node_ref.clone(), data)) .await? ); - Ok(NetworkResult::value(SendDataMethod { - contact_method: NodeContactMethod::SignalHolePunch(relay_nr, target_node_ref), - opt_relayed_contact_method: None, - unique_flow, - })) + + Ok(NetworkResult::value(unique_flow)) } /// Send data using NodeContactMethod::Direct @@ -347,7 +376,7 @@ impl NetworkManager { node_ref: FilteredNodeRef, dial_info: DialInfo, data: Vec, - ) -> EyreResult> { + ) -> EyreResult> { // Since we have the best dial info already, we can find a connection to use by protocol type let node_ref = node_ref.filtered_clone(NodeRefFilter::from(dial_info.make_filter())); @@ -359,16 +388,13 @@ impl NetworkManager { flow, node_ref ); - match self.net().send_data_to_existing_flow(flow, data).await? { + let net = self.net(); + match pin_future!(net.send_data_to_existing_flow(flow, data)).await? { SendDataToExistingFlowResult::Sent(unique_flow) => { // Update timestamp for this last connection since we just sent to it self.set_last_flow(node_ref.unfiltered(), flow, Timestamp::now()); - return Ok(NetworkResult::value(SendDataMethod { - contact_method: NodeContactMethod::Existing, - opt_relayed_contact_method: None, - unique_flow, - })); + return Ok(NetworkResult::value(unique_flow)); } SendDataToExistingFlowResult::NotSent(d) => { // Connection couldn't send, kill it @@ -381,27 +407,22 @@ impl NetworkManager { }; // New direct connection was necessary for this dial info + let net = self.net(); let unique_flow = network_result_try!( - self.net() - .send_data_to_dial_info(dial_info.clone(), data) - .await? + pin_future!(net.send_data_to_dial_info(dial_info.clone(), data)).await? ); // If we connected to this node directly, save off the last connection so we can use it again self.set_last_flow(node_ref.unfiltered(), unique_flow.flow, Timestamp::now()); - Ok(NetworkResult::value(SendDataMethod { - contact_method: NodeContactMethod::Direct(dial_info), - opt_relayed_contact_method: None, - unique_flow, - })) + Ok(NetworkResult::value(unique_flow)) } - #[instrument(level = "trace", target = "net", skip_all, err)] + #[instrument(level = "trace", target = "net", skip(self), err)] pub fn get_node_contact_method( &self, target_node_ref: FilteredNodeRef, - ) -> EyreResult { + ) -> EyreResult> { let routing_table = self.routing_table(); // If a node is punished, then don't try to contact it @@ -410,7 +431,7 @@ impl NetworkManager { .iter() .any(|nid| self.address_filter().is_node_id_punished(*nid)) { - return Ok(NodeContactMethod::Unreachable); + return Ok(None); } // Figure out the best routing domain to get the contact method over @@ -418,7 +439,7 @@ impl NetworkManager { Some(rd) => rd, None => { veilid_log!(self trace "no routing domain for node {:?}", target_node_ref); - return Ok(NodeContactMethod::Unreachable); + return Ok(None); } }; @@ -430,7 +451,7 @@ impl NetworkManager { // Peer B is the target node, get the whole peer info now let Some(peer_b) = target_node_ref.get_peer_info(routing_domain) else { veilid_log!(self trace "no node info for node {:?}", target_node_ref); - return Ok(NodeContactMethod::Unreachable); + return Ok(None); }; // Calculate the dial info failures map @@ -458,42 +479,47 @@ impl NetworkManager { target_node_ref_sequencing: target_node_ref.sequencing(), dial_info_failures_map, }; - if let Some(ncm) = self.inner.lock().node_contact_method_cache.get(&ncm_key) { - return Ok(ncm.clone()); + if let Some(ncm_kind) = self.inner.lock().node_contact_method_cache.get(&ncm_key) { + return Ok(Some(NodeContactMethod { ncm_key, ncm_kind })); } // Calculate the node contact method let routing_table = self.routing_table(); - let ncm = Self::get_node_contact_method_uncached( + let Some(ncm_kind) = Self::get_node_contact_method_kind( &routing_table, routing_domain, target_node_ref, peer_a, peer_b, &ncm_key, - )?; + )? + else { + return Ok(None); + }; + Ok(Some(NodeContactMethod { ncm_key, ncm_kind })) + } + + fn cache_node_contact_method(&self, ncm: NodeContactMethod) { // Cache this self.inner .lock() .node_contact_method_cache - .insert(ncm_key, ncm.clone()); - - Ok(ncm) + .insert(ncm.ncm_key, ncm.ncm_kind); } /// Figure out how to reach a node from our own node over the best routing domain and reference the nodes we want to access /// Uses NodeRefs to ensure nodes are referenced, this is not a part of 'RoutingTable' because RoutingTable is not /// allowed to use NodeRefs due to recursive locking #[instrument(level = "trace", target = "net", skip_all, err)] - fn get_node_contact_method_uncached( + fn get_node_contact_method_kind( routing_table: &RoutingTable, routing_domain: RoutingDomain, target_node_ref: FilteredNodeRef, peer_a: Arc, peer_b: Arc, ncm_key: &NodeContactMethodCacheKey, - ) -> EyreResult { + ) -> EyreResult> { // Dial info filter comes from the target node ref but must be filtered by this node's outbound capabilities let dial_info_filter = target_node_ref.dial_info_filter().filtered( DialInfoFilter::all() @@ -542,9 +568,9 @@ impl NetworkManager { // Translate the raw contact method to a referenced contact method let ncm = match cm { - ContactMethod::Unreachable => NodeContactMethod::Unreachable, - ContactMethod::Existing => NodeContactMethod::Existing, - ContactMethod::Direct(di) => NodeContactMethod::Direct(di), + ContactMethod::Unreachable => None, + ContactMethod::Existing => Some(NodeContactMethodKind::Existing), + ContactMethod::Direct(di) => Some(NodeContactMethodKind::Direct(di)), ContactMethod::SignalReverse(relay_key, target_key) => { let mut relay_nr = routing_table .lookup_and_filter_noderef(relay_key, routing_domain.into(), dial_info_filter)? @@ -595,7 +621,10 @@ impl NetworkManager { if tighten { target_node_ref.set_sequencing(Sequencing::EnsureOrdered); } - NodeContactMethod::SignalReverse(relay_nr, target_node_ref) + Some(NodeContactMethodKind::SignalReverse( + relay_nr, + target_node_ref, + )) } ContactMethod::SignalHolePunch(relay_key, target_key) => { let mut relay_nr = routing_table @@ -622,7 +651,10 @@ impl NetworkManager { .with_protocol_type(ProtocolType::UDP), ); - NodeContactMethod::SignalHolePunch(relay_nr, udp_target_node_ref) + Some(NodeContactMethodKind::SignalHolePunch( + relay_nr, + udp_target_node_ref, + )) } ContactMethod::InboundRelay(relay_key) => { let mut relay_nr = routing_table @@ -635,7 +667,7 @@ impl NetworkManager { ) })?; relay_nr.set_sequencing(sequencing); - NodeContactMethod::InboundRelay(relay_nr) + Some(NodeContactMethodKind::InboundRelay(relay_nr)) } ContactMethod::OutboundRelay(relay_key) => { let mut relay_nr = routing_table @@ -648,7 +680,7 @@ impl NetworkManager { ) })?; relay_nr.set_sequencing(sequencing); - NodeContactMethod::OutboundRelay(relay_nr) + Some(NodeContactMethodKind::OutboundRelay(relay_nr)) } }; @@ -695,16 +727,15 @@ impl NetworkManager { // Issue the signal let rpc = self.rpc_processor(); - network_result_try!(rpc - .rpc_call_signal( - Destination::relay(relay_nr.clone(), target_nr.unfiltered()), - SignalInfo::ReverseConnect { - receipt, - peer_info: published_peer_info - }, - ) - .await - .wrap_err("failed to send signal")?); + network_result_try!(pin_future!(rpc.rpc_call_signal( + Destination::relay(relay_nr.clone(), target_nr.unfiltered()), + SignalInfo::ReverseConnect { + receipt, + peer_info: published_peer_info + }, + )) + .await + .wrap_err("failed to send signal")?); // Wait for the return receipt let inbound_nr = match eventual_value @@ -747,7 +778,8 @@ impl NetworkManager { // And now use the existing connection to send over if let Some(flow) = inbound_nr.last_flow() { - match self.net().send_data_to_existing_flow(flow, data).await? { + let net = self.net(); + match pin_future!(net.send_data_to_existing_flow(flow, data)).await? { SendDataToExistingFlowResult::Sent(unique_flow) => { Ok(NetworkResult::value(unique_flow)) } @@ -817,9 +849,9 @@ impl NetworkManager { // Both sides will do this and then the receipt will get sent over the punched hole // Don't bother storing the returned flow as the 'last flow' because the other side of the hole // punch should come through and create a real 'last connection' for us if this succeeds + let net = self.net(); network_result_try!( - self.net() - .send_data_to_dial_info(hole_punch_did.dial_info.clone(), Vec::new()) + pin_future!(net.send_data_to_dial_info(hole_punch_did.dial_info.clone(), Vec::new())) .await? ); @@ -828,22 +860,20 @@ impl NetworkManager { // Issue the signal let rpc = self.rpc_processor(); - network_result_try!(rpc - .rpc_call_signal( - Destination::relay(relay_nr, target_nr.unfiltered()), - SignalInfo::HolePunch { - receipt, - peer_info: published_peer_info - }, - ) - .await - .wrap_err("failed to send signal")?); + network_result_try!(pin_future!(rpc.rpc_call_signal( + Destination::relay(relay_nr, target_nr.unfiltered()), + SignalInfo::HolePunch { + receipt, + peer_info: published_peer_info + }, + )) + .await + .wrap_err("failed to send signal")?); // Another hole punch after the signal for UDP redundancy + let net = self.net(); network_result_try!( - self.net() - .send_data_to_dial_info(hole_punch_did.dial_info, Vec::new()) - .await? + pin_future!(net.send_data_to_dial_info(hole_punch_did.dial_info, Vec::new())).await? ); // Wait for the return receipt diff --git a/veilid-core/src/network_manager/stats.rs b/veilid-core/src/network_manager/stats.rs index ac91a41f..0e897968 100644 --- a/veilid-core/src/network_manager/stats.rs +++ b/veilid-core/src/network_manager/stats.rs @@ -69,12 +69,28 @@ impl NetworkManager { .add_down(bytes); } - #[expect(dead_code)] pub fn get_stats(&self) -> NetworkManagerStats { let inner = self.inner.lock(); inner.stats.clone() } + pub fn debug(&self) -> String { + let stats = self.get_stats(); + + let mut out = String::new(); + out += "Network Manager\n"; + out += "---------------\n"; + let mut out = format!( + "Transfer stats:\n{}\n", + indent_all_string(&stats.self_stats.transfer_stats) + ); + out += "Node Contact Method Cache\n"; + out += "-------------------------\n"; + out += &self.inner.lock().node_contact_method_cache.debug(); + + out + } + pub fn get_veilid_state(&self) -> Box { if !self.network_is_started() { return Box::new(VeilidStateNetwork { diff --git a/veilid-core/src/network_manager/tests/test_signed_node_info.rs b/veilid-core/src/network_manager/tests/test_signed_node_info.rs index b9f2d255..43ad1081 100644 --- a/veilid-core/src/network_manager/tests/test_signed_node_info.rs +++ b/veilid-core/src/network_manager/tests/test_signed_node_info.rs @@ -54,7 +54,7 @@ pub async fn test_signed_node_info() { sni.timestamp(), sni.signatures().to_vec(), ); - sdni.validate(&tks1, &crypto).unwrap_err(); + let _ = sdni.validate(&tks1, &crypto).unwrap_err(); // Test unsupported cryptosystem validation let fake_crypto_kind: CryptoKind = FourCC::from([0, 1, 2, 3]); @@ -119,7 +119,7 @@ pub async fn test_signed_node_info() { sni2.timestamp(), sni2.signatures().to_vec(), ); - srni.validate(&tks3, &crypto).unwrap_err(); + assert_err!(srni.validate(&tks3, &crypto)); // Test unsupported cryptosystem validation let fake_crypto_kind: CryptoKind = FourCC::from([0, 1, 2, 3]); diff --git a/veilid-core/src/network_manager/types/dial_info_class.rs b/veilid-core/src/network_manager/types/dial_info_class.rs index 87bd9b51..ec85a1e5 100644 --- a/veilid-core/src/network_manager/types/dial_info_class.rs +++ b/veilid-core/src/network_manager/types/dial_info_class.rs @@ -1,7 +1,7 @@ use super::*; // Keep member order appropriate for sorting < preference -#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +#[derive(Debug, Ord, PartialOrd, Hash, Serialize, Deserialize, EnumSetType)] pub(crate) enum DialInfoClass { Direct = 0, // D = Directly reachable with public IP and no firewall, with statically configured port Mapped = 1, // M = Directly reachable with via portmap behind any NAT or firewalled with dynamically negotiated port @@ -33,3 +33,6 @@ impl DialInfoClass { ) } } + +#[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), expect(dead_code))] +pub(crate) type DialInfoClassSet = EnumSet; diff --git a/veilid-core/src/network_manager/wasm/mod.rs b/veilid-core/src/network_manager/wasm/mod.rs index ebd173a4..986a0582 100644 --- a/veilid-core/src/network_manager/wasm/mod.rs +++ b/veilid-core/src/network_manager/wasm/mod.rs @@ -516,5 +516,6 @@ impl Network { Ok(()) } + #[expect(clippy::unused_async)] pub async fn cancel_tasks(&self) {} } diff --git a/veilid-core/src/routing_table/mod.rs b/veilid-core/src/routing_table/mod.rs index a27814b9..43c58db7 100644 --- a/veilid-core/src/routing_table/mod.rs +++ b/veilid-core/src/routing_table/mod.rs @@ -60,6 +60,7 @@ const CACHE_VALIDITY_KEY: &[u8] = b"cache_validity_key"; type LowLevelProtocolPorts = BTreeSet<(LowLevelProtocolType, AddressType, u16)>; type ProtocolToPortMapping = BTreeMap<(ProtocolType, AddressType), (LowLevelProtocolType, u16)>; #[derive(Clone, Debug)] +#[must_use] pub struct LowLevelPortInfo { pub low_level_protocol_ports: LowLevelProtocolPorts, pub protocol_to_port: ProtocolToPortMapping, @@ -71,6 +72,7 @@ type SerializedBuckets = Vec>; type SerializedBucketMap = BTreeMap; #[derive(Clone, Debug, Default, Eq, PartialEq)] +#[must_use] pub struct RoutingTableHealth { /// Number of reliable (long-term responsive) entries in the routing table pub reliable_entry_count: usize, @@ -89,10 +91,12 @@ pub struct RoutingTableHealth { pub type BucketIndex = (CryptoKind, usize); #[derive(Debug, Clone, Copy)] +#[must_use] pub struct RecentPeersEntry { pub last_connection: Flow, } +#[must_use] pub(crate) struct RoutingTable { registry: VeilidComponentRegistry, inner: RwLock, @@ -231,10 +235,12 @@ impl RoutingTable { Ok(()) } + #[expect(clippy::unused_async)] async fn post_init_async(&self) -> EyreResult<()> { Ok(()) } + #[expect(clippy::unused_async)] pub(crate) async fn startup(&self) -> EyreResult<()> { Ok(()) } @@ -245,6 +251,7 @@ impl RoutingTable { self.cancel_tasks().await; } + #[expect(clippy::unused_async)] async fn pre_terminate_async(&self) {} /// Called to shut down the routing table @@ -1091,7 +1098,7 @@ impl RoutingTable { capabilities: Vec, ) { // Ask node for nodes closest to our own node - let closest_nodes = network_result_value_or_log!(self match self.find_nodes_close_to_self(crypto_kind, node_ref.clone(), capabilities.clone()).await { + let closest_nodes = network_result_value_or_log!(self match pin_future!(self.find_nodes_close_to_self(crypto_kind, node_ref.clone(), capabilities.clone())).await { Err(e) => { veilid_log!(self error "find_self failed for {:?}: {:?}", @@ -1107,7 +1114,7 @@ impl RoutingTable { // Ask each node near us to find us as well if wide { for closest_nr in closest_nodes { - network_result_value_or_log!(self match self.find_nodes_close_to_self(crypto_kind, closest_nr.clone(), capabilities.clone()).await { + network_result_value_or_log!(self match pin_future!(self.find_nodes_close_to_self(crypto_kind, closest_nr.clone(), capabilities.clone())).await { Err(e) => { veilid_log!(self error "find_self failed for {:?}: {:?}", diff --git a/veilid-core/src/routing_table/route_spec_store/mod.rs b/veilid-core/src/routing_table/route_spec_store/mod.rs index 623a228f..51be2aca 100644 --- a/veilid-core/src/routing_table/route_spec_store/mod.rs +++ b/veilid-core/src/routing_table/route_spec_store/mod.rs @@ -38,6 +38,7 @@ struct RouteSpecStoreInner { /// The routing table's storage for private/safety routes #[derive(Debug)] +#[must_use] pub(crate) struct RouteSpecStore { registry: VeilidComponentRegistry, inner: Mutex, diff --git a/veilid-core/src/routing_table/route_spec_store/route_spec_store_cache.rs b/veilid-core/src/routing_table/route_spec_store/route_spec_store_cache.rs index e225985e..eb9f5d81 100644 --- a/veilid-core/src/routing_table/route_spec_store/route_spec_store_cache.rs +++ b/veilid-core/src/routing_table/route_spec_store/route_spec_store_cache.rs @@ -157,12 +157,7 @@ impl RouteSpecStoreCache { } /// add remote private route to caches - /// returns a remote private route set id - fn add_remote_private_route( - &mut self, - id: RouteId, - rprinfo: RemotePrivateRouteInfo, - ) -> RouteId { + fn add_remote_private_route(&mut self, id: RouteId, rprinfo: RemotePrivateRouteInfo) { // also store in id by key table for private_route in rprinfo.get_private_routes() { self.remote_private_routes_by_key @@ -182,15 +177,14 @@ impl RouteSpecStoreCache { // If anything LRUs out, remove from the by-key table // Follow the same logic as 'remove_remote_private_route' here for dead_private_route in dead_rpri.get_private_routes() { - self.remote_private_routes_by_key + let _ = self + .remote_private_routes_by_key .remove(&dead_private_route.public_key.value) .unwrap(); self.invalidate_compiled_route_cache(&dead_private_route.public_key.value); } self.dead_remote_routes.push(dead_id); } - - id } /// iterate all of the remote private routes we have in the cache @@ -311,7 +305,8 @@ impl RouteSpecStoreCache { return false; }; for private_route in rprinfo.get_private_routes() { - self.remote_private_routes_by_key + let _ = self + .remote_private_routes_by_key .remove(&private_route.public_key.value) .unwrap(); self.invalidate_compiled_route_cache(&private_route.public_key.value); diff --git a/veilid-core/src/routing_table/route_spec_store/route_spec_store_content.rs b/veilid-core/src/routing_table/route_spec_store/route_spec_store_content.rs index 189cccd2..f30c2b0f 100644 --- a/veilid-core/src/routing_table/route_spec_store/route_spec_store_content.rs +++ b/veilid-core/src/routing_table/route_spec_store/route_spec_store_content.rs @@ -75,7 +75,7 @@ impl RouteSpecStoreContent { pub fn remove_detail(&mut self, id: &RouteId) -> Option { let detail = self.details.remove(id)?; for (pk, _) in detail.iter_route_set() { - self.id_by_key.remove(pk).unwrap(); + let _ = self.id_by_key.remove(pk).unwrap(); } Some(detail) } diff --git a/veilid-core/src/routing_table/routing_table_inner/mod.rs b/veilid-core/src/routing_table/routing_table_inner/mod.rs index b410315f..22505f21 100644 --- a/veilid-core/src/routing_table/routing_table_inner/mod.rs +++ b/veilid-core/src/routing_table/routing_table_inner/mod.rs @@ -16,6 +16,7 @@ pub type EntryCounts = BTreeMap<(RoutingDomain, CryptoKind), usize>; ////////////////////////////////////////////////////////////////////////// /// RoutingTable rwlock-internal data +#[must_use] pub struct RoutingTableInner { /// Convenience accessor for the global component registry pub(super) registry: VeilidComponentRegistry, diff --git a/veilid-core/src/routing_table/routing_table_inner/routing_domains/editor.rs b/veilid-core/src/routing_table/routing_table_inner/routing_domains/editor.rs index 78cdd179..65f0dbde 100644 --- a/veilid-core/src/routing_table/routing_table_inner/routing_domains/editor.rs +++ b/veilid-core/src/routing_table/routing_table_inner/routing_domains/editor.rs @@ -17,8 +17,8 @@ pub trait RoutingDomainEditorCommonTrait { capabilities: Vec, confirmed: bool, ) -> &mut Self; - fn commit(&mut self, pause_tasks: bool) -> SendPinBoxFutureLifetime<'_, bool>; - fn shutdown(&mut self) -> SendPinBoxFutureLifetime<'_, ()>; + fn commit(&mut self, pause_tasks: bool) -> PinBoxFuture<'_, bool>; + fn shutdown(&mut self) -> PinBoxFuture<'_, ()>; fn publish(&mut self); } diff --git a/veilid-core/src/routing_table/routing_table_inner/routing_domains/local_network/editor.rs b/veilid-core/src/routing_table/routing_table_inner/routing_domains/local_network/editor.rs index a5dc88e5..a3fdbe72 100644 --- a/veilid-core/src/routing_table/routing_table_inner/routing_domains/local_network/editor.rs +++ b/veilid-core/src/routing_table/routing_table_inner/routing_domains/local_network/editor.rs @@ -105,7 +105,7 @@ impl<'a> RoutingDomainEditorCommonTrait for RoutingDomainEditorLocalNetwork<'a> } #[instrument(level = "debug", skip(self))] - fn commit(&mut self, pause_tasks: bool) -> SendPinBoxFutureLifetime<'_, bool> { + fn commit(&mut self, pause_tasks: bool) -> PinBoxFuture<'_, bool> { Box::pin(async move { // No locking if we have nothing to do if self.changes.is_empty() { @@ -254,7 +254,7 @@ impl<'a> RoutingDomainEditorCommonTrait for RoutingDomainEditorLocalNetwork<'a> } #[instrument(level = "debug", skip(self))] - fn shutdown(&mut self) -> SendPinBoxFutureLifetime<'_, ()> { + fn shutdown(&mut self) -> PinBoxFuture<'_, ()> { Box::pin(async move { self.clear_dial_info_details(None, None) .set_relay_node(None) diff --git a/veilid-core/src/routing_table/routing_table_inner/routing_domains/public_internet/editor.rs b/veilid-core/src/routing_table/routing_table_inner/routing_domains/public_internet/editor.rs index d180a4f8..9dfab66b 100644 --- a/veilid-core/src/routing_table/routing_table_inner/routing_domains/public_internet/editor.rs +++ b/veilid-core/src/routing_table/routing_table_inner/routing_domains/public_internet/editor.rs @@ -116,7 +116,7 @@ impl<'a> RoutingDomainEditorCommonTrait for RoutingDomainEditorPublicInternet<'a } #[instrument(level = "debug", skip(self))] - fn commit(&mut self, pause_tasks: bool) -> SendPinBoxFutureLifetime<'_, bool> { + fn commit(&mut self, pause_tasks: bool) -> PinBoxFuture<'_, bool> { Box::pin(async move { // No locking if we have nothing to do if self.changes.is_empty() { @@ -270,7 +270,7 @@ impl<'a> RoutingDomainEditorCommonTrait for RoutingDomainEditorPublicInternet<'a } #[instrument(level = "debug", skip(self))] - fn shutdown(&mut self) -> SendPinBoxFutureLifetime<'_, ()> { + fn shutdown(&mut self) -> PinBoxFuture<'_, ()> { Box::pin(async move { self.clear_dial_info_details(None, None) .set_relay_node(None) diff --git a/veilid-core/src/routing_table/tasks/bootstrap.rs b/veilid-core/src/routing_table/tasks/bootstrap.rs index 80c3be5e..8ab20079 100644 --- a/veilid-core/src/routing_table/tasks/bootstrap.rs +++ b/veilid-core/src/routing_table/tasks/bootstrap.rs @@ -33,7 +33,7 @@ impl BootstrapRecord { impl RoutingTable { /// Process bootstrap version 0 - async fn process_bootstrap_records_v0( + fn process_bootstrap_records_v0( &self, records: Vec, ) -> EyreResult> { @@ -195,7 +195,7 @@ impl RoutingTable { }; let bootstrap_record = match txt_version { BOOTSTRAP_TXT_VERSION_0 => { - match self.process_bootstrap_records_v0(records).await { + match self.process_bootstrap_records_v0(records) { Err(e) => { veilid_log!(self error "couldn't process v0 bootstrap records from {}: {}", @@ -260,7 +260,7 @@ impl RoutingTable { &self, crypto_kinds: Vec, pi: Arc, - unord: &FuturesUnordered>, + unord: &FuturesUnordered>, ) { veilid_log!(self trace "--- bootstrapping {} with {:?}", @@ -291,7 +291,7 @@ impl RoutingTable { let bsdi = match network_manager .get_node_contact_method(nr.default_filtered()) { - Ok(NodeContactMethod::Direct(v)) => v, + Ok(Some(ncm)) if ncm.is_direct() => ncm.direct_dial_info().unwrap(), Ok(v) => { veilid_log!(nr debug "invalid contact method for bootstrap, ignoring peer: {:?}", v); // let _ = @@ -342,7 +342,7 @@ impl RoutingTable { veilid_log!(self debug " bootstrap crypto kinds: {:?}", &crypto_kinds); // Run all bootstrap operations concurrently - let mut unord = FuturesUnordered::>::new(); + let mut unord = FuturesUnordered::>::new(); for peer in peers { self.bootstrap_with_peer(crypto_kinds.clone(), peer, &unord); } @@ -367,7 +367,7 @@ impl RoutingTable { crypto_kinds } - #[instrument(level = "trace", skip(self), err)] + #[instrument(level = "trace", skip_all, err)] pub async fn bootstrap_task_routine( &self, stop_token: StopToken, @@ -403,7 +403,7 @@ impl RoutingTable { let mut peer_map = HashMap::>::new(); for bootstrap_di in bootstrap_dialinfos { veilid_log!(self debug "direct bootstrap with: {}", bootstrap_di); - let peers = network_manager.boot_request(bootstrap_di).await?; + let peers = pin_future!(network_manager.boot_request(bootstrap_di)).await?; for peer in peers { if !peer_map.contains_key(peer.node_ids()) { peer_map.insert(peer.node_ids().clone(), peer); @@ -413,10 +413,10 @@ impl RoutingTable { peer_map.into_values().collect() } else { // If not direct, resolve bootstrap servers and recurse their TXT entries - let bsrecs = match self + let bsrecs = match pin_future!(self .resolve_bootstrap(bootstrap) - .timeout_at(stop_token.clone()) - .await + .timeout_at(stop_token.clone())) + .await { Ok(v) => v?, Err(_) => { diff --git a/veilid-core/src/routing_table/tasks/ping_validator.rs b/veilid-core/src/routing_table/tasks/ping_validator.rs index bb82f554..f880dd37 100644 --- a/veilid-core/src/routing_table/tasks/ping_validator.rs +++ b/veilid-core/src/routing_table/tasks/ping_validator.rs @@ -14,7 +14,7 @@ const ACTIVE_WATCH_KEEPALIVE_PING_INTERVAL_SECS: u32 = 10; /// Ping queue processing depth per validator const MAX_PARALLEL_PINGS: usize = 8; -type PingValidatorFuture = SendPinBoxFuture>; +type PingValidatorFuture = PinBoxFutureStatic>; impl RoutingTable { // Task routine for PublicInternet status pings @@ -258,7 +258,7 @@ impl RoutingTable { futurequeue.push_back( async move { #[cfg(feature = "verbose-tracing")] - veilid_log!(self debug "--> PublicInternet Validator ping to {:?}", nr); + veilid_log!(nr debug "--> PublicInternet Validator ping to {:?}", nr); let rpc_processor = nr.rpc_processor(); let _ = rpc_processor .rpc_call_status(Destination::direct(nr)) @@ -291,7 +291,7 @@ impl RoutingTable { futurequeue.push_back( async move { #[cfg(feature = "verbose-tracing")] - veilid_log!(self debug "--> LocalNetwork Validator ping to {:?}", nr); + veilid_log!(nr debug "--> LocalNetwork Validator ping to {:?}", nr); let rpc_processor = nr.rpc_processor(); let _ = rpc_processor .rpc_call_status(Destination::direct(nr)) diff --git a/veilid-core/src/routing_table/tests/test_serialize_routing_table.rs b/veilid-core/src/routing_table/tests/test_serialize_routing_table.rs index f64cb9bf..68ce2c2e 100644 --- a/veilid-core/src/routing_table/tests/test_serialize_routing_table.rs +++ b/veilid-core/src/routing_table/tests/test_serialize_routing_table.rs @@ -57,7 +57,7 @@ pub async fn test_routingtable_buckets_round_trip() { mock_registry::terminate(copy_registry).await; } -pub async fn test_round_trip_peerinfo() { +pub fn test_round_trip_peerinfo() { let mut tks = TypedKeyGroup::new(); tks.add(TypedKey::new( CRYPTO_KIND_VLD0, @@ -93,5 +93,5 @@ pub async fn test_round_trip_peerinfo() { pub async fn test_all() { test_routingtable_buckets_round_trip().await; - test_round_trip_peerinfo().await; + test_round_trip_peerinfo(); } diff --git a/veilid-core/src/rpc_processor/fanout/fanout_call.rs b/veilid-core/src/rpc_processor/fanout/fanout_call.rs index 0b793673..8aabe788 100644 --- a/veilid-core/src/rpc_processor/fanout/fanout_call.rs +++ b/veilid-core/src/rpc_processor/fanout/fanout_call.rs @@ -64,7 +64,10 @@ pub struct FanoutCallOutput { } pub type FanoutCallResult = RPCNetworkResult; -pub type FanoutNodeInfoFilter = Arc bool + Send + Sync>; +pub type FanoutNodeInfoFilter = Arc bool) + Send + Sync>; +pub type FanoutCheckDone = Arc Option) + Send + Sync>; +pub type FanoutCallRoutine = + Arc PinBoxFutureStatic) + Send + Sync>; pub fn empty_fanout_node_info_filter() -> FanoutNodeInfoFilter { Arc::new(|_, _| true) @@ -91,12 +94,9 @@ pub fn capability_fanout_node_info_filter(caps: Vec) -> FanoutNodeIn /// If the algorithm times out, a Timeout result is returned, however operations will still have been performed and a /// timeout is not necessarily indicative of an algorithmic 'failure', just that no definitive stopping condition was found /// in the given time -pub(crate) struct FanoutCall<'a, R, F, C, D> +pub(crate) struct FanoutCall<'a, R> where R: Unpin, - F: Future, - C: Fn(NodeRef) -> F, - D: Fn(&[NodeRef]) -> Option, { routing_table: &'a RoutingTable, node_id: TypedKey, @@ -105,16 +105,13 @@ where fanout: usize, timeout_us: TimestampDuration, node_info_filter: FanoutNodeInfoFilter, - call_routine: C, - check_done: D, + call_routine: FanoutCallRoutine, + check_done: FanoutCheckDone, } -impl<'a, R, F, C, D> FanoutCall<'a, R, F, C, D> +impl<'a, R> FanoutCall<'a, R> where R: Unpin, - F: Future, - C: Fn(NodeRef) -> F, - D: Fn(&[NodeRef]) -> Option, { #[allow(clippy::too_many_arguments)] pub fn new( @@ -124,8 +121,8 @@ where fanout: usize, timeout_us: TimestampDuration, node_info_filter: FanoutNodeInfoFilter, - call_routine: C, - check_done: D, + call_routine: FanoutCallRoutine, + check_done: FanoutCheckDone, ) -> Self { let context = Mutex::new(FanoutContext { fanout_queue: FanoutQueue::new(node_id.kind), @@ -225,7 +222,7 @@ where #[allow(unused_variables)] Ok(x) => { // Call failed, node will not be considered again - event!(target: "fanout", Level::DEBUG, + event!(target: "fanout", Level::DEBUG, "Fanout result {}: {:?}", &next_node, x); } Err(e) => { diff --git a/veilid-core/src/rpc_processor/mod.rs b/veilid-core/src/rpc_processor/mod.rs index 29403af2..8b1b0906 100644 --- a/veilid-core/src/rpc_processor/mod.rs +++ b/veilid-core/src/rpc_processor/mod.rs @@ -68,12 +68,13 @@ impl_veilid_log_facility!("rpc"); ///////////////////////////////////////////////////////////////////// #[derive(Debug)] +#[must_use] struct WaitableReply { handle: OperationWaitHandle>, timeout_us: TimestampDuration, node_ref: NodeRef, send_ts: Timestamp, - send_data_method: SendDataMethod, + send_data_method: SendDataResult, safety_route: Option, remote_private_route: Option, reply_private_route: Option, @@ -83,6 +84,7 @@ struct WaitableReply { ///////////////////////////////////////////////////////////////////// #[derive(Copy, Clone, Debug)] +#[must_use] enum RPCKind { Question, Statement, @@ -92,6 +94,7 @@ enum RPCKind { ///////////////////////////////////////////////////////////////////// #[derive(Debug, Clone)] +#[must_use] pub struct RPCProcessorStartupContext { pub startup_lock: Arc, } @@ -111,6 +114,7 @@ impl Default for RPCProcessorStartupContext { ///////////////////////////////////////////////////////////////////// #[derive(Debug)] +#[must_use] struct RPCProcessorInner { send_channel: Option>, stop_source: Option, @@ -118,6 +122,7 @@ struct RPCProcessorInner { } #[derive(Debug)] +#[must_use] pub(crate) struct RPCProcessor { registry: VeilidComponentRegistry, inner: Mutex, @@ -183,14 +188,17 @@ impl RPCProcessor { ///////////////////////////////////// /// Initialization + #[expect(clippy::unused_async)] async fn init_async(&self) -> EyreResult<()> { Ok(()) } + #[expect(clippy::unused_async)] async fn post_init_async(&self) -> EyreResult<()> { Ok(()) } + #[expect(clippy::unused_async)] async fn pre_terminate_async(&self) { // Ensure things have shut down assert!( @@ -199,6 +207,7 @@ impl RPCProcessor { ); } + #[expect(clippy::unused_async)] async fn terminate_async(&self) {} ////////////////////////////////////////////////////////////////////// @@ -223,7 +232,7 @@ impl RPCProcessor { let stop_token = inner.stop_source.as_ref().unwrap().token(); let jh = spawn(&format!("rpc worker {}", task_n), async move { let this = registry.rpc_processor(); - this.rpc_worker(stop_token, receiver).await + Box::pin(this.rpc_worker(stop_token, receiver)).await }); inner.worker_join_handles.push(jh); } @@ -368,9 +377,10 @@ impl RPCProcessor { } // Routine to call to generate fanout - let call_routine = |next_node: NodeRef| { - let registry = self.registry(); - async move { + let registry = self.registry(); + let call_routine = Arc::new(move |next_node: NodeRef| { + let registry = registry.clone(); + Box::pin(async move { let this = registry.rpc_processor(); let v = network_result_try!( this.rpc_call_find_node( @@ -384,11 +394,11 @@ impl RPCProcessor { Ok(NetworkResult::value(FanoutCallOutput { peer_info_list: v.answer, })) - } - }; + }) as PinBoxFuture + }); // Routine to call to check if we're done at each step - let check_done = |_: &[NodeRef]| { + let check_done = Arc::new(move |_: &[NodeRef]| { let Ok(Some(nr)) = routing_table.lookup_node_ref(node_id) else { return None; }; @@ -401,7 +411,7 @@ impl RPCProcessor { } None - }; + }); // Call the fanout let routing_table = self.routing_table(); @@ -421,13 +431,13 @@ impl RPCProcessor { /// Search the DHT for a specific node corresponding to a key unless we /// have that node in our routing table already, and return the node reference - /// Note: This routine can possibly be recursive, hence the SendPinBoxFuture async form + /// Note: This routine can possibly be recursive, hence the PinBoxFuture async form #[instrument(level = "trace", target = "rpc", skip_all)] pub fn resolve_node( &self, node_id: TypedKey, safety_selection: SafetySelection, - ) -> SendPinBoxFuture, RPCError>> { + ) -> PinBoxFuture, RPCError>> { let registry = self.registry(); Box::pin( async move { @@ -1165,11 +1175,12 @@ impl RPCProcessor { ); // Ref the connection so it doesn't go away until we're done with the waitable reply - let opt_connection_ref_scope = send_data_method.unique_flow.connection_id.and_then(|id| { - self.network_manager() - .connection_manager() - .try_connection_ref_scope(id) - }); + let opt_connection_ref_scope = + send_data_method.unique_flow().connection_id.and_then(|id| { + self.network_manager() + .connection_manager() + .try_connection_ref_scope(id) + }); // Pass back waitable reply completion Ok(NetworkResult::value(WaitableReply { @@ -1506,35 +1517,75 @@ impl RPCProcessor { // Process specific message kind match msg.operation.kind() { - RPCOperationKind::Question(q) => match q.detail() { - RPCQuestionDetail::StatusQ(_) => self.process_status_q(msg).await, - RPCQuestionDetail::FindNodeQ(_) => self.process_find_node_q(msg).await, - RPCQuestionDetail::AppCallQ(_) => self.process_app_call_q(msg).await, - RPCQuestionDetail::GetValueQ(_) => self.process_get_value_q(msg).await, - RPCQuestionDetail::SetValueQ(_) => self.process_set_value_q(msg).await, - RPCQuestionDetail::WatchValueQ(_) => self.process_watch_value_q(msg).await, - RPCQuestionDetail::InspectValueQ(_) => self.process_inspect_value_q(msg).await, - #[cfg(feature = "unstable-blockstore")] - RPCQuestionDetail::SupplyBlockQ(_) => self.process_supply_block_q(msg).await, - #[cfg(feature = "unstable-blockstore")] - RPCQuestionDetail::FindBlockQ(_) => self.process_find_block_q(msg).await, - #[cfg(feature = "unstable-tunnels")] - RPCQuestionDetail::StartTunnelQ(_) => self.process_start_tunnel_q(msg).await, - #[cfg(feature = "unstable-tunnels")] - RPCQuestionDetail::CompleteTunnelQ(_) => self.process_complete_tunnel_q(msg).await, - #[cfg(feature = "unstable-tunnels")] - RPCQuestionDetail::CancelTunnelQ(_) => self.process_cancel_tunnel_q(msg).await, - }, - RPCOperationKind::Statement(s) => match s.detail() { - RPCStatementDetail::ValidateDialInfo(_) => { - self.process_validate_dial_info(msg).await - } - RPCStatementDetail::Route(_) => self.process_route(msg).await, - RPCStatementDetail::ValueChanged(_) => self.process_value_changed(msg).await, - RPCStatementDetail::Signal(_) => self.process_signal(msg).await, - RPCStatementDetail::ReturnReceipt(_) => self.process_return_receipt(msg).await, - RPCStatementDetail::AppMessage(_) => self.process_app_message(msg).await, - }, + RPCOperationKind::Question(q) => { + let res = match q.detail() { + RPCQuestionDetail::StatusQ(_) => { + pin_dyn_future_closure!(self.process_status_q(msg)) + } + RPCQuestionDetail::FindNodeQ(_) => { + pin_dyn_future_closure!(self.process_find_node_q(msg)) + } + RPCQuestionDetail::AppCallQ(_) => { + pin_dyn_future_closure!(self.process_app_call_q(msg)) + } + RPCQuestionDetail::GetValueQ(_) => { + pin_dyn_future_closure!(self.process_get_value_q(msg)) + } + RPCQuestionDetail::SetValueQ(_) => { + pin_dyn_future_closure!(self.process_set_value_q(msg)) + } + RPCQuestionDetail::WatchValueQ(_) => { + pin_dyn_future_closure!(self.process_watch_value_q(msg)) + } + RPCQuestionDetail::InspectValueQ(_) => { + pin_dyn_future_closure!(self.process_inspect_value_q(msg)) + } + #[cfg(feature = "unstable-blockstore")] + RPCQuestionDetail::SupplyBlockQ(_) => { + pin_dyn_future_closure!(self.process_supply_block_q(msg)) + } + #[cfg(feature = "unstable-blockstore")] + RPCQuestionDetail::FindBlockQ(_) => { + pin_dyn_future_closure!(self.process_find_block_q(msg)) + } + #[cfg(feature = "unstable-tunnels")] + RPCQuestionDetail::StartTunnelQ(_) => { + pin_dyn_future_closure!(self.process_start_tunnel_q(msg)) + } + #[cfg(feature = "unstable-tunnels")] + RPCQuestionDetail::CompleteTunnelQ(_) => { + pin_dyn_future_closure!(self.process_complete_tunnel_q(msg)) + } + #[cfg(feature = "unstable-tunnels")] + RPCQuestionDetail::CancelTunnelQ(_) => { + pin_dyn_future_closure!(self.process_cancel_tunnel_q(msg)) + } + }; + res.await + } + RPCOperationKind::Statement(s) => { + let res = match s.detail() { + RPCStatementDetail::ValidateDialInfo(_) => { + pin_dyn_future_closure!(self.process_validate_dial_info(msg)) + } + RPCStatementDetail::Route(_) => { + pin_dyn_future_closure!(self.process_route(msg)) + } + RPCStatementDetail::ValueChanged(_) => { + pin_dyn_future_closure!(self.process_value_changed(msg)) + } + RPCStatementDetail::Signal(_) => { + pin_dyn_future_closure!(self.process_signal(msg)) + } + RPCStatementDetail::ReturnReceipt(_) => { + pin_dyn_future_closure!(self.process_return_receipt(msg)) + } + RPCStatementDetail::AppMessage(_) => { + pin_dyn_future_closure!(self.process_app_message(msg)) + } + }; + res.await + } RPCOperationKind::Answer(_) => { let op_id = msg.operation.op_id(); if let Err(e) = self.waiting_rpc_table.complete_op_waiter(op_id, msg) { diff --git a/veilid-core/src/rpc_processor/rpc_status.rs b/veilid-core/src/rpc_processor/rpc_status.rs index 6a692525..cdf6208f 100644 --- a/veilid-core/src/rpc_processor/rpc_status.rs +++ b/veilid-core/src/rpc_processor/rpc_status.rs @@ -115,18 +115,13 @@ impl RPCProcessor { } => { if matches!(safety_selection, SafetySelection::Unsafe(_)) { if let Some(sender_info) = sender_info { - if send_data_method.opt_relayed_contact_method.is_none() - && matches!( - send_data_method.contact_method, - NodeContactMethod::Direct(_) - ) - { + if send_data_method.is_direct() { // Directly requested status that actually gets sent directly and not over a relay will tell us what our IP address appears as // If this changes, we'd want to know about that to reset the networking stack opt_previous_sender_info = target.report_sender_info( routing_domain, - send_data_method.unique_flow.flow.protocol_type(), - send_data_method.unique_flow.flow.address_type(), + send_data_method.unique_flow().flow.protocol_type(), + send_data_method.unique_flow().flow.address_type(), sender_info, ); }; @@ -137,7 +132,7 @@ impl RPCProcessor { routing_domain, socket_address: sender_info.socket_address, old_socket_address: opt_previous_sender_info.map(|s| s.socket_address), - flow: send_data_method.unique_flow.flow, + flow: send_data_method.unique_flow().flow, reporting_peer: target.unfiltered(), }) { veilid_log!(self debug "Failed to post event: {}", e); diff --git a/veilid-core/src/rpc_processor/rpc_validate_dial_info.rs b/veilid-core/src/rpc_processor/rpc_validate_dial_info.rs index 00327b6d..1948ae3c 100644 --- a/veilid-core/src/rpc_processor/rpc_validate_dial_info.rs +++ b/veilid-core/src/rpc_processor/rpc_validate_dial_info.rs @@ -82,7 +82,7 @@ impl RPCProcessor { //////////////////////////////////////////////////////////////////////////////////////////////// - #[instrument(level = "trace", target = "rpc", skip(self, msg), fields(msg.operation.op_id), ret, err)] + //#[instrument(level = "trace", target = "rpc", skip(self, msg), fields(msg.operation.op_id), ret, err)] pub(super) async fn process_validate_dial_info(&self, msg: Message) -> RPCNetworkResult<()> { // Ensure this never came over a private route, safety route is okay though let detail = match msg.header.detail { @@ -187,7 +187,7 @@ impl RPCProcessor { // Send the validate_dial_info request // This can only be sent directly, as relays can not validate dial info - network_result_value_or_log!(self self.statement(Destination::direct(peer.default_filtered()), statement) + network_result_value_or_log!(self pin_future_closure!(self.statement(Destination::direct(peer.default_filtered()), statement)) .await? => [ format!(": peer={} statement={:?}", peer, statement) ] { continue; } diff --git a/veilid-core/src/storage_manager/debug.rs b/veilid-core/src/storage_manager/debug.rs index 17b08391..05a44759 100644 --- a/veilid-core/src/storage_manager/debug.rs +++ b/veilid-core/src/storage_manager/debug.rs @@ -33,11 +33,20 @@ impl StorageManager { } format!("{}]\n", out) } + pub async fn debug_offline_records(&self) -> String { let inner = self.inner.lock().await; + let Some(local_record_store) = &inner.local_record_store else { + return "not initialized".to_owned(); + }; + let mut out = "[\n".to_owned(); for (k, v) in &inner.offline_subkey_writes { - out += &format!(" {}:{:?}\n", k, v); + let record_info = local_record_store + .peek_record(*k, |r| format!("{} nodes", r.detail().nodes.len())) + .unwrap_or("Not found".to_owned()); + + out += &format!(" {}:{:?}, {}\n", k, v, record_info); } format!("{}]\n", out) } diff --git a/veilid-core/src/storage_manager/get_value.rs b/veilid-core/src/storage_manager/get_value.rs index 18897a1c..f0aeb5da 100644 --- a/veilid-core/src/storage_manager/get_value.rs +++ b/veilid-core/src/storage_manager/get_value.rs @@ -84,11 +84,11 @@ impl StorageManager { let call_routine = { let context = context.clone(); let registry = self.registry(); - move |next_node: NodeRef| { + Arc::new(move |next_node: NodeRef| { let context = context.clone(); let registry = registry.clone(); let last_descriptor = last_get_result.opt_descriptor.clone(); - async move { + Box::pin(async move { let rpc_processor = registry.rpc_processor(); let gva = network_result_try!( rpc_processor @@ -189,8 +189,8 @@ impl StorageManager { veilid_log!(registry debug target:"network_result", "GetValue fanout call returned peers {}", gva.answer.peers.len()); Ok(NetworkResult::value(FanoutCallOutput{peer_info_list: gva.answer.peers})) - }.instrument(tracing::trace_span!("outbound_get_value fanout routine")) - } + }.instrument(tracing::trace_span!("outbound_get_value fanout routine"))) as PinBoxFuture + }) }; // Routine to call to check if we're done at each step @@ -198,7 +198,7 @@ impl StorageManager { let context = context.clone(); let out_tx = out_tx.clone(); let registry = self.registry(); - move |_closest_nodes: &[NodeRef]| { + Arc::new(move |_closest_nodes: &[NodeRef]| { let mut ctx = context.lock(); // send partial update if desired @@ -229,7 +229,7 @@ impl StorageManager { return Some(()); } None - } + }) }; // Call the fanout in a spawned task @@ -305,7 +305,7 @@ impl StorageManager { self.process_deferred_results( res_rx, Box::new( - move |result: VeilidAPIResult| -> SendPinBoxFuture { + move |result: VeilidAPIResult| -> PinBoxFutureStatic { let registry=registry.clone(); Box::pin(async move { let this = registry.storage_manager(); diff --git a/veilid-core/src/storage_manager/inspect_value.rs b/veilid-core/src/storage_manager/inspect_value.rs index 356bdba3..ef8d3fef 100644 --- a/veilid-core/src/storage_manager/inspect_value.rs +++ b/veilid-core/src/storage_manager/inspect_value.rs @@ -120,12 +120,12 @@ impl StorageManager { let call_routine = { let context = context.clone(); let registry = self.registry(); - move |next_node: NodeRef| { + Arc::new(move |next_node: NodeRef| { let context = context.clone(); let registry = registry.clone(); let opt_descriptor = local_inspect_result.opt_descriptor.clone(); let subkeys = subkeys.clone(); - async move { + Box::pin(async move { let rpc_processor = registry.rpc_processor(); let iva = network_result_try!( @@ -159,7 +159,7 @@ impl StorageManager { // Keep the value if we got one and it is newer and it passes schema validation if !answer.seqs.is_empty() { - veilid_log!(self debug "Got seqs back: len={}", answer.seqs.len()); + veilid_log!(registry debug "Got seqs back: len={}", answer.seqs.len()); let mut ctx = context.lock(); // Ensure we have a schema and descriptor etc @@ -239,25 +239,29 @@ impl StorageManager { veilid_log!(registry debug target:"network_result", "InspectValue fanout call returned peers {}", answer.peers.len()); Ok(NetworkResult::value(FanoutCallOutput { peer_info_list: answer.peers})) - }.instrument(tracing::trace_span!("outbound_inspect_value fanout call")) - } + }.instrument(tracing::trace_span!("outbound_inspect_value fanout call"))) as PinBoxFuture + }) }; // Routine to call to check if we're done at each step - let check_done = |_closest_nodes: &[NodeRef]| { - // If we have reached sufficient consensus on all subkeys, return done - let ctx = context.lock(); - let mut has_consensus = true; - for cs in ctx.seqcounts.iter() { - if cs.value_nodes.len() < consensus_count { - has_consensus = false; - break; + + let check_done = { + let context = context.clone(); + Arc::new(move |_closest_nodes: &[NodeRef]| { + // If we have reached sufficient consensus on all subkeys, return done + let ctx = context.lock(); + let mut has_consensus = true; + for cs in ctx.seqcounts.iter() { + if cs.value_nodes.len() < consensus_count { + has_consensus = false; + break; + } } - } - if !ctx.seqcounts.is_empty() && ctx.opt_descriptor_info.is_some() && has_consensus { - return Some(()); - } - None + if !ctx.seqcounts.is_empty() && ctx.opt_descriptor_info.is_some() && has_consensus { + return Some(()); + } + None + }) }; // Call the fanout diff --git a/veilid-core/src/storage_manager/mod.rs b/veilid-core/src/storage_manager/mod.rs index 26d2d559..73ea7ebf 100644 --- a/veilid-core/src/storage_manager/mod.rs +++ b/veilid-core/src/storage_manager/mod.rs @@ -62,7 +62,7 @@ struct StorageManagerInner { /// Storage manager metadata that is persistent, including copy of offline subkey writes pub metadata_db: Option, /// Background processing task (not part of attachment manager tick tree so it happens when detached too) - pub tick_future: Option>, + pub tick_future: Option>, } impl fmt::Debug for StorageManagerInner { @@ -237,7 +237,7 @@ impl StorageManager { } // Start deferred results processors - self.deferred_result_processor.init().await; + self.deferred_result_processor.init(); Ok(()) } @@ -966,9 +966,8 @@ impl StorageManager { // Update the watch. This just calls through to the above watch_values() function // This will update the active_watch so we don't need to do that in this routine. - let expiration_ts = self - .watch_values(key, subkeys, active_watch.expiration_ts, count) - .await?; + let expiration_ts = + pin_future!(self.watch_values(key, subkeys, active_watch.expiration_ts, count)).await?; // A zero expiration time returned from watch_value() means the watch is done // or no subkeys are left, and the watch is no longer active @@ -1739,7 +1738,7 @@ impl StorageManager { pub(super) fn process_deferred_results( &self, receiver: flume::Receiver, - handler: impl FnMut(T) -> SendPinBoxFuture + Send + 'static, + handler: impl FnMut(T) -> PinBoxFutureStatic + Send + 'static, ) -> bool { self.deferred_result_processor .add(receiver.into_stream(), handler) diff --git a/veilid-core/src/storage_manager/set_value.rs b/veilid-core/src/storage_manager/set_value.rs index a018ee91..bbf86108 100644 --- a/veilid-core/src/storage_manager/set_value.rs +++ b/veilid-core/src/storage_manager/set_value.rs @@ -82,11 +82,11 @@ impl StorageManager { let context = context.clone(); let registry = self.registry(); - move |next_node: NodeRef| { + Arc::new(move |next_node: NodeRef| { let registry = registry.clone(); let context = context.clone(); let descriptor = descriptor.clone(); - async move { + Box::pin(async move { let rpc_processor = registry.rpc_processor(); let send_descriptor = true; // xxx check if next_node needs the descriptor or not, see issue #203 @@ -187,8 +187,8 @@ impl StorageManager { ctx.send_partial_update = true; Ok(NetworkResult::value(FanoutCallOutput{peer_info_list:sva.answer.peers})) - }.instrument(tracing::trace_span!("fanout call_routine")) - } + }.instrument(tracing::trace_span!("fanout call_routine"))) as PinBoxFuture + }) }; // Routine to call to check if we're done at each step @@ -196,7 +196,7 @@ impl StorageManager { let context = context.clone(); let out_tx = out_tx.clone(); let registry = self.registry(); - move |_closest_nodes: &[NodeRef]| { + Arc::new(move |_closest_nodes: &[NodeRef]| { let mut ctx = context.lock(); // send partial update if desired @@ -233,7 +233,7 @@ impl StorageManager { return Some(()); } None - } + }) }; // Call the fanout in a spawned task @@ -308,7 +308,7 @@ impl StorageManager { self.process_deferred_results( res_rx, Box::new( - move |result: VeilidAPIResult| -> SendPinBoxFuture { + move |result: VeilidAPIResult| -> PinBoxFutureStatic { let registry = registry.clone(); let last_value_data = last_value_data.clone(); Box::pin(async move { diff --git a/veilid-core/src/storage_manager/types/signed_value_descriptor.rs b/veilid-core/src/storage_manager/types/signed_value_descriptor.rs index 48bf2a6a..bb0ff54b 100644 --- a/veilid-core/src/storage_manager/types/signed_value_descriptor.rs +++ b/veilid-core/src/storage_manager/types/signed_value_descriptor.rs @@ -26,7 +26,7 @@ impl SignedValueDescriptor { ); } // validate schema - DHTSchema::try_from(self.schema_data.as_slice())?; + let _ = DHTSchema::try_from(self.schema_data.as_slice())?; Ok(()) } diff --git a/veilid-core/src/storage_manager/watch_value.rs b/veilid-core/src/storage_manager/watch_value.rs index d3c6bea2..e9933c03 100644 --- a/veilid-core/src/storage_manager/watch_value.rs +++ b/veilid-core/src/storage_manager/watch_value.rs @@ -99,18 +99,17 @@ impl StorageManager { opt_watcher.unwrap_or_else(|| self.anonymous_watch_keys.get(key.kind).unwrap().value); let wva = VeilidAPIError::from_network_result( - self.rpc_processor() - .rpc_call_watch_value( - Destination::direct(watch_node.routing_domain_filtered(routing_domain)) - .with_safety(safety_selection), - key, - subkeys, - expiration, - count, - watcher, - Some(watch_id), - ) - .await?, + pin_future!(self.rpc_processor().rpc_call_watch_value( + Destination::direct(watch_node.routing_domain_filtered(routing_domain)) + .with_safety(safety_selection), + key, + subkeys, + expiration, + count, + watcher, + Some(watch_id), + )) + .await?, )?; if wva.answer.accepted { @@ -233,13 +232,13 @@ impl StorageManager { let call_routine = { let context = context.clone(); let registry = self.registry(); - move |next_node: NodeRef| { + Arc::new(move |next_node: NodeRef| { let context = context.clone(); let registry = registry.clone(); let subkeys = subkeys.clone(); - async move { + Box::pin(async move { let rpc_processor = registry.rpc_processor(); let wva = network_result_try!( rpc_processor @@ -282,18 +281,21 @@ impl StorageManager { veilid_log!(registry debug target:"network_result", "WatchValue fanout call returned peers {} ({})", wva.answer.peers.len(), next_node); Ok(NetworkResult::value(FanoutCallOutput{peer_info_list: wva.answer.peers})) - }.instrument(tracing::trace_span!("outbound_watch_value call routine")) - } + }.instrument(tracing::trace_span!("outbound_watch_value call routine"))) as PinBoxFuture + }) }; // Routine to call to check if we're done at each step - let check_done = |_closest_nodes: &[NodeRef]| { - // If a watch has succeeded, return done - let ctx = context.lock(); - if ctx.opt_watch_value_result.is_some() { - return Some(()); - } - None + let check_done = { + let context = context.clone(); + Arc::new(move |_closest_nodes: &[NodeRef]| { + // If a watch has succeeded, return done + let ctx = context.lock(); + if ctx.opt_watch_value_result.is_some() { + return Some(()); + } + None + }) }; // Call the fanout diff --git a/veilid-core/src/table_store/mod.rs b/veilid-core/src/table_store/mod.rs index cc7d7ba1..ed15f538 100644 --- a/veilid-core/src/table_store/mod.rs +++ b/veilid-core/src/table_store/mod.rs @@ -23,6 +23,7 @@ const ALL_TABLE_NAMES: &[u8] = b"all_table_names"; /// Description of column #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct ColumnInfo { pub key_count: AlignedU64, } @@ -30,6 +31,7 @@ pub struct ColumnInfo { /// IO Stats for table #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct IOStatsInfo { /// Number of transaction. pub transactions: AlignedU64, @@ -54,6 +56,7 @@ pub struct IOStatsInfo { /// Description of table #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct TableInfo { /// Internal table name pub table_name: String, @@ -67,6 +70,7 @@ pub struct TableInfo { pub columns: Vec, } +#[must_use] struct TableStoreInner { opened: BTreeMap>, encryption_key: Option, @@ -87,6 +91,7 @@ impl fmt::Debug for TableStoreInner { /// Veilid Table Storage. /// Database for storing key value pairs persistently and securely across runs. +#[must_use] pub struct TableStore { registry: VeilidComponentRegistry, inner: Mutex, // Sync mutex here because TableDB drops can happen at any time @@ -160,7 +165,7 @@ impl TableStore { }) } - async fn name_get_or_create(&self, table: &str) -> VeilidAPIResult { + fn name_get_or_create(&self, table: &str) -> VeilidAPIResult { let name = self.namespaced_name(table)?; let mut inner = self.inner.lock(); @@ -356,8 +361,7 @@ impl TableStore { async fn load_device_encryption_key(&self) -> EyreResult> { let dek_bytes: Option> = self .protected_store() - .load_user_secret("device_encryption_key") - .await?; + .load_user_secret("device_encryption_key")?; let Some(dek_bytes) = dek_bytes else { veilid_log!(self debug "no device encryption key"); return Ok(None); @@ -383,8 +387,7 @@ impl TableStore { // Remove the device encryption key let existed = self .protected_store() - .remove_user_secret("device_encryption_key") - .await?; + .remove_user_secret("device_encryption_key")?; veilid_log!(self debug "removed device encryption key. existed: {}", existed); return Ok(()); }; @@ -423,8 +426,7 @@ impl TableStore { // Save the new device encryption key let existed = self .protected_store() - .save_user_secret("device_encryption_key", &dek_bytes) - .await?; + .save_user_secret("device_encryption_key", &dek_bytes)?; veilid_log!(self debug "saving device encryption key. existed: {}", existed); Ok(()) } @@ -560,7 +562,7 @@ impl TableStore { } } - let table_name = self.name_get_or_create(name).await?; + let table_name = self.name_get_or_create(name)?; // See if this table is already opened, if so the column count must be the same { diff --git a/veilid-core/src/table_store/native.rs b/veilid-core/src/table_store/native.rs index 4c4bba7d..46218464 100644 --- a/veilid-core/src/table_store/native.rs +++ b/veilid-core/src/table_store/native.rs @@ -3,6 +3,7 @@ pub use keyvaluedb_sqlite::*; use std::path::PathBuf; #[derive(Clone)] +#[must_use] pub(in crate::table_store) struct TableStoreDriver { registry: VeilidComponentRegistry, } @@ -31,6 +32,7 @@ impl TableStoreDriver { Ok(dbpath) } + #[expect(clippy::unused_async)] pub async fn open(&self, table_name: &str, column_count: u32) -> VeilidAPIResult { let dbpath = self.get_dbpath(table_name)?; @@ -52,6 +54,7 @@ impl TableStoreDriver { Ok(db) } + #[expect(clippy::unused_async)] pub async fn delete(&self, table_name: &str) -> VeilidAPIResult { let dbpath = self.get_dbpath(table_name)?; if !dbpath.exists() { diff --git a/veilid-core/src/table_store/table_db.rs b/veilid-core/src/table_store/table_db.rs index 0335b80c..19ac1f4a 100644 --- a/veilid-core/src/table_store/table_db.rs +++ b/veilid-core/src/table_store/table_db.rs @@ -12,6 +12,7 @@ cfg_if! { impl_veilid_log_facility!("tstore"); +#[must_use] struct CryptInfo { typed_key: TypedSharedSecret, } @@ -21,6 +22,7 @@ impl CryptInfo { } } +#[must_use] pub struct TableDBUnlockedInner { registry: VeilidComponentRegistry, table: String, @@ -44,6 +46,7 @@ impl Drop for TableDBUnlockedInner { } #[derive(Debug, Clone)] +#[must_use] pub struct TableDB { opened_column_count: u32, unlocked_inner: Arc, @@ -107,6 +110,7 @@ impl TableDB { } /// Get the internal name of the table + #[must_use] pub fn table_name(&self) -> String { self.unlocked_inner.table.clone() } diff --git a/veilid-core/src/table_store/wasm.rs b/veilid-core/src/table_store/wasm.rs index f4a6a6f6..da2f910c 100644 --- a/veilid-core/src/table_store/wasm.rs +++ b/veilid-core/src/table_store/wasm.rs @@ -2,6 +2,7 @@ use super::*; pub use keyvaluedb_web::*; #[derive(Clone)] +#[must_use] pub(in crate::table_store) struct TableStoreDriver { registry: VeilidComponentRegistry, } diff --git a/veilid-core/src/tests/common/test_protected_store.rs b/veilid-core/src/tests/common/test_protected_store.rs index 4347e105..4705342b 100644 --- a/veilid-core/src/tests/common/test_protected_store.rs +++ b/veilid-core/src/tests/common/test_protected_store.rs @@ -15,73 +15,55 @@ async fn shutdown(api: VeilidAPI) { trace!("test_table_store: finished"); } -pub async fn test_protected_store(ps: &ProtectedStore) { +pub fn test_protected_store(ps: &ProtectedStore) { info!("testing protected store"); - let _ = ps.remove_user_secret("_test_key").await; - let _ = ps.remove_user_secret("_test_broken").await; + let _ = ps.remove_user_secret("_test_key"); + let _ = ps.remove_user_secret("_test_broken"); let d1: [u8; 0] = []; - assert!(!ps - .save_user_secret("_test_key", &[2u8, 3u8, 4u8]) - .await - .unwrap()); + assert!(!ps.save_user_secret("_test_key", &[2u8, 3u8, 4u8]).unwrap()); info!("testing saving user secret"); - assert!(ps.save_user_secret("_test_key", &d1).await.unwrap()); + assert!(ps.save_user_secret("_test_key", &d1).unwrap()); info!("testing loading user secret"); - assert_eq!( - ps.load_user_secret("_test_key").await.unwrap(), - Some(d1.to_vec()) - ); + assert_eq!(ps.load_user_secret("_test_key").unwrap(), Some(d1.to_vec())); info!("testing loading user secret again"); - assert_eq!( - ps.load_user_secret("_test_key").await.unwrap(), - Some(d1.to_vec()) - ); + assert_eq!(ps.load_user_secret("_test_key").unwrap(), Some(d1.to_vec())); info!("testing loading broken user secret"); - assert_eq!(ps.load_user_secret("_test_broken").await.unwrap(), None); + assert_eq!(ps.load_user_secret("_test_broken").unwrap(), None); info!("testing loading broken user secret again"); - assert_eq!(ps.load_user_secret("_test_broken").await.unwrap(), None); + assert_eq!(ps.load_user_secret("_test_broken").unwrap(), None); info!("testing remove user secret"); - assert!(ps.remove_user_secret("_test_key").await.unwrap()); + assert!(ps.remove_user_secret("_test_key").unwrap()); info!("testing remove user secret again"); - assert!(!ps.remove_user_secret("_test_key").await.unwrap()); + assert!(!ps.remove_user_secret("_test_key").unwrap()); info!("testing remove broken user secret"); - assert!(!ps.remove_user_secret("_test_broken").await.unwrap()); + assert!(!ps.remove_user_secret("_test_broken").unwrap()); info!("testing remove broken user secret again"); - assert!(!ps.remove_user_secret("_test_broken").await.unwrap()); + assert!(!ps.remove_user_secret("_test_broken").unwrap()); let d2: [u8; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert!(!ps - .save_user_secret("_test_key", &[2u8, 3u8, 4u8]) - .await - .unwrap()); - assert!(ps.save_user_secret("_test_key", &d2).await.unwrap()); - assert_eq!( - ps.load_user_secret("_test_key").await.unwrap(), - Some(d2.to_vec()) - ); - assert_eq!( - ps.load_user_secret("_test_key").await.unwrap(), - Some(d2.to_vec()) - ); - assert_eq!(ps.load_user_secret("_test_broken").await.unwrap(), None); - assert_eq!(ps.load_user_secret("_test_broken").await.unwrap(), None); - assert!(ps.remove_user_secret("_test_key").await.unwrap()); - assert!(!ps.remove_user_secret("_test_key").await.unwrap()); - assert!(!ps.remove_user_secret("_test_key").await.unwrap()); - assert!(!ps.remove_user_secret("_test_broken").await.unwrap()); + assert!(!ps.save_user_secret("_test_key", &[2u8, 3u8, 4u8]).unwrap()); + assert!(ps.save_user_secret("_test_key", &d2).unwrap()); + assert_eq!(ps.load_user_secret("_test_key").unwrap(), Some(d2.to_vec())); + assert_eq!(ps.load_user_secret("_test_key").unwrap(), Some(d2.to_vec())); + assert_eq!(ps.load_user_secret("_test_broken").unwrap(), None); + assert_eq!(ps.load_user_secret("_test_broken").unwrap(), None); + assert!(ps.remove_user_secret("_test_key").unwrap()); + assert!(!ps.remove_user_secret("_test_key").unwrap()); + assert!(!ps.remove_user_secret("_test_key").unwrap()); + assert!(!ps.remove_user_secret("_test_broken").unwrap()); - let _ = ps.remove_user_secret("_test_key").await; - let _ = ps.remove_user_secret("_test_broken").await; + let _ = ps.remove_user_secret("_test_key"); + let _ = ps.remove_user_secret("_test_broken"); } pub async fn test_all() { let api = startup().await; let ps = api.protected_store().unwrap(); - test_protected_store(&ps).await; + test_protected_store(&ps); shutdown(api).await; } diff --git a/veilid-core/src/tests/common/test_veilid_config.rs b/veilid-core/src/tests/common/test_veilid_config.rs index d5f7a44e..3f729e6e 100644 --- a/veilid-core/src/tests/common/test_veilid_config.rs +++ b/veilid-core/src/tests/common/test_veilid_config.rs @@ -62,25 +62,25 @@ wFAbkZY9eS/x6P7qrpd7dUA= cfg_if! { if #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] { - pub fn get_table_store_path() -> String { + #[must_use]pub fn get_table_store_path() -> String { String::new() } - pub fn get_block_store_path() -> String { + #[must_use]pub fn get_block_store_path() -> String { String::new() } - pub fn get_protected_store_path() -> String { + #[must_use]pub fn get_protected_store_path() -> String { String::new() } - pub fn get_certfile_path() -> String { + #[must_use]pub fn get_certfile_path() -> String { String::new() } - pub fn get_keyfile_path() -> String { + #[must_use]pub fn get_keyfile_path() -> String { String::new() } } else { - fn get_data_dir() -> PathBuf { + #[must_use] fn get_data_dir() -> PathBuf { cfg_if! { if #[cfg(target_os = "android")] { PathBuf::from(crate::intf::android::get_files_dir()) @@ -96,7 +96,7 @@ cfg_if! { } } - pub fn get_table_store_path() -> String { + #[must_use] pub fn get_table_store_path() -> String { let mut out = get_data_dir(); std::fs::create_dir_all(&out).unwrap(); @@ -105,7 +105,7 @@ cfg_if! { out.into_os_string().into_string().unwrap() } - pub fn get_block_store_path() -> String { + #[must_use] pub fn get_block_store_path() -> String { let mut out = get_data_dir(); std::fs::create_dir_all(&out).unwrap(); @@ -114,7 +114,7 @@ cfg_if! { out.into_os_string().into_string().unwrap() } - pub fn get_protected_store_path() -> String { + #[must_use] pub fn get_protected_store_path() -> String { let mut out = get_data_dir(); std::fs::create_dir_all(&out).unwrap(); @@ -123,7 +123,7 @@ cfg_if! { out.into_os_string().into_string().unwrap() } - pub fn get_certfile_path() -> String { + #[must_use]pub fn get_certfile_path() -> String { let mut out = get_data_dir(); std::fs::create_dir_all(&out).unwrap(); @@ -137,7 +137,7 @@ cfg_if! { out.into_os_string().into_string().unwrap() } - pub fn get_keyfile_path() -> String { + #[must_use]pub fn get_keyfile_path() -> String { let mut out = get_data_dir(); std::fs::create_dir_all(&out).unwrap(); @@ -307,7 +307,7 @@ pub fn get_config() -> VeilidConfig { } } -pub async fn test_config() { +pub fn test_config() { let vc = get_config(); let inner = vc.get(); @@ -426,6 +426,7 @@ pub async fn test_config() { assert_eq!(inner.network.virtual_network.server_address, ""); } +#[expect(clippy::unused_async)] pub async fn test_all() { - test_config().await; + test_config(); } diff --git a/veilid-core/src/veilid_api/api.rs b/veilid-core/src/veilid_api/api.rs index 2cc2e768..e0a0790d 100644 --- a/veilid-core/src/veilid_api/api.rs +++ b/veilid-core/src/veilid_api/api.rs @@ -35,6 +35,7 @@ impl Drop for VeilidAPIInner { /// * Create and import private routes. /// * Reply to `AppCall` RPCs. #[derive(Clone, Debug)] +#[must_use] pub struct VeilidAPI { inner: Arc>, } @@ -69,6 +70,7 @@ impl VeilidAPI { } /// Check to see if Veilid is already shut down. + #[must_use] pub fn is_shutdown(&self) -> bool { self.inner.lock().context.is_none() } @@ -154,6 +156,7 @@ impl VeilidAPI { // Attach/Detach /// Get a full copy of the current state of Veilid. + #[expect(clippy::unused_async)] pub async fn get_state(&self) -> VeilidAPIResult { let attachment_manager = self.core_context()?.attachment_manager(); let network_manager = attachment_manager.network_manager(); @@ -177,7 +180,7 @@ impl VeilidAPI { "VeilidAPI::attach()"); let attachment_manager = self.core_context()?.attachment_manager(); - if !attachment_manager.attach().await { + if !Box::pin(attachment_manager.attach()).await { apibail_generic!("Already attached"); } Ok(()) @@ -190,7 +193,7 @@ impl VeilidAPI { "VeilidAPI::detach()"); let attachment_manager = self.core_context()?.attachment_manager(); - if !attachment_manager.detach().await { + if !Box::pin(attachment_manager.detach()).await { apibail_generic!("Already detached"); } Ok(()) @@ -253,11 +256,11 @@ impl VeilidAPI { /// imported by another Veilid node. //#[instrument(target = "veilid_api", level = "debug", skip(self), ret, err)] pub async fn new_private_route(&self) -> VeilidAPIResult<(RouteId, Vec)> { - self.new_custom_private_route( + Box::pin(self.new_custom_private_route( &VALID_CRYPTO_KINDS, Stability::Reliable, Sequencing::PreferOrdered, - ) + )) .await } @@ -303,7 +306,7 @@ impl VeilidAPI { let rss = routing_table.route_spec_store(); let route_id = rss.allocate_route(crypto_kinds, &safety_spec, DirectionSet::all(), &[], false)?; - match rss.test_route(route_id).await? { + match Box::pin(rss.test_route(route_id)).await? { Some(true) => { // route tested okay } diff --git a/veilid-core/src/veilid_api/debug.rs b/veilid-core/src/veilid_api/debug.rs index 58b62189..ab7a4da0 100644 --- a/veilid-core/src/veilid_api/debug.rs +++ b/veilid-core/src/veilid_api/debug.rs @@ -17,6 +17,7 @@ pub(crate) struct DebugCache { pub opened_record_contexts: Lazy>, } +#[must_use] pub fn format_opt_ts(ts: Option) -> String { let Some(ts) = ts else { return "---".to_owned(); @@ -30,6 +31,7 @@ pub fn format_opt_ts(ts: Option) -> String { } } +#[must_use] pub fn format_opt_bps(bps: Option) -> String { let Some(bps) = bps else { return "---".to_owned(); @@ -288,7 +290,7 @@ fn get_dht_key( fn resolve_node_ref( registry: VeilidComponentRegistry, safety_selection: SafetySelection, -) -> impl FnOnce(&str) -> SendPinBoxFuture> { +) -> impl FnOnce(&str) -> PinBoxFutureStatic> { move |text| { let text = text.to_owned(); Box::pin(async move { @@ -318,7 +320,7 @@ fn resolve_node_ref( fn resolve_filtered_node_ref( registry: VeilidComponentRegistry, safety_selection: SafetySelection, -) -> impl FnOnce(&str) -> SendPinBoxFuture> { +) -> impl FnOnce(&str) -> PinBoxFutureStatic> { move |text| { let text = text.to_owned(); Box::pin(async move { @@ -503,7 +505,7 @@ fn get_debug_argument Option>( Ok(val) } -async fn async_get_debug_argument SendPinBoxFuture>>( +async fn async_get_debug_argument PinBoxFutureStatic>>( value: &str, context: &str, argument: &str, @@ -532,7 +534,7 @@ fn get_debug_argument_at Option>( Ok(val) } -async fn async_get_debug_argument_at SendPinBoxFuture>>( +async fn async_get_debug_argument_at PinBoxFutureStatic>>( debug_args: &[String], pos: usize, context: &str, @@ -549,6 +551,7 @@ async fn async_get_debug_argument_at SendPinBoxFuture) -> String { // check if message body is ascii printable let mut printable = true; @@ -588,7 +591,7 @@ pub fn print_data(data: &[u8], truncate_len: Option) -> String { } impl VeilidAPI { - async fn debug_buckets(&self, args: String) -> VeilidAPIResult { + fn debug_buckets(&self, args: String) -> VeilidAPIResult { let args: Vec = args.split_whitespace().map(|s| s.to_owned()).collect(); let mut min_state = BucketEntryState::Unreliable; if args.len() == 1 { @@ -604,12 +607,12 @@ impl VeilidAPI { Ok(routing_table.debug_info_buckets(min_state)) } - async fn debug_dialinfo(&self, _args: String) -> VeilidAPIResult { + fn debug_dialinfo(&self, _args: String) -> VeilidAPIResult { // Dump routing table dialinfo let routing_table = self.core_context()?.routing_table(); Ok(routing_table.debug_info_dialinfo()) } - async fn debug_peerinfo(&self, args: String) -> VeilidAPIResult { + fn debug_peerinfo(&self, args: String) -> VeilidAPIResult { // Dump routing table peerinfo let args: Vec = args.split_whitespace().map(|s| s.to_owned()).collect(); let routing_table = self.core_context()?.routing_table(); @@ -647,7 +650,7 @@ impl VeilidAPI { Ok(routing_table.debug_info_txtrecord().await) } - async fn debug_keypair(&self, args: String) -> VeilidAPIResult { + fn debug_keypair(&self, args: String) -> VeilidAPIResult { let args: Vec = args.split_whitespace().map(|s| s.to_owned()).collect(); let crypto = self.crypto()?; @@ -665,7 +668,7 @@ impl VeilidAPI { Ok(out) } - async fn debug_entries(&self, args: String) -> VeilidAPIResult { + fn debug_entries(&self, args: String) -> VeilidAPIResult { let args: Vec = args.split_whitespace().map(|s| s.to_owned()).collect(); let mut min_state = BucketEntryState::Unreliable; @@ -695,7 +698,7 @@ impl VeilidAPI { }) } - async fn debug_entry(&self, args: String) -> VeilidAPIResult { + fn debug_entry(&self, args: String) -> VeilidAPIResult { let args: Vec = args.split_whitespace().map(|s| s.to_owned()).collect(); let registry = self.core_context()?.registry(); @@ -782,7 +785,7 @@ impl VeilidAPI { // Dump connection table let connman = if let Some(connection_manager) = registry.network_manager().opt_connection_manager() { - connection_manager.debug_print().await + connection_manager.debug_print() } else { "Connection manager unavailable when detached".to_owned() }; @@ -790,7 +793,7 @@ impl VeilidAPI { Ok(format!("{}\n{}\n{}\n", nodeinfo, peertable, connman)) } - async fn debug_nodeid(&self, _args: String) -> VeilidAPIResult { + fn debug_nodeid(&self, _args: String) -> VeilidAPIResult { // Dump routing table entry let registry = self.core_context()?.registry(); let nodeid = registry.routing_table().debug_info_nodeid(); @@ -833,15 +836,15 @@ impl VeilidAPI { Ok("Config value set".to_owned()) } - async fn debug_restart(&self, args: String) -> VeilidAPIResult { + async fn debug_network(&self, args: String) -> VeilidAPIResult { let args = args.trim_start(); if args.is_empty() { - apibail_missing_argument!("debug_restart", "arg_0"); + apibail_missing_argument!("debug_network", "arg_0"); } let (arg, _rest) = args.split_once(' ').unwrap_or((args, "")); // let rest = rest.trim_start().to_owned(); - if arg == "network" { + if arg == "restart" { // Must be attached if matches!( self.get_state().await?.attachment.state, @@ -854,6 +857,11 @@ impl VeilidAPI { registry.network_manager().restart_network(); Ok("Network restarted".to_owned()) + } else if arg == "stats" { + let registry = self.core_context()?.registry(); + let debug_stats = registry.network_manager().debug(); + + Ok(debug_stats) } else { apibail_invalid_argument!("debug_restart", "arg_1", arg); } @@ -888,7 +896,6 @@ impl VeilidAPI { if let Some(connection_manager) = &opt_connection_manager { connection_manager .startup() - .await .map_err(VeilidAPIError::internal)?; } Ok("Connections purged".to_owned()) @@ -942,7 +949,7 @@ impl VeilidAPI { Ok("Detached".to_owned()) } - async fn debug_contact(&self, args: String) -> VeilidAPIResult { + fn debug_contact(&self, args: String) -> VeilidAPIResult { let args: Vec = args.split_whitespace().map(|s| s.to_owned()).collect(); let registry = self.core_context()?.registry(); @@ -1153,7 +1160,7 @@ impl VeilidAPI { Ok(format!("Replied with {} bytes", data_len)) } - async fn debug_route_allocate(&self, args: Vec) -> VeilidAPIResult { + fn debug_route_allocate(&self, args: Vec) -> VeilidAPIResult { // [ord|*ord] [rel] [] [in|out] [avoid_node_id] let registry = self.core_context()?.registry(); @@ -1212,7 +1219,7 @@ impl VeilidAPI { Ok(out) } - async fn debug_route_release(&self, args: Vec) -> VeilidAPIResult { + fn debug_route_release(&self, args: Vec) -> VeilidAPIResult { // let registry = self.core_context()?.registry(); let routing_table = registry.routing_table(); @@ -1233,7 +1240,7 @@ impl VeilidAPI { self.with_debug_cache(|dc| { for (n, ir) in dc.imported_routes.iter().enumerate() { if *ir == route_id { - dc.imported_routes.remove(n); + let _ = dc.imported_routes.remove(n); break; } } @@ -1245,7 +1252,7 @@ impl VeilidAPI { Ok(out) } - async fn debug_route_publish(&self, args: Vec) -> VeilidAPIResult { + fn debug_route_publish(&self, args: Vec) -> VeilidAPIResult { // [full] let registry = self.core_context()?.registry(); let routing_table = registry.routing_table(); @@ -1297,7 +1304,7 @@ impl VeilidAPI { Ok(out) } - async fn debug_route_unpublish(&self, args: Vec) -> VeilidAPIResult { + fn debug_route_unpublish(&self, args: Vec) -> VeilidAPIResult { // let registry = self.core_context()?.registry(); let routing_table = registry.routing_table(); @@ -1319,7 +1326,7 @@ impl VeilidAPI { }; Ok(out) } - async fn debug_route_print(&self, args: Vec) -> VeilidAPIResult { + fn debug_route_print(&self, args: Vec) -> VeilidAPIResult { // let registry = self.core_context()?.registry(); let routing_table = registry.routing_table(); @@ -1338,7 +1345,7 @@ impl VeilidAPI { None => Ok("Route does not exist".to_owned()), } } - async fn debug_route_list(&self, _args: Vec) -> VeilidAPIResult { + fn debug_route_list(&self, _args: Vec) -> VeilidAPIResult { // let registry = self.core_context()?.registry(); let routing_table = registry.routing_table(); @@ -1361,7 +1368,7 @@ impl VeilidAPI { Ok(out) } - async fn debug_route_import(&self, args: Vec) -> VeilidAPIResult { + fn debug_route_import(&self, args: Vec) -> VeilidAPIResult { // let registry = self.core_context()?.registry(); let routing_table = registry.routing_table(); @@ -1420,19 +1427,19 @@ impl VeilidAPI { let command = get_debug_argument_at(&args, 0, "debug_route", "command", get_string)?; if command == "allocate" { - self.debug_route_allocate(args).await + self.debug_route_allocate(args) } else if command == "release" { - self.debug_route_release(args).await + self.debug_route_release(args) } else if command == "publish" { - self.debug_route_publish(args).await + self.debug_route_publish(args) } else if command == "unpublish" { - self.debug_route_unpublish(args).await + self.debug_route_unpublish(args) } else if command == "print" { - self.debug_route_print(args).await + self.debug_route_print(args) } else if command == "list" { - self.debug_route_list(args).await + self.debug_route_list(args) } else if command == "import" { - self.debug_route_import(args).await + self.debug_route_import(args) } else if command == "test" { self.debug_route_test(args).await } else { @@ -1953,7 +1960,7 @@ impl VeilidAPI { } } - async fn debug_table_list(&self, _args: Vec) -> VeilidAPIResult { + fn debug_table_list(&self, _args: Vec) -> VeilidAPIResult { // let table_store = self.table_store()?; let table_names = table_store.list_all(); @@ -2012,7 +2019,7 @@ impl VeilidAPI { let command = get_debug_argument_at(&args, 0, "debug_table", "command", get_string)?; if command == "list" { - self.debug_table_list(args).await + self.debug_table_list(args) } else if command == "info" { self.debug_table_info(args).await } else { @@ -2020,7 +2027,7 @@ impl VeilidAPI { } } - async fn debug_punish_list(&self, _args: Vec) -> VeilidAPIResult { + fn debug_punish_list(&self, _args: Vec) -> VeilidAPIResult { // let registry = self.core_context()?.registry(); let network_manager = registry.network_manager(); @@ -2030,7 +2037,7 @@ impl VeilidAPI { Ok(out) } - async fn debug_punish_clear(&self, _args: Vec) -> VeilidAPIResult { + fn debug_punish_clear(&self, _args: Vec) -> VeilidAPIResult { // let registry = self.core_context()?.registry(); let network_manager = registry.network_manager(); @@ -2041,23 +2048,23 @@ impl VeilidAPI { Ok("Address Filter punishments cleared\n".to_owned()) } - async fn debug_punish(&self, args: String) -> VeilidAPIResult { + fn debug_punish(&self, args: String) -> VeilidAPIResult { let args: Vec = shell_words::split(&args).map_err(|e| VeilidAPIError::parse_error(e, args))?; let command = get_debug_argument_at(&args, 0, "debug_punish", "command", get_string)?; if command == "list" { - self.debug_punish_list(args).await + self.debug_punish_list(args) } else if command == "clear" { - self.debug_punish_clear(args).await + self.debug_punish_clear(args) } else { Ok(">>> Unknown command\n".to_owned()) } } /// Get the help text for 'internal debug' commands. - pub async fn debug_help(&self, _args: String) -> VeilidAPIResult { + pub fn debug_help(&self, _args: String) -> VeilidAPIResult { Ok(r#"Node Information: nodeid - display a node's id(s) nodeinfo - display detailed information about this node @@ -2089,9 +2096,12 @@ Utilities: txtrecord - Generate a TXT record for making this node into a bootstrap node capable of DNS bootstrap keypair [cryptokind] - Generate and display a random public/private keypair purge - Throw away the node's routing table, connections, or routes + +Network: attach - Attach the node to the network if it is detached detach - Detach the node from the network if it is attached - restart network - Restart the low level network + network restart - Restart the low level network + stats - Print network manager statistics RPC Operations: ping - Send a 'Status' RPC question to a destination node and display the returned ping status @@ -2177,67 +2187,70 @@ TableDB Operations: let args = args.trim_start(); if args.is_empty() { // No arguments runs help command - return self.debug_help("".to_owned()).await; + return self.debug_help("".to_owned()); } let (arg, rest) = args.split_once(' ').unwrap_or((args, "")); let rest = rest.trim_start().to_owned(); if arg == "help" { - self.debug_help(rest).await + self.debug_help(rest) } else if arg == "nodeid" { - self.debug_nodeid(rest).await + self.debug_nodeid(rest) } else if arg == "buckets" { - self.debug_buckets(rest).await + self.debug_buckets(rest) } else if arg == "dialinfo" { - self.debug_dialinfo(rest).await + self.debug_dialinfo(rest) } else if arg == "peerinfo" { - self.debug_peerinfo(rest).await - } else if arg == "txtrecord" { - self.debug_txtrecord(rest).await - } else if arg == "keypair" { - self.debug_keypair(rest).await - } else if arg == "entries" { - self.debug_entries(rest).await - } else if arg == "entry" { - self.debug_entry(rest).await - } else if arg == "relay" { - self.debug_relay(rest).await - } else if arg == "ping" { - self.debug_ping(rest).await - } else if arg == "appmessage" { - self.debug_app_message(rest).await - } else if arg == "appcall" { - self.debug_app_call(rest).await - } else if arg == "appreply" { - self.debug_app_reply(rest).await - } else if arg == "resolve" { - self.debug_resolve(rest).await + self.debug_peerinfo(rest) } else if arg == "contact" { - self.debug_contact(rest).await - } else if arg == "nodeinfo" { - self.debug_nodeinfo(rest).await - } else if arg == "purge" { - self.debug_purge(rest).await - } else if arg == "attach" { - self.debug_attach(rest).await - } else if arg == "detach" { - self.debug_detach(rest).await - } else if arg == "config" { - self.debug_config(rest).await - } else if arg == "restart" { - self.debug_restart(rest).await - } else if arg == "route" { - self.debug_route(rest).await - } else if arg == "record" { - self.debug_record(rest).await + self.debug_contact(rest) + } else if arg == "keypair" { + self.debug_keypair(rest) + } else if arg == "entries" { + self.debug_entries(rest) + } else if arg == "entry" { + self.debug_entry(rest) } else if arg == "punish" { - self.debug_punish(rest).await - } else if arg == "table" { - self.debug_table(rest).await - } else if arg == "uptime" { - self.debug_uptime(rest).await + self.debug_punish(rest) } else { - Err(VeilidAPIError::generic("Unknown debug command")) + let fut = if arg == "txtrecord" { + pin_dyn_future!(self.debug_txtrecord(rest)) + } else if arg == "relay" { + pin_dyn_future!(self.debug_relay(rest)) + } else if arg == "ping" { + pin_dyn_future!(self.debug_ping(rest)) + } else if arg == "appmessage" { + pin_dyn_future!(self.debug_app_message(rest)) + } else if arg == "appcall" { + pin_dyn_future!(self.debug_app_call(rest)) + } else if arg == "appreply" { + pin_dyn_future!(self.debug_app_reply(rest)) + } else if arg == "resolve" { + pin_dyn_future!(self.debug_resolve(rest)) + } else if arg == "nodeinfo" { + pin_dyn_future!(self.debug_nodeinfo(rest)) + } else if arg == "purge" { + pin_dyn_future!(self.debug_purge(rest)) + } else if arg == "attach" { + pin_dyn_future!(self.debug_attach(rest)) + } else if arg == "detach" { + pin_dyn_future!(self.debug_detach(rest)) + } else if arg == "config" { + pin_dyn_future!(self.debug_config(rest)) + } else if arg == "network" { + pin_dyn_future!(self.debug_network(rest)) + } else if arg == "route" { + pin_dyn_future!(self.debug_route(rest)) + } else if arg == "record" { + pin_dyn_future!(self.debug_record(rest)) + } else if arg == "table" { + pin_dyn_future!(self.debug_table(rest)) + } else if arg == "uptime" { + pin_dyn_future!(self.debug_uptime(rest)) + } else { + return Err(VeilidAPIError::generic("Unknown debug command")); + }; + fut.await } }; res @@ -2246,7 +2259,7 @@ TableDB Operations: fn get_destination( self, registry: VeilidComponentRegistry, - ) -> impl FnOnce(&str) -> SendPinBoxFuture> { + ) -> impl FnOnce(&str) -> PinBoxFutureStatic> { move |text| { let text = text.to_owned(); Box::pin(async move { @@ -2278,7 +2291,7 @@ TableDB Operations: let prid = *dc.imported_routes.get(n)?; let Some(private_route) = rss.best_remote_private_route(&prid) else { // Remove imported route - dc.imported_routes.remove(n); + let _ = dc.imported_routes.remove(n); veilid_log!(registry info "removed dead imported route {}", n); return None; }; diff --git a/veilid-core/src/veilid_api/error.rs b/veilid-core/src/veilid_api/error.rs index fd564dcf..2bebd7a0 100644 --- a/veilid-core/src/veilid_api/error.rs +++ b/veilid-core/src/veilid_api/error.rs @@ -113,6 +113,7 @@ macro_rules! apibail_already_initialized { tsify(into_wasm_abi) )] #[serde(tag = "kind")] +#[must_use] pub enum VeilidAPIError { #[error("Not initialized")] NotInitialized, diff --git a/veilid-core/src/veilid_api/json_api/process.rs b/veilid-core/src/veilid_api/json_api/process.rs index 170e0e17..d6b727f4 100644 --- a/veilid-core/src/veilid_api/json_api/process.rs +++ b/veilid-core/src/veilid_api/json_api/process.rs @@ -1,5 +1,4 @@ use super::*; -use futures_util::FutureExt; pub fn to_json_api_result( r: VeilidAPIResult, @@ -37,6 +36,7 @@ pub fn to_json_api_result_with_opt_vec_string( } } +#[must_use] pub fn to_json_api_result_with_vec_u8(r: VeilidAPIResult>) -> json_api::ApiResultWithVecU8 { match r { Err(e) => json_api::ApiResultWithVecU8::Err { error: e }, @@ -44,6 +44,7 @@ pub fn to_json_api_result_with_vec_u8(r: VeilidAPIResult>) -> json_api:: } } +#[must_use] pub fn to_json_api_result_with_vec_vec_u8( r: VeilidAPIResult>>, ) -> json_api::ApiResultWithVecVecU8 { @@ -69,6 +70,7 @@ pub struct JsonRequestProcessor { } impl JsonRequestProcessor { + #[must_use] pub fn new(api: VeilidAPI) -> Self { Self { api, @@ -212,7 +214,7 @@ impl JsonRequestProcessor { // Target // Parse target - async fn parse_target(&self, s: String) -> VeilidAPIResult { + fn parse_target(&self, s: String) -> VeilidAPIResult { // Is this a route id? if let Ok(rrid) = RouteId::from_str(&s) { let routing_table = self.api.core_context()?.routing_table(); @@ -277,18 +279,24 @@ impl JsonRequestProcessor { RoutingContextRequestOp::AppCall { target, message } => { RoutingContextResponseOp::AppCall { result: to_json_api_result_with_vec_u8( - self.parse_target(target) - .then(|tr| async { routing_context.app_call(tr?, message).await }) - .await, + async { + routing_context + .app_call(self.parse_target(target)?, message) + .await + } + .await, ), } } RoutingContextRequestOp::AppMessage { target, message } => { RoutingContextResponseOp::AppMessage { result: to_json_api_result( - self.parse_target(target) - .then(|tr| async { routing_context.app_message(tr?, message).await }) - .await, + async { + routing_context + .app_message(self.parse_target(target)?, message) + .await + } + .await, ), } } diff --git a/veilid-core/src/veilid_api/routing_context.rs b/veilid-core/src/veilid_api/routing_context.rs index 704d6b93..5e212bf4 100644 --- a/veilid-core/src/veilid_api/routing_context.rs +++ b/veilid-core/src/veilid_api/routing_context.rs @@ -4,6 +4,7 @@ use super::*; /// Valid destinations for a message sent over a routing context. #[derive(Clone, Debug, Eq, PartialEq, Hash, Copy, PartialOrd, Ord)] +#[must_use] pub enum Target { /// Node by its public key. NodeId(TypedKey), @@ -25,6 +26,7 @@ pub struct RoutingContextUnlockedInner { /// To enable receiver privacy, you should send to a private route RouteId that you have imported, rather than directly to a NodeId. /// #[derive(Clone)] +#[must_use] pub struct RoutingContext { /// Veilid API handle. api: VeilidAPI, @@ -144,10 +146,12 @@ impl RoutingContext { "RoutingContext::get_destination(self: {:?}, target: {:?})", self, target); let rpc_processor = self.api.core_context()?.rpc_processor(); - rpc_processor - .resolve_target_to_destination(target, self.unlocked_inner.safety_selection) - .await - .map_err(VeilidAPIError::invalid_target) + Box::pin( + rpc_processor + .resolve_target_to_destination(target, self.unlocked_inner.safety_selection), + ) + .await + .map_err(VeilidAPIError::invalid_target) } //////////////////////////////////////////////////////////////// @@ -172,7 +176,7 @@ impl RoutingContext { let dest = self.get_destination(target).await?; // Send app message - let answer = match rpc_processor.rpc_call_app_call(dest, message).await { + let answer = match Box::pin(rpc_processor.rpc_call_app_call(dest, message)).await { Ok(NetworkResult::Value(v)) => v, Ok(NetworkResult::Timeout) => apibail_timeout!(), Ok(NetworkResult::ServiceUnavailable(e)) => apibail_invalid_target!(e), @@ -206,7 +210,7 @@ impl RoutingContext { let dest = self.get_destination(target).await?; // Send app message - match rpc_processor.rpc_call_app_message(dest, message).await { + match Box::pin(rpc_processor.rpc_call_app_message(dest, message)).await { Ok(NetworkResult::Value(())) => {} Ok(NetworkResult::Timeout) => apibail_timeout!(), Ok(NetworkResult::ServiceUnavailable(e)) => apibail_invalid_target!(e), @@ -267,9 +271,13 @@ impl RoutingContext { Crypto::validate_crypto_kind(kind)?; let storage_manager = self.api.core_context()?.storage_manager(); - storage_manager - .create_record(kind, schema, owner, self.unlocked_inner.safety_selection) - .await + Box::pin(storage_manager.create_record( + kind, + schema, + owner, + self.unlocked_inner.safety_selection, + )) + .await } /// Opens a DHT record at a specific key. @@ -311,7 +319,7 @@ impl RoutingContext { Crypto::validate_crypto_kind(key.kind)?; let storage_manager = self.api.core_context()?.storage_manager(); - storage_manager.close_record(key).await + Box::pin(storage_manager.close_record(key)).await } /// Deletes a DHT record at a specific key. @@ -327,7 +335,7 @@ impl RoutingContext { Crypto::validate_crypto_kind(key.kind)?; let storage_manager = self.api.core_context()?.storage_manager(); - storage_manager.delete_record(key).await + Box::pin(storage_manager.delete_record(key)).await } /// Gets the latest value of a subkey. @@ -349,7 +357,7 @@ impl RoutingContext { Crypto::validate_crypto_kind(key.kind)?; let storage_manager = self.api.core_context()?.storage_manager(); - storage_manager.get_value(key, subkey, force_refresh).await + Box::pin(storage_manager.get_value(key, subkey, force_refresh)).await } /// Pushes a changed subkey value to the network. @@ -373,7 +381,7 @@ impl RoutingContext { Crypto::validate_crypto_kind(key.kind)?; let storage_manager = self.api.core_context()?.storage_manager(); - storage_manager.set_value(key, subkey, data, writer).await + Box::pin(storage_manager.set_value(key, subkey, data, writer)).await } /// Add or update a watch to a DHT value that informs the user via an VeilidUpdate::ValueChange callback when the record has subkeys change. @@ -410,9 +418,7 @@ impl RoutingContext { Crypto::validate_crypto_kind(key.kind)?; let storage_manager = self.api.core_context()?.storage_manager(); - storage_manager - .watch_values(key, subkeys, expiration, count) - .await + Box::pin(storage_manager.watch_values(key, subkeys, expiration, count)).await } /// Cancels a watch early. @@ -436,7 +442,7 @@ impl RoutingContext { Crypto::validate_crypto_kind(key.kind)?; let storage_manager = self.api.core_context()?.storage_manager(); - storage_manager.cancel_watch_values(key, subkeys).await + Box::pin(storage_manager.cancel_watch_values(key, subkeys)).await } /// Inspects a DHT record for subkey state. @@ -491,7 +497,7 @@ impl RoutingContext { Crypto::validate_crypto_kind(key.kind)?; let storage_manager = self.api.core_context()?.storage_manager(); - storage_manager.inspect_record(key, subkeys, scope).await + Box::pin(storage_manager.inspect_record(key, subkeys, scope)).await } /////////////////////////////////// diff --git a/veilid-core/src/veilid_api/tests/test_serialize_json.rs b/veilid-core/src/veilid_api/tests/test_serialize_json.rs index bf508779..903f5220 100644 --- a/veilid-core/src/veilid_api/tests/test_serialize_json.rs +++ b/veilid-core/src/veilid_api/tests/test_serialize_json.rs @@ -2,49 +2,50 @@ use super::test_types::*; use super::test_types_dht::*; use super::test_types_dht_schema::*; +#[expect(clippy::unused_async)] pub async fn test_all() { // test_types - test_alignedu64().await; - test_veilidappmessage().await; - test_veilidappcall().await; - test_fourcc().await; - test_sequencing().await; - test_stability().await; - test_safetyselection().await; - test_safetyspec().await; - test_latencystats().await; - test_transferstats().await; - test_transferstatsdownup().await; - test_rpcstats().await; - test_peerstats().await; + test_alignedu64(); + test_veilidappmessage(); + test_veilidappcall(); + test_fourcc(); + test_sequencing(); + test_stability(); + test_safetyselection(); + test_safetyspec(); + test_latencystats(); + test_transferstats(); + test_transferstatsdownup(); + test_rpcstats(); + test_peerstats(); #[cfg(feature = "unstable-tunnels")] - test_tunnelmode().await; + test_tunnelmode(); #[cfg(feature = "unstable-tunnels")] - test_tunnelerror().await; + test_tunnelerror(); #[cfg(feature = "unstable-tunnels")] - test_tunnelendpoint().await; + test_tunnelendpoint(); #[cfg(feature = "unstable-tunnels")] - test_fulltunnel().await; + test_fulltunnel(); #[cfg(feature = "unstable-tunnels")] - test_partialtunnel().await; - test_veilidloglevel().await; - test_veilidlog().await; - test_attachmentstate().await; - test_veilidstateattachment().await; - test_peertabledata().await; - test_veilidstatenetwork().await; - test_veilidroutechange().await; - test_veilidstateconfig().await; - test_veilidvaluechange().await; - test_veilidupdate().await; - test_veilidstate().await; + test_partialtunnel(); + test_veilidloglevel(); + test_veilidlog(); + test_attachmentstate(); + test_veilidstateattachment(); + test_peertabledata(); + test_veilidstatenetwork(); + test_veilidroutechange(); + test_veilidstateconfig(); + test_veilidvaluechange(); + test_veilidupdate(); + test_veilidstate(); // test_types_dht - test_dhtrecorddescriptor().await; - test_valuedata().await; - test_valuesubkeyrangeset().await; + test_dhtrecorddescriptor(); + test_valuedata(); + test_valuesubkeyrangeset(); // test_types_dht_schema - test_dhtschemadflt().await; - test_dhtschema().await; - test_dhtschemasmplmember().await; - test_dhtschemasmpl().await; + test_dhtschemadflt(); + test_dhtschema(); + test_dhtschemasmplmember(); + test_dhtschemasmpl(); } diff --git a/veilid-core/src/veilid_api/tests/test_types.rs b/veilid-core/src/veilid_api/tests/test_types.rs index 7f537018..71cc1a26 100644 --- a/veilid-core/src/veilid_api/tests/test_types.rs +++ b/veilid-core/src/veilid_api/tests/test_types.rs @@ -3,7 +3,7 @@ use crate::*; // aligned_u64 -pub async fn test_alignedu64() { +pub fn test_alignedu64() { let orig = AlignedU64::new(0x0123456789abcdef); let copy = deserialize_json(&serialize_json(orig)).unwrap(); @@ -12,7 +12,7 @@ pub async fn test_alignedu64() { // app_messsage_call -pub async fn test_veilidappmessage() { +pub fn test_veilidappmessage() { let orig = VeilidAppMessage::new( Some(fix_typedkey()), Some(fix_cryptokey()), @@ -23,7 +23,7 @@ pub async fn test_veilidappmessage() { assert_eq!(orig, copy); } -pub async fn test_veilidappcall() { +pub fn test_veilidappcall() { let orig = VeilidAppCall::new( Some(fix_typedkey()), Some(fix_cryptokey()), @@ -37,7 +37,7 @@ pub async fn test_veilidappcall() { // fourcc -pub async fn test_fourcc() { +pub fn test_fourcc() { let orig = FourCC::from_str("D34D").unwrap(); let copy = deserialize_json(&serialize_json(orig)).unwrap(); @@ -46,28 +46,28 @@ pub async fn test_fourcc() { // safety -pub async fn test_sequencing() { +pub fn test_sequencing() { let orig = Sequencing::PreferOrdered; let copy = deserialize_json(&serialize_json(orig)).unwrap(); assert_eq!(orig, copy); } -pub async fn test_stability() { +pub fn test_stability() { let orig = Stability::Reliable; let copy = deserialize_json(&serialize_json(orig)).unwrap(); assert_eq!(orig, copy); } -pub async fn test_safetyselection() { +pub fn test_safetyselection() { let orig = SafetySelection::Unsafe(Sequencing::EnsureOrdered); let copy = deserialize_json(&serialize_json(orig)).unwrap(); assert_eq!(orig, copy); } -pub async fn test_safetyspec() { +pub fn test_safetyspec() { let orig = SafetySpec { preferred_route: Some(fix_cryptokey()), hop_count: 23, @@ -81,35 +81,35 @@ pub async fn test_safetyspec() { // stats -pub async fn test_latencystats() { +pub fn test_latencystats() { let orig = fix_latencystats(); let copy = deserialize_json(&serialize_json(&orig)).unwrap(); assert_eq!(orig, copy); } -pub async fn test_transferstats() { +pub fn test_transferstats() { let orig = fix_transferstats(); let copy = deserialize_json(&serialize_json(&orig)).unwrap(); assert_eq!(orig, copy); } -pub async fn test_transferstatsdownup() { +pub fn test_transferstatsdownup() { let orig = fix_transferstatsdownup(); let copy = deserialize_json(&serialize_json(&orig)).unwrap(); assert_eq!(orig, copy); } -pub async fn test_rpcstats() { +pub fn test_rpcstats() { let orig = fix_rpcstats(); let copy = deserialize_json(&serialize_json(&orig)).unwrap(); assert_eq!(orig, copy); } -pub async fn test_peerstats() { +pub fn test_peerstats() { let orig = fix_peerstats(); let copy = deserialize_json(&serialize_json(&orig)).unwrap(); @@ -119,7 +119,7 @@ pub async fn test_peerstats() { // tunnel #[cfg(feature = "unstable-tunnels")] -pub async fn test_tunnelmode() { +pub fn test_tunnelmode() { let orig = TunnelMode::Raw; let copy = deserialize_json(&serialize_json(&orig)).unwrap(); @@ -127,7 +127,7 @@ pub async fn test_tunnelmode() { } #[cfg(feature = "unstable-tunnels")] -pub async fn test_tunnelerror() { +pub fn test_tunnelerror() { let orig = TunnelError::NoCapacity; let copy = deserialize_json(&serialize_json(&orig)).unwrap(); @@ -135,7 +135,7 @@ pub async fn test_tunnelerror() { } #[cfg(feature = "unstable-tunnels")] -pub async fn test_tunnelendpoint() { +pub fn test_tunnelendpoint() { let orig = TunnelEndpoint { mode: TunnelMode::Raw, description: "Here there be tygers.".to_string(), @@ -146,7 +146,7 @@ pub async fn test_tunnelendpoint() { } #[cfg(feature = "unstable-tunnels")] -pub async fn test_fulltunnel() { +pub fn test_fulltunnel() { let orig = FullTunnel { id: AlignedU64::from(42), timeout: AlignedU64::from(3_000_000), @@ -165,7 +165,7 @@ pub async fn test_fulltunnel() { } #[cfg(feature = "unstable-tunnels")] -pub async fn test_partialtunnel() { +pub fn test_partialtunnel() { let orig = PartialTunnel { id: AlignedU64::from(42), timeout: AlignedU64::from(3_000_000), @@ -181,14 +181,14 @@ pub async fn test_partialtunnel() { // veilid_log -pub async fn test_veilidloglevel() { +pub fn test_veilidloglevel() { let orig = VeilidLogLevel::Info; let copy = deserialize_json(&serialize_json(orig)).unwrap(); assert_eq!(orig, copy); } -pub async fn test_veilidlog() { +pub fn test_veilidlog() { let orig = VeilidLog { log_level: VeilidLogLevel::Debug, message: "A log! A log!".to_string(), @@ -201,14 +201,14 @@ pub async fn test_veilidlog() { // veilid_state -pub async fn test_attachmentstate() { +pub fn test_attachmentstate() { let orig = AttachmentState::FullyAttached; let copy = deserialize_json(&serialize_json(orig)).unwrap(); assert_eq!(orig, copy); } -pub async fn test_veilidstateattachment() { +pub fn test_veilidstateattachment() { let orig = VeilidStateAttachment { state: AttachmentState::OverAttached, public_internet_ready: true, @@ -221,14 +221,14 @@ pub async fn test_veilidstateattachment() { assert_eq!(orig, copy); } -pub async fn test_peertabledata() { +pub fn test_peertabledata() { let orig = fix_peertabledata(); let copy = deserialize_json(&serialize_json(&orig)).unwrap(); assert_eq!(orig, copy); } -pub async fn test_veilidstatenetwork() { +pub fn test_veilidstatenetwork() { let orig = VeilidStateNetwork { started: true, bps_down: ByteCount::from(14_400), @@ -240,7 +240,7 @@ pub async fn test_veilidstatenetwork() { assert_eq!(orig, copy); } -pub async fn test_veilidroutechange() { +pub fn test_veilidroutechange() { let orig = VeilidRouteChange { dead_routes: vec![fix_cryptokey()], dead_remote_routes: vec![fix_cryptokey()], @@ -250,7 +250,7 @@ pub async fn test_veilidroutechange() { assert_eq!(orig, copy); } -pub async fn test_veilidstateconfig() { +pub fn test_veilidstateconfig() { let orig = VeilidStateConfig { config: fix_veilidconfiginner(), }; @@ -259,21 +259,21 @@ pub async fn test_veilidstateconfig() { assert_eq!(orig, copy); } -pub async fn test_veilidvaluechange() { +pub fn test_veilidvaluechange() { let orig = fix_veilidvaluechange(); let copy = deserialize_json(&serialize_json(&orig)).unwrap(); assert_eq!(orig, copy); } -pub async fn test_veilidupdate() { +pub fn test_veilidupdate() { let orig = VeilidUpdate::ValueChange(Box::new(fix_veilidvaluechange())); let copy = deserialize_json(&serialize_json(&orig)).unwrap(); assert_eq!(orig, copy); } -pub async fn test_veilidstate() { +pub fn test_veilidstate() { let orig = VeilidState { attachment: Box::new(VeilidStateAttachment { state: AttachmentState::OverAttached, diff --git a/veilid-core/src/veilid_api/tests/test_types_dht.rs b/veilid-core/src/veilid_api/tests/test_types_dht.rs index a8b5aa13..fdbb4149 100644 --- a/veilid-core/src/veilid_api/tests/test_types_dht.rs +++ b/veilid-core/src/veilid_api/tests/test_types_dht.rs @@ -4,7 +4,7 @@ use range_set_blaze::*; // dht_record_descriptors -pub async fn test_dhtrecorddescriptor() { +pub fn test_dhtrecorddescriptor() { let orig = DHTRecordDescriptor::new( fix_typedkey(), fix_cryptokey(), @@ -18,7 +18,7 @@ pub async fn test_dhtrecorddescriptor() { // value_data -pub async fn test_valuedata() { +pub fn test_valuedata() { let orig = ValueData::new_with_seq(42, b"Brent Spiner".to_vec(), fix_cryptokey()); let copy = deserialize_json(&serialize_json(&orig)).unwrap(); @@ -27,7 +27,7 @@ pub async fn test_valuedata() { // value_subkey_range_set -pub async fn test_valuesubkeyrangeset() { +pub fn test_valuesubkeyrangeset() { let orig = ValueSubkeyRangeSet::new_with_data(RangeSetBlaze::from_iter([20..=30])); let copy = deserialize_json(&serialize_json(&orig)).unwrap(); diff --git a/veilid-core/src/veilid_api/tests/test_types_dht_schema.rs b/veilid-core/src/veilid_api/tests/test_types_dht_schema.rs index 885ac144..d7ddcd8b 100644 --- a/veilid-core/src/veilid_api/tests/test_types_dht_schema.rs +++ b/veilid-core/src/veilid_api/tests/test_types_dht_schema.rs @@ -3,7 +3,7 @@ use crate::*; // dlft -pub async fn test_dhtschemadflt() { +pub fn test_dhtschemadflt() { let orig = DHTSchemaDFLT::new(9); let copy = deserialize_json(&serialize_json(&orig)).unwrap(); @@ -12,7 +12,7 @@ pub async fn test_dhtschemadflt() { // mod -pub async fn test_dhtschema() { +pub fn test_dhtschema() { let orig = DHTSchema::SMPL( DHTSchemaSMPL::new( 91, @@ -36,7 +36,7 @@ pub async fn test_dhtschema() { // smpl -pub async fn test_dhtschemasmplmember() { +pub fn test_dhtschemasmplmember() { let orig = DHTSchemaSMPLMember { m_key: fix_cryptokey(), m_cnt: 7, @@ -46,7 +46,7 @@ pub async fn test_dhtschemasmplmember() { assert_eq!(orig, copy); } -pub async fn test_dhtschemasmpl() { +pub fn test_dhtschemasmpl() { let orig = DHTSchemaSMPL::new( 91, vec![ diff --git a/veilid-core/src/veilid_api/types/aligned_u64.rs b/veilid-core/src/veilid_api/types/aligned_u64.rs index efaff0d5..7465d73d 100644 --- a/veilid-core/src/veilid_api/types/aligned_u64.rs +++ b/veilid-core/src/veilid_api/types/aligned_u64.rs @@ -24,6 +24,7 @@ macro_rules! aligned_u64_type { #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] #[repr(C, align(8))] #[serde(transparent)] + #[must_use] pub struct $name( #[serde(with = "as_human_string")] #[schemars(with = "String")] @@ -49,6 +50,7 @@ macro_rules! aligned_u64_type { pub const fn new(v: u64) -> Self { Self(v) } + #[must_use] pub fn as_u64(self) -> u64 { self.0 } diff --git a/veilid-core/src/veilid_api/types/app_message_call.rs b/veilid-core/src/veilid_api/types/app_message_call.rs index 1885a240..80896e21 100644 --- a/veilid-core/src/veilid_api/types/app_message_call.rs +++ b/veilid-core/src/veilid_api/types/app_message_call.rs @@ -3,6 +3,7 @@ use super::*; /// Direct statement blob passed to hosting application for processing. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidAppMessage { #[serde(with = "as_human_opt_string")] #[schemars(with = "Option")] @@ -43,16 +44,19 @@ impl VeilidAppMessage { } /// Some(sender) if the message was sent directly, None if received via a private/safety route. + #[must_use] pub fn sender(&self) -> Option<&TypedKey> { self.sender.as_ref() } /// Some(route_id) if the message was received over a private route, None if received only a safety route or directly. + #[must_use] pub fn route_id(&self) -> Option<&RouteId> { self.route_id.as_ref() } /// The content of the message to deliver to the application. + #[must_use] pub fn message(&self) -> &[u8] { &self.message } @@ -61,6 +65,7 @@ impl VeilidAppMessage { /// Direct question blob passed to hosting application for processing to send an eventual AppReply. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidAppCall { #[serde(with = "as_human_opt_string")] #[schemars(with = "Option")] @@ -108,16 +113,19 @@ impl VeilidAppCall { } /// Some(sender) if the request was sent directly, None if received via a private/safety route. + #[must_use] pub fn sender(&self) -> Option<&TypedKey> { self.sender.as_ref() } /// Some(route_id) if the request was received over a private route, None if received only a safety route or directly. + #[must_use] pub fn route_id(&self) -> Option<&RouteId> { self.route_id.as_ref() } /// The content of the request to deliver to the application. + #[must_use] pub fn message(&self) -> &[u8] { &self.message } diff --git a/veilid-core/src/veilid_api/types/dht/dht_record_descriptor.rs b/veilid-core/src/veilid_api/types/dht/dht_record_descriptor.rs index d4422279..19ba0cf6 100644 --- a/veilid-core/src/veilid_api/types/dht/dht_record_descriptor.rs +++ b/veilid-core/src/veilid_api/types/dht/dht_record_descriptor.rs @@ -7,6 +7,7 @@ use super::*; derive(Tsify), tsify(from_wasm_abi, into_wasm_abi) )] +#[must_use] pub struct DHTRecordDescriptor { /// DHT Key = Hash(ownerKeyKind) of: [ ownerKeyValue, schema ] #[schemars(with = "String")] @@ -46,6 +47,7 @@ impl DHTRecordDescriptor { &self.owner } + #[must_use] pub fn owner_secret(&self) -> Option<&SecretKey> { self.owner_secret.as_ref() } diff --git a/veilid-core/src/veilid_api/types/dht/dht_record_report.rs b/veilid-core/src/veilid_api/types/dht/dht_record_report.rs index 4bf81b99..82896e85 100644 --- a/veilid-core/src/veilid_api/types/dht/dht_record_report.rs +++ b/veilid-core/src/veilid_api/types/dht/dht_record_report.rs @@ -7,6 +7,7 @@ use super::*; derive(Tsify), tsify(from_wasm_abi, into_wasm_abi) )] +#[must_use] pub struct DHTRecordReport { /// The actual subkey range within the schema being reported on /// This may be a subset of the requested range if it exceeds the schema limits @@ -42,9 +43,11 @@ impl DHTRecordReport { pub fn offline_subkeys(&self) -> &ValueSubkeyRangeSet { &self.offline_subkeys } + #[must_use] pub fn local_seqs(&self) -> &[ValueSeqNum] { &self.local_seqs } + #[must_use] pub fn network_seqs(&self) -> &[ValueSeqNum] { &self.network_seqs } diff --git a/veilid-core/src/veilid_api/types/dht/schema/dflt.rs b/veilid-core/src/veilid_api/types/dht/schema/dflt.rs index 7dfefab8..c3034ea7 100644 --- a/veilid-core/src/veilid_api/types/dht/schema/dflt.rs +++ b/veilid-core/src/veilid_api/types/dht/schema/dflt.rs @@ -8,6 +8,7 @@ use crate::storage_manager::{MAX_RECORD_DATA_SIZE, MAX_SUBKEY_SIZE}; derive(Tsify), tsify(from_wasm_abi) )] +#[must_use] pub struct DHTSchemaDFLT { /// Owner subkey count o_cnt: u16, @@ -33,11 +34,13 @@ impl DHTSchemaDFLT { } /// Get the owner subkey count + #[must_use] pub fn o_cnt(&self) -> u16 { self.o_cnt } /// Build the data representation of the schema + #[must_use] pub fn compile(&self) -> Vec { let mut out = Vec::::with_capacity(Self::FIXED_SIZE); // kind @@ -48,15 +51,18 @@ impl DHTSchemaDFLT { } /// Get the maximum subkey this schema allocates + #[must_use] pub fn max_subkey(&self) -> ValueSubkey { self.o_cnt as ValueSubkey - 1 } /// Get the data size of this schema beyond the size of the structure itself + #[must_use] pub fn data_size(&self) -> usize { 0 } /// Check a subkey value data against the schema + #[must_use] pub fn check_subkey_value_data( &self, owner: &PublicKey, @@ -90,6 +96,7 @@ impl DHTSchemaDFLT { } /// Check if a key is a schema member + #[must_use] pub fn is_member(&self, _key: &PublicKey) -> bool { false } diff --git a/veilid-core/src/veilid_api/types/dht/schema/mod.rs b/veilid-core/src/veilid_api/types/dht/schema/mod.rs index f60397c0..19bc613d 100644 --- a/veilid-core/src/veilid_api/types/dht/schema/mod.rs +++ b/veilid-core/src/veilid_api/types/dht/schema/mod.rs @@ -14,6 +14,7 @@ pub use smpl::*; derive(Tsify), tsify(from_wasm_abi) )] +#[must_use] pub enum DHTSchema { DFLT(DHTSchemaDFLT), SMPL(DHTSchemaSMPL), @@ -36,6 +37,7 @@ impl DHTSchema { } /// Build the data representation of the schema + #[must_use] pub fn compile(&self) -> Vec { match self { DHTSchema::DFLT(d) => d.compile(), @@ -44,6 +46,7 @@ impl DHTSchema { } /// Get maximum subkey number for this schema + #[must_use] pub fn max_subkey(&self) -> ValueSubkey { match self { DHTSchema::DFLT(d) => d.max_subkey(), @@ -52,6 +55,7 @@ impl DHTSchema { } /// Get the data size of this schema beyond the size of the structure itself + #[must_use] pub fn data_size(&self) -> usize { match self { DHTSchema::DFLT(d) => d.data_size(), @@ -60,6 +64,7 @@ impl DHTSchema { } /// Check a subkey value data against the schema + #[must_use] pub fn check_subkey_value_data( &self, owner: &PublicKey, @@ -73,6 +78,7 @@ impl DHTSchema { } /// Check if a key is a schema member + #[must_use] pub fn is_member(&self, key: &PublicKey) -> bool { match self { DHTSchema::DFLT(d) => d.is_member(key), diff --git a/veilid-core/src/veilid_api/types/dht/schema/smpl.rs b/veilid-core/src/veilid_api/types/dht/schema/smpl.rs index 03d6b96c..3a0c6b17 100644 --- a/veilid-core/src/veilid_api/types/dht/schema/smpl.rs +++ b/veilid-core/src/veilid_api/types/dht/schema/smpl.rs @@ -8,6 +8,7 @@ use crate::storage_manager::{MAX_RECORD_DATA_SIZE, MAX_SUBKEY_SIZE}; derive(Tsify), tsify(from_wasm_abi) )] +#[must_use] pub struct DHTSchemaSMPLMember { /// Member key #[schemars(with = "String")] @@ -23,6 +24,7 @@ pub struct DHTSchemaSMPLMember { derive(Tsify), tsify(from_wasm_abi) )] +#[must_use] pub struct DHTSchemaSMPL { /// Owner subkey count o_cnt: u16, @@ -58,6 +60,7 @@ impl DHTSchemaSMPL { } /// Get the owner subkey count + #[must_use] pub fn o_cnt(&self) -> u16 { self.o_cnt } @@ -68,6 +71,7 @@ impl DHTSchemaSMPL { } /// Build the data representation of the schema + #[must_use] pub fn compile(&self) -> Vec { let mut out = Vec::::with_capacity( Self::FIXED_SIZE + (self.members.len() * (PUBLIC_KEY_LENGTH + 2)), @@ -87,6 +91,7 @@ impl DHTSchemaSMPL { } /// Get the maximum subkey this schema allocates + #[must_use] pub fn max_subkey(&self) -> ValueSubkey { let subkey_count = self .members @@ -96,11 +101,13 @@ impl DHTSchemaSMPL { } /// Get the data size of this schema beyond the size of the structure itself + #[must_use] pub fn data_size(&self) -> usize { self.members.len() * mem::size_of::() } /// Check a subkey value data against the schema + #[must_use] pub fn check_subkey_value_data( &self, owner: &PublicKey, @@ -156,6 +163,7 @@ impl DHTSchemaSMPL { } /// Check if a key is a schema member + #[must_use] pub fn is_member(&self, key: &PublicKey) -> bool { for m in &self.members { if m.m_key == *key { diff --git a/veilid-core/src/veilid_api/types/dht/value_data.rs b/veilid-core/src/veilid_api/types/dht/value_data.rs index 6c7d0a82..b478665e 100644 --- a/veilid-core/src/veilid_api/types/dht/value_data.rs +++ b/veilid-core/src/veilid_api/types/dht/value_data.rs @@ -7,6 +7,7 @@ use veilid_api::VeilidAPIResult; derive(Tsify), tsify(into_wasm_abi) )] +#[must_use] pub struct ValueData { /// An increasing sequence number to time-order the DHT record changes seq: ValueSeqNum, @@ -54,6 +55,7 @@ impl ValueData { Ok(Self { seq, data, writer }) } + #[must_use] pub fn seq(&self) -> ValueSeqNum { self.seq } @@ -62,14 +64,17 @@ impl ValueData { &self.writer } + #[must_use] pub fn data(&self) -> &[u8] { &self.data } + #[must_use] pub fn data_size(&self) -> usize { self.data.len() } + #[must_use] pub fn total_size(&self) -> usize { mem::size_of::() + self.data.len() } diff --git a/veilid-core/src/veilid_api/types/dht/value_subkey_range_set.rs b/veilid-core/src/veilid_api/types/dht/value_subkey_range_set.rs index 23458a2c..1e5192d9 100644 --- a/veilid-core/src/veilid_api/types/dht/value_subkey_range_set.rs +++ b/veilid-core/src/veilid_api/types/dht/value_subkey_range_set.rs @@ -11,6 +11,7 @@ use range_set_blaze::*; tsify(from_wasm_abi, into_wasm_abi) )] #[serde(transparent)] +#[must_use] pub struct ValueSubkeyRangeSet { #[serde(with = "serialize_range_set_blaze")] #[schemars(with = "Vec<(u32,u32)>")] @@ -52,13 +53,16 @@ impl ValueSubkeyRangeSet { Self::new_with_data(&self.data | &other.data) } + #[must_use] pub fn data(&self) -> &RangeSetBlaze { &self.data } + #[must_use] pub fn into_data(self) -> RangeSetBlaze { self.data } + #[must_use] pub fn nth_subkey(&self, idx: usize) -> Option { let mut idxleft = idx; for range in self.data.ranges() { @@ -71,6 +75,7 @@ impl ValueSubkeyRangeSet { None } + #[must_use] pub fn idx_of_subkey(&self, subkey: ValueSubkey) -> Option { let mut idx = 0usize; for range in self.data.ranges() { diff --git a/veilid-core/src/veilid_api/types/fourcc.rs b/veilid-core/src/veilid_api/types/fourcc.rs index d2c630b8..2e68473c 100644 --- a/veilid-core/src/veilid_api/types/fourcc.rs +++ b/veilid-core/src/veilid_api/types/fourcc.rs @@ -6,6 +6,7 @@ use super::*; )] #[serde(try_from = "String")] #[serde(into = "String")] +#[must_use] pub struct FourCC(pub [u8; 4]); impl From<[u8; 4]> for FourCC { diff --git a/veilid-core/src/veilid_api/types/safety.rs b/veilid-core/src/veilid_api/types/safety.rs index 360f56ac..ac3db3f3 100644 --- a/veilid-core/src/veilid_api/types/safety.rs +++ b/veilid-core/src/veilid_api/types/safety.rs @@ -9,6 +9,7 @@ use super::*; derive(Tsify), tsify(from_wasm_abi, into_wasm_abi, namespace) )] +#[must_use] pub enum Sequencing { NoPreference = 0, PreferOrdered = 1, @@ -31,6 +32,7 @@ impl Default for Sequencing { derive(Tsify), tsify(from_wasm_abi, into_wasm_abi, namespace) )] +#[must_use] pub enum Stability { LowLatency = 0, Reliable = 1, @@ -52,7 +54,7 @@ impl Default for Stability { derive(Tsify), tsify(from_wasm_abi, into_wasm_abi, namespace) )] - +#[must_use] pub enum SafetySelection { /// Don't use a safety route, only specify the sequencing preference. Unsafe(Sequencing), @@ -80,6 +82,7 @@ impl Default for SafetySelection { Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema, )] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct SafetySpec { /// Preferred safety route set id if it still exists. #[schemars(with = "Option")] diff --git a/veilid-core/src/veilid_api/types/veilid_log.rs b/veilid-core/src/veilid_api/types/veilid_log.rs index 46d6a8c4..d79fdb9c 100644 --- a/veilid-core/src/veilid_api/types/veilid_log.rs +++ b/veilid-core/src/veilid_api/types/veilid_log.rs @@ -9,6 +9,7 @@ use super::*; derive(Tsify), tsify(namespace) )] +#[must_use] pub enum VeilidLogLevel { Error = 1, Warn = 2, @@ -36,6 +37,7 @@ impl VeilidLogLevel { log::Level::Trace => VeilidLogLevel::Trace, } } + #[must_use] pub fn to_tracing_level(&self) -> tracing::Level { match self { Self::Error => tracing::Level::ERROR, @@ -45,6 +47,7 @@ impl VeilidLogLevel { Self::Trace => tracing::Level::TRACE, } } + #[must_use] pub fn to_log_level(&self) -> log::Level { match self { Self::Error => log::Level::Error, diff --git a/veilid-core/src/veilid_api/types/veilid_state.rs b/veilid-core/src/veilid_api/types/veilid_state.rs index ff6afa01..ae843b31 100644 --- a/veilid-core/src/veilid_api/types/veilid_state.rs +++ b/veilid-core/src/veilid_api/types/veilid_state.rs @@ -7,6 +7,7 @@ use super::*; derive(Tsify), tsify(namespace, from_wasm_abi, into_wasm_abi) )] +#[must_use] pub enum AttachmentState { Detached = 0, Attaching = 1, @@ -18,9 +19,11 @@ pub enum AttachmentState { Detaching = 7, } impl AttachmentState { + #[must_use] pub fn is_detached(&self) -> bool { matches!(self, Self::Detached) } + #[must_use] pub fn is_attached(&self) -> bool { matches!( self, @@ -78,6 +81,7 @@ impl TryFrom<&str> for AttachmentState { /// Describe the attachment state of the Veilid node #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidStateAttachment { /// The overall quality of the routing table if attached, or the current state the attachment state machine. pub state: AttachmentState, @@ -95,6 +99,7 @@ pub struct VeilidStateAttachment { /// Describe a recently accessed peer #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct PeerTableData { /// The node ids used by this peer #[schemars(with = "Vec")] @@ -112,6 +117,7 @@ pub struct PeerTableData { /// Describe the current network state of the Veilid node #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidStateNetwork { /// If the network has been started or not. pub started: bool, @@ -127,6 +133,7 @@ pub struct VeilidStateNetwork { /// Describe a private route change that has happened #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidRouteChange { /// If a private route that was allocated has died, it is listed here. #[schemars(with = "Vec")] @@ -142,6 +149,7 @@ pub struct VeilidRouteChange { /// itself during runtime. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidStateConfig { /// If the Veilid node configuration has changed the full new config will be here. pub config: VeilidConfigInner, @@ -150,6 +158,7 @@ pub struct VeilidStateConfig { /// Describe when DHT records have subkey values changed #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidValueChange { /// The DHT Record key that changed #[schemars(with = "String")] @@ -176,6 +185,7 @@ pub struct VeilidValueChange { tsify(into_wasm_abi) )] #[serde(tag = "kind")] +#[must_use] pub enum VeilidUpdate { Log(Box), AppMessage(Box), @@ -196,6 +206,7 @@ from_impl_to_jsvalue!(VeilidUpdate); derive(Tsify), tsify(into_wasm_abi) )] +#[must_use] pub struct VeilidState { pub attachment: Box, pub network: Box, diff --git a/veilid-core/src/veilid_config.rs b/veilid-core/src/veilid_config.rs index 5fc0431e..0269a783 100644 --- a/veilid-core/src/veilid_config.rs +++ b/veilid-core/src/veilid_config.rs @@ -32,6 +32,7 @@ pub type ConfigCallback = Arc ConfigCallbackReturn + Send + Sy /// #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidConfigHTTPS { pub enabled: bool, pub listen_address: String, @@ -63,6 +64,7 @@ impl Default for VeilidConfigHTTPS { /// #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidConfigHTTP { pub enabled: bool, pub listen_address: String, @@ -90,6 +92,7 @@ impl Default for VeilidConfigHTTP { /// #[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidConfigApplication { pub https: VeilidConfigHTTPS, pub http: VeilidConfigHTTP, @@ -107,6 +110,7 @@ pub struct VeilidConfigApplication { /// #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidConfigUDP { pub enabled: bool, pub socket_pool_size: u32, @@ -145,6 +149,7 @@ impl Default for VeilidConfigUDP { /// #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidConfigTCP { pub connect: bool, pub listen: bool, @@ -188,6 +193,7 @@ impl Default for VeilidConfigTCP { /// #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidConfigWS { pub connect: bool, pub listen: bool, @@ -233,6 +239,7 @@ impl Default for VeilidConfigWS { /// #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidConfigWSS { pub connect: bool, pub listen: bool, @@ -265,6 +272,7 @@ impl Default for VeilidConfigWSS { /// #[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidConfigProtocol { pub udp: VeilidConfigUDP, pub tcp: VeilidConfigTCP, @@ -281,6 +289,7 @@ pub struct VeilidConfigProtocol { #[cfg(feature = "geolocation")] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(target_arch = "wasm32", derive(Tsify))] +#[must_use] pub struct VeilidConfigPrivacy { pub country_code_denylist: Vec, } @@ -304,6 +313,7 @@ impl Default for VeilidConfigPrivacy { #[cfg(feature = "virtual-network")] #[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(target_arch = "wasm32", derive(Tsify))] +#[must_use] pub struct VeilidConfigVirtualNetwork { pub enabled: bool, pub server_address: String, @@ -319,6 +329,7 @@ pub struct VeilidConfigVirtualNetwork { /// #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidConfigTLS { pub certificate_path: String, pub private_key_path: String, @@ -339,6 +350,7 @@ impl Default for VeilidConfigTLS { all(target_arch = "wasm32", target_os = "unknown"), allow(unused_variables) )] +#[must_use] pub fn get_default_ssl_directory( program_name: &str, organization: &str, @@ -365,6 +377,7 @@ pub fn get_default_ssl_directory( /// for correct DHT operations. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidConfigDHT { pub max_find_node_count: u32, pub resolve_node_timeout_ms: u32, @@ -449,6 +462,7 @@ impl Default for VeilidConfigDHT { /// #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidConfigRPC { pub concurrency: u32, pub queue_size: u32, @@ -479,6 +493,7 @@ impl Default for VeilidConfigRPC { /// #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidConfigRoutingTable { #[schemars(with = "Vec")] pub node_id: TypedKeyGroup, @@ -519,6 +534,7 @@ impl Default for VeilidConfigRoutingTable { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidConfigNetwork { pub connection_initial_timeout_ms: u32, pub connection_inactivity_timeout_ms: u32, @@ -578,6 +594,7 @@ impl Default for VeilidConfigNetwork { #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidConfigTableStore { pub directory: String, pub delete: bool, @@ -587,6 +604,7 @@ pub struct VeilidConfigTableStore { all(target_arch = "wasm32", target_os = "unknown"), allow(unused_variables) )] +#[must_use] fn get_default_store_path( program_name: &str, organization: &str, @@ -610,6 +628,7 @@ fn get_default_store_path( #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidConfigBlockStore { pub directory: String, pub delete: bool, @@ -626,6 +645,7 @@ impl Default for VeilidConfigBlockStore { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidConfigProtectedStore { pub allow_insecure_fallback: bool, pub always_use_insecure_storage: bool, @@ -651,6 +671,7 @@ impl Default for VeilidConfigProtectedStore { #[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidConfigCapabilities { pub disable: Vec, } @@ -661,6 +682,7 @@ pub struct VeilidConfigCapabilities { all(target_arch = "wasm32", target_os = "unknown"), tsify(namespace, from_wasm_abi) )] +#[must_use] pub enum VeilidConfigLogLevel { Off, Error, @@ -671,6 +693,7 @@ pub enum VeilidConfigLogLevel { } impl VeilidConfigLogLevel { + #[must_use] pub fn to_veilid_log_level(&self) -> Option { match self { Self::Off => None, @@ -681,6 +704,7 @@ impl VeilidConfigLogLevel { Self::Trace => Some(VeilidLogLevel::Trace), } } + #[must_use] pub fn to_tracing_level_filter(&self) -> level_filters::LevelFilter { match self { Self::Off => level_filters::LevelFilter::OFF, @@ -750,6 +774,7 @@ impl fmt::Display for VeilidConfigLogLevel { /// Top level of the Veilid configuration tree #[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] +#[must_use] pub struct VeilidConfigInner { /// An identifier used to describe the program using veilid-core. /// Used to partition storage locations in places like the ProtectedStore. @@ -857,6 +882,7 @@ impl VeilidConfigInner { /// The configuration built for each Veilid node during API startup #[derive(Clone)] +#[must_use] pub struct VeilidConfig { update_cb: UpdateCallback, inner: Arc>, @@ -879,6 +905,25 @@ impl VeilidConfig { } } + fn get_config_key( + inner_field: &mut T, + keyname: &str, + cb: ConfigCallback, + ) -> VeilidAPIResult<()> { + let v = cb(keyname.to_owned())?; + *inner_field = match v.downcast() { + Ok(v) => *v, + Err(e) => { + apibail_generic!(format!( + "incorrect type for key {}: {:?}", + keyname, + type_name_of_val(&*e) + )) + } + }; + Ok(()) + } + pub(crate) fn new_from_callback( cb: ConfigCallback, update_cb: UpdateCallback, @@ -888,18 +933,7 @@ impl VeilidConfig { // Simple config transformation macro_rules! get_config { ($key:expr) => { - let keyname = &stringify!($key)[6..]; - let v = cb(keyname.to_owned())?; - $key = match v.downcast() { - Ok(v) => *v, - Err(e) => { - apibail_generic!(format!( - "incorrect type for key {}: {:?}", - keyname, - type_name_of_val(&*e) - )) - } - }; + Self::get_config_key(&mut $key, &stringify!($key)[6..], cb.clone())?; }; } @@ -1019,6 +1053,7 @@ impl VeilidConfig { }) } + #[must_use] pub fn update_callback(&self) -> UpdateCallback { self.update_cb.clone() } @@ -1298,6 +1333,7 @@ impl VeilidConfig { } /// Return the default veilid config as a json object. +#[must_use] pub fn default_veilid_config() -> String { serialize_json(VeilidConfigInner::default()) } diff --git a/veilid-flutter/lib/veilid.dart b/veilid-flutter/lib/veilid.dart index 058899a9..bd0555d0 100644 --- a/veilid-flutter/lib/veilid.dart +++ b/veilid-flutter/lib/veilid.dart @@ -30,17 +30,6 @@ export 'veilid_table_db.dart'; ////////////////////////////////////// /// JSON Encode Helper -Object? veilidApiToEncodable(Object? value) { - if (value == null) { - return value; - } - switch (value.runtimeType) { - // case KeyPair: - // return (value as KeyPair).json; - } - throw UnsupportedError('Cannot convert to JSON: $value'); -} - List Function(dynamic) jsonListConstructor( T Function(dynamic) jsonConstructor) => (dynamic j) => (j as List).map(jsonConstructor).toList(); diff --git a/veilid-flutter/rust/Cargo.toml b/veilid-flutter/rust/Cargo.toml index 27977533..b98347de 100644 --- a/veilid-flutter/rust/Cargo.toml +++ b/veilid-flutter/rust/Cargo.toml @@ -79,3 +79,6 @@ android_log-sys = { version = "0.3.1", optional = true } # Dependencies for iOS builds only [target.'cfg(target_os = "ios")'.dependencies] oslog = { version = "0.2.0", default-features = false, optional = true } + +[lints] +workspace = true diff --git a/veilid-flutter/rust/src/lib.rs b/veilid-flutter/rust/src/lib.rs index b844dd3a..2121c5ce 100644 --- a/veilid-flutter/rust/src/lib.rs +++ b/veilid-flutter/rust/src/lib.rs @@ -1,6 +1,3 @@ -#![deny(clippy::all)] -#![allow(clippy::comparison_chain, clippy::upper_case_acronyms)] -#![deny(unused_must_use)] #![recursion_limit = "256"] mod dart_ffi; diff --git a/veilid-python/tests/test_dht.py b/veilid-python/tests/test_dht.py index 8fbf34be..ce02662b 100644 --- a/veilid-python/tests/test_dht.py +++ b/veilid-python/tests/test_dht.py @@ -541,19 +541,18 @@ async def test_dht_integration_writer_reader(): for n in range(COUNT): desc = await rc0.create_dht_record(schema) records.append(desc) + print(f' {n}: key={desc.key} owner={desc.owner_key_pair()}') await rc0.set_dht_value(desc.key, ValueSubkey(0), TEST_DATA) - print(f' {n}') - print('syncing records to the network') recleft = len(records) - for desc0 in records: + for desc in records: while True: - rr = await rc0.inspect_dht_record(desc0.key, []) + rr = await rc0.inspect_dht_record(desc.key, []) left = 0; [left := left + (x[1]-x[0]+1) for x in rr.offline_subkeys] if left == 0: - await rc0.close_dht_record(desc0.key) + await rc0.close_dht_record(desc.key) break print(f' {recleft} records {left} subkeys left') time.sleep(0.1) @@ -562,14 +561,15 @@ async def test_dht_integration_writer_reader(): # read dht records on server 1 print(f'reading {COUNT} records') n = 0 - for desc0 in records: - desc1 = await rc1.open_dht_record(desc0.key) + for desc in records: + print(f' {n}: key={desc.key} owner={desc.owner_key_pair()}') + n += 1 + + desc1 = await rc1.open_dht_record(desc.key) vd1 = await rc1.get_dht_value(desc1.key, ValueSubkey(0)) assert vd1.data == TEST_DATA await rc1.close_dht_record(desc1.key) - print(f' {n}') - n += 1 @pytest.mark.skipif(os.getenv("STRESS") != "1", reason="stress test takes a long time") diff --git a/veilid-python/veilid/json_api.py b/veilid-python/veilid/json_api.py index 5b81d7f5..5969c5ea 100644 --- a/veilid-python/veilid/json_api.py +++ b/veilid-python/veilid/json_api.py @@ -243,7 +243,6 @@ class _JsonVeilidAPI(VeilidAPI): try: reqfuture = self.in_flight_requests.pop(id, None) if reqfuture is not None: - print("ass") reqfuture.cancel() finally: self.lock.release() @@ -277,7 +276,7 @@ class _JsonVeilidAPI(VeilidAPI): writer = self.writer if self.writer is None: - return + raise AssertionError("Don't send requests on a closed VeilidAPI object") finally: self.lock.release() diff --git a/veilid-server/Cargo.toml b/veilid-server/Cargo.toml index 75d718b9..fc2612c6 100644 --- a/veilid-server/Cargo.toml +++ b/veilid-server/Cargo.toml @@ -112,3 +112,6 @@ tracing-journald = "^0.3.0" [dev-dependencies] serial_test = "^3.1.1" + +[lints] +workspace = true diff --git a/veilid-server/src/client_api.rs b/veilid-server/src/client_api.rs index 5009b3f4..dbdd16bb 100644 --- a/veilid-server/src/client_api.rs +++ b/veilid-server/src/client_api.rs @@ -208,7 +208,7 @@ impl ClientApi { } // Process control messages for the server - async fn process_control(self, args: Vec) -> VeilidAPIResult { + fn process_control(self, args: Vec) -> VeilidAPIResult { if args.is_empty() { apibail_generic!("no control request specified"); } @@ -293,7 +293,7 @@ impl ClientApi { json_api::Response { id: request.id, op: json_api::ResponseOp::Control { - result: json_api::to_json_api_result(self.process_control(args).await), + result: json_api::to_json_api_result(self.process_control(args)), }, } } else { @@ -541,7 +541,7 @@ impl ClientApi { #[instrument(level = "trace", skip(self))] pub fn run(&self, ipc_path: Option, tcp_bind_addrs: Vec) { - let mut bind_futures: Vec> = Vec::new(); + let mut bind_futures: Vec> = Vec::new(); // Local IPC if let Some(ipc_path) = ipc_path { diff --git a/veilid-server/src/main.rs b/veilid-server/src/main.rs index ff9f46e1..265071bf 100644 --- a/veilid-server/src/main.rs +++ b/veilid-server/src/main.rs @@ -1,7 +1,4 @@ #![forbid(unsafe_code)] -#![deny(clippy::all)] -#![allow(clippy::comparison_chain, clippy::upper_case_acronyms)] -#![deny(unused_must_use)] #![recursion_limit = "256"] #[cfg(all(feature = "rt-async-std", windows))] @@ -445,7 +442,7 @@ fn main() -> EyreResult<()> { run_veilid_server(settings, server_mode, veilid_logs).await }) .inspect(|_v| { - println!("{}", success); + println!("{success}"); }) .inspect_err(|_e| { println!("{}", failure); diff --git a/veilid-server/src/tools.rs b/veilid-server/src/tools.rs index 471ccdee..5f9c81f2 100644 --- a/veilid-server/src/tools.rs +++ b/veilid-server/src/tools.rs @@ -42,9 +42,15 @@ cfg_if! { // let _ = tokio::task::spawn_local(f); // } //pub use tokio::time::sleep; - //pub use tokio::time::timeout; + //pub use tokio::time::timeout pub fn block_on, T>(f: F) -> T { - let rt = tokio::runtime::Runtime::new().unwrap(); + //let rt = tokio::runtime::Runtime::new().unwrap(); + let rt = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .thread_stack_size(2048*1024) + .build() + .unwrap(); + let local = tokio::task::LocalSet::new(); local.block_on(&rt, f) } diff --git a/veilid-tools/Cargo.toml b/veilid-tools/Cargo.toml index 73fb5b26..22d6283b 100644 --- a/veilid-tools/Cargo.toml +++ b/veilid-tools/Cargo.toml @@ -202,5 +202,5 @@ build_targets = [ deployment_target = "12.0" build_id_prefix = "com.veilid.veilidtools" -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tokio_unstable)'] } +[lints] +workspace = true diff --git a/veilid-tools/src/assembly_buffer.rs b/veilid-tools/src/assembly_buffer.rs index 9287b4c6..339a9ae2 100644 --- a/veilid-tools/src/assembly_buffer.rs +++ b/veilid-tools/src/assembly_buffer.rs @@ -247,6 +247,7 @@ impl AssemblyBuffer { } } + #[must_use] pub fn new() -> Self { Self { inner: Arc::new(Mutex::new(Self::new_inner())), diff --git a/veilid-tools/src/async_tag_lock.rs b/veilid-tools/src/async_tag_lock.rs index 4375b7ee..0b8306ea 100644 --- a/veilid-tools/src/async_tag_lock.rs +++ b/veilid-tools/src/async_tag_lock.rs @@ -83,6 +83,7 @@ impl AsyncTagLockTable where T: Hash + Eq + Clone + Debug, { + #[must_use] pub fn new() -> Self { Self { inner: Arc::new(Mutex::new(AsyncTagLockTableInner { @@ -91,11 +92,13 @@ where } } + #[must_use] pub fn is_empty(&self) -> bool { let inner = self.inner.lock(); inner.table.is_empty() } + #[must_use] pub fn len(&self) -> usize { let inner = self.inner.lock(); inner.table.len() diff --git a/veilid-tools/src/deferred_stream_processor.rs b/veilid-tools/src/deferred_stream_processor.rs index 047eab3b..64fe4d87 100644 --- a/veilid-tools/src/deferred_stream_processor.rs +++ b/veilid-tools/src/deferred_stream_processor.rs @@ -9,7 +9,7 @@ use super::*; #[derive(Debug)] struct DeferredStreamProcessorInner { - opt_deferred_stream_channel: Option>>, + opt_deferred_stream_channel: Option>>, opt_stopper: Option, opt_join_handle: Option>, } @@ -23,6 +23,7 @@ pub struct DeferredStreamProcessor { impl DeferredStreamProcessor { /// Create a new DeferredStreamProcessor + #[must_use] pub fn new() -> Self { Self { inner: Mutex::new(DeferredStreamProcessorInner { @@ -34,13 +35,13 @@ impl DeferredStreamProcessor { } /// Initialize the processor before use - pub async fn init(&self) { + pub fn init(&self) { let stopper = StopSource::new(); let stop_token = stopper.token(); let mut inner = self.inner.lock(); inner.opt_stopper = Some(stopper); - let (dsc_tx, dsc_rx) = flume::unbounded::>(); + let (dsc_tx, dsc_rx) = flume::unbounded::>(); inner.opt_deferred_stream_channel = Some(dsc_tx); inner.opt_join_handle = Some(spawn( "deferred stream processor", @@ -61,8 +62,8 @@ impl DeferredStreamProcessor { } } - async fn processor(stop_token: StopToken, dsc_rx: flume::Receiver>) { - let mut unord = FuturesUnordered::>::new(); + async fn processor(stop_token: StopToken, dsc_rx: flume::Receiver>) { + let mut unord = FuturesUnordered::>::new(); // Ensure the unord never finishes unord.push(Box::pin(std::future::pending())); @@ -115,7 +116,7 @@ impl DeferredStreamProcessor { pub fn add + Unpin + Send + 'static>( &self, mut receiver: S, - mut handler: impl FnMut(T) -> SendPinBoxFuture + Send + 'static, + mut handler: impl FnMut(T) -> PinBoxFutureStatic + Send + 'static, ) -> bool { let (st, dsc_tx) = { let inner = self.inner.lock(); diff --git a/veilid-tools/src/event_bus.rs b/veilid-tools/src/event_bus.rs index d19e8f2b..ca0fe4bc 100644 --- a/veilid-tools/src/event_bus.rs +++ b/veilid-tools/src/event_bus.rs @@ -7,7 +7,7 @@ use stop_token::future::FutureExt as _; use std::any::{Any, TypeId}; type AnyEventHandler = - Arc) -> SendPinBoxFuture<()> + Send + Sync>; + Arc) -> PinBoxFutureStatic<()> + Send + Sync>; type SubscriptionId = u64; #[derive(Debug)] @@ -78,6 +78,7 @@ impl EventBus { // Public interface /// Create a new EventBus + #[must_use] pub fn new() -> Self { let (tx, rx) = flume::unbounded(); Self { @@ -91,7 +92,7 @@ impl EventBus { } /// Start up the EventBus background processor - pub async fn startup(&self) -> Result<(), StartupLockAlreadyStartedError> { + pub fn startup(&self) -> Result<(), StartupLockAlreadyStartedError> { let guard = self.unlocked_inner.startup_lock.startup()?; { let mut inner = self.inner.lock(); @@ -152,7 +153,7 @@ impl EventBus { /// Returns an subscription object that can be used to cancel this specific subscription if desired pub fn subscribe< E: Any + Send + Sync + 'static, - F: Fn(Arc) -> SendPinBoxFuture<()> + Send + Sync + 'static, + F: Fn(Arc) -> PinBoxFutureStatic<()> + Send + Sync + 'static, >( &self, handler: F, @@ -194,11 +195,13 @@ impl EventBus { } /// Returns the number of unprocessed events remaining + #[must_use] pub fn len(&self) -> usize { self.unlocked_inner.rx.len() } /// Checks if the bus has no events + #[must_use] pub fn is_empty(&self) -> bool { self.unlocked_inner.rx.is_empty() } diff --git a/veilid-tools/src/eventual.rs b/veilid-tools/src/eventual.rs index 33d5c51b..5e936060 100644 --- a/veilid-tools/src/eventual.rs +++ b/veilid-tools/src/eventual.rs @@ -41,6 +41,7 @@ impl Default for Eventual { } impl Eventual { + #[must_use] pub fn new() -> Self { Self { inner: Arc::new(Mutex::new(EventualBaseInner::new())), @@ -57,6 +58,7 @@ impl Eventual { eventual: self.clone(), } } + #[must_use] pub fn instance_none(&self) -> EventualFutureNone where T: Unpin, @@ -67,6 +69,7 @@ impl Eventual { _marker: core::marker::PhantomData {}, } } + #[must_use] pub fn instance_empty(&self) -> EventualFutureEmpty { EventualFutureEmpty { id: None, @@ -74,6 +77,7 @@ impl Eventual { } } + #[must_use] pub fn resolve(&self) -> EventualResolvedFuture { self.resolve_to_value(()) } diff --git a/veilid-tools/src/eventual_value.rs b/veilid-tools/src/eventual_value.rs index 8bf93aa6..c8dfdb89 100644 --- a/veilid-tools/src/eventual_value.rs +++ b/veilid-tools/src/eventual_value.rs @@ -34,12 +34,14 @@ impl Default for EventualValue { } impl EventualValue { + #[must_use] pub fn new() -> Self { Self { inner: Arc::new(Mutex::new(EventualBaseInner::new())), } } + #[must_use] pub fn instance(&self) -> EventualValueFuture { EventualValueFuture { id: None, @@ -51,6 +53,7 @@ impl EventualValue { self.resolve_to_value(value) } + #[must_use] pub fn take_value(&self) -> Option { let mut inner = self.inner.lock(); inner.resolved_value_mut().take() diff --git a/veilid-tools/src/eventual_value_clone.rs b/veilid-tools/src/eventual_value_clone.rs index f0c555fb..7d196b00 100644 --- a/veilid-tools/src/eventual_value_clone.rs +++ b/veilid-tools/src/eventual_value_clone.rs @@ -34,12 +34,14 @@ impl Default for EventualValueClone { } impl EventualValueClone { + #[must_use] pub fn new() -> Self { Self { inner: Arc::new(Mutex::new(EventualBaseInner::new())), } } + #[must_use] pub fn instance(&self) -> EventualValueCloneFuture where T: Clone + Unpin, @@ -54,6 +56,7 @@ impl EventualValueClone { self.resolve_to_value(value) } + #[must_use] pub fn value(&self) -> Option { let inner = self.inner.lock(); inner.resolved_value_ref().clone() diff --git a/veilid-tools/src/interval.rs b/veilid-tools/src/interval.rs index 1873bb1e..1ef404b5 100644 --- a/veilid-tools/src/interval.rs +++ b/veilid-tools/src/interval.rs @@ -3,7 +3,7 @@ use super::*; cfg_if! { if #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] { - pub fn interval(name: &str, freq_ms: u32, callback: F) -> SendPinBoxFuture<()> + pub fn interval(name: &str, freq_ms: u32, callback: F) -> PinBoxFutureStatic<()> where F: Fn() -> FUT + Send + Sync + 'static, FUT: Future + Send, @@ -25,7 +25,7 @@ cfg_if! { } else { - pub fn interval(name: &str, freq_ms: u32, callback: F) -> SendPinBoxFuture<()> + pub fn interval(name: &str, freq_ms: u32, callback: F) -> PinBoxFutureStatic<()> where F: Fn() -> FUT + Send + Sync + 'static, FUT: Future + Send, diff --git a/veilid-tools/src/ip_addr_port.rs b/veilid-tools/src/ip_addr_port.rs index 118c588a..f9b2b361 100644 --- a/veilid-tools/src/ip_addr_port.rs +++ b/veilid-tools/src/ip_addr_port.rs @@ -8,12 +8,15 @@ pub struct IpAddrPort { } impl IpAddrPort { + #[must_use] pub fn new(addr: IpAddr, port: u16) -> Self { Self { addr, port } } + #[must_use] pub fn addr(&self) -> &IpAddr { &self.addr } + #[must_use] pub fn port(&self) -> u16 { self.port } @@ -24,6 +27,7 @@ impl IpAddrPort { self.port = new_port; } + #[must_use] pub fn from_socket_addr(sa: &SocketAddr) -> Self { match sa { SocketAddr::V4(v) => Self { @@ -36,6 +40,7 @@ impl IpAddrPort { }, } } + #[must_use] pub fn to_socket_addr(&self) -> SocketAddr { match self.addr { IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, self.port)), diff --git a/veilid-tools/src/ip_extra.rs b/veilid-tools/src/ip_extra.rs index edbce74b..f66dec95 100644 --- a/veilid-tools/src/ip_extra.rs +++ b/veilid-tools/src/ip_extra.rs @@ -17,6 +17,7 @@ pub enum Ipv6MulticastScope { Global, } +#[must_use] pub fn ipaddr_is_unspecified(addr: &IpAddr) -> bool { match addr { IpAddr::V4(ip) => ipv4addr_is_unspecified(ip), @@ -24,6 +25,7 @@ pub fn ipaddr_is_unspecified(addr: &IpAddr) -> bool { } } +#[must_use] pub fn ipaddr_is_loopback(addr: &IpAddr) -> bool { match addr { IpAddr::V4(ip) => ipv4addr_is_loopback(ip), @@ -31,6 +33,7 @@ pub fn ipaddr_is_loopback(addr: &IpAddr) -> bool { } } +#[must_use] pub fn ipaddr_is_global(addr: &IpAddr) -> bool { match addr { IpAddr::V4(ip) => ipv4addr_is_global(ip), @@ -38,6 +41,7 @@ pub fn ipaddr_is_global(addr: &IpAddr) -> bool { } } +#[must_use] pub fn ipaddr_is_multicast(addr: &IpAddr) -> bool { match addr { IpAddr::V4(ip) => ipv4addr_is_multicast(ip), @@ -45,6 +49,7 @@ pub fn ipaddr_is_multicast(addr: &IpAddr) -> bool { } } +#[must_use] pub fn ipaddr_is_documentation(addr: &IpAddr) -> bool { match addr { IpAddr::V4(ip) => ipv4addr_is_documentation(ip), @@ -52,14 +57,17 @@ pub fn ipaddr_is_documentation(addr: &IpAddr) -> bool { } } +#[must_use] pub fn ipv4addr_is_unspecified(addr: &Ipv4Addr) -> bool { addr.octets() == [0u8, 0u8, 0u8, 0u8] } +#[must_use] pub fn ipv4addr_is_loopback(addr: &Ipv4Addr) -> bool { addr.octets()[0] == 127 } +#[must_use] pub fn ipv4addr_is_private(addr: &Ipv4Addr) -> bool { match addr.octets() { [10, ..] => true, @@ -69,10 +77,12 @@ pub fn ipv4addr_is_private(addr: &Ipv4Addr) -> bool { } } +#[must_use] pub fn ipv4addr_is_link_local(addr: &Ipv4Addr) -> bool { matches!(addr.octets(), [169, 254, ..]) } +#[must_use] pub fn ipv4addr_is_global(addr: &Ipv4Addr) -> bool { // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two // globally routable addresses in the 192.0.0.0/24 range. @@ -92,30 +102,37 @@ pub fn ipv4addr_is_global(addr: &Ipv4Addr) -> bool { && addr.octets()[0] != 0 } +#[must_use] pub fn ipv4addr_is_shared(addr: &Ipv4Addr) -> bool { addr.octets()[0] == 100 && (addr.octets()[1] & 0b1100_0000 == 0b0100_0000) } +#[must_use] pub fn ipv4addr_is_ietf_protocol_assignment(addr: &Ipv4Addr) -> bool { addr.octets()[0] == 192 && addr.octets()[1] == 0 && addr.octets()[2] == 0 } +#[must_use] pub fn ipv4addr_is_benchmarking(addr: &Ipv4Addr) -> bool { addr.octets()[0] == 198 && (addr.octets()[1] & 0xfe) == 18 } +#[must_use] pub fn ipv4addr_is_reserved(addr: &Ipv4Addr) -> bool { addr.octets()[0] & 240 == 240 && !addr.is_broadcast() } +#[must_use] pub fn ipv4addr_is_multicast(addr: &Ipv4Addr) -> bool { addr.octets()[0] >= 224 && addr.octets()[0] <= 239 } +#[must_use] pub fn ipv4addr_is_broadcast(addr: &Ipv4Addr) -> bool { addr.octets() == [255u8, 255u8, 255u8, 255u8] } +#[must_use] pub fn ipv4addr_is_documentation(addr: &Ipv4Addr) -> bool { matches!( addr.octets(), @@ -123,14 +140,17 @@ pub fn ipv4addr_is_documentation(addr: &Ipv4Addr) -> bool { ) } +#[must_use] pub fn ipv6addr_is_unspecified(addr: &Ipv6Addr) -> bool { addr.segments() == [0, 0, 0, 0, 0, 0, 0, 0] } +#[must_use] pub fn ipv6addr_is_loopback(addr: &Ipv6Addr) -> bool { addr.segments() == [0, 0, 0, 0, 0, 0, 0, 1] } +#[must_use] pub fn ipv6addr_is_global(addr: &Ipv6Addr) -> bool { match ipv6addr_multicast_scope(addr) { Some(Ipv6MulticastScope::Global) => true, @@ -139,10 +159,12 @@ pub fn ipv6addr_is_global(addr: &Ipv6Addr) -> bool { } } +#[must_use] pub fn ipv6addr_is_unique_local(addr: &Ipv6Addr) -> bool { (addr.segments()[0] & 0xfe00) == 0xfc00 } +#[must_use] pub fn ipv6addr_is_unicast_link_local_strict(addr: &Ipv6Addr) -> bool { addr.segments()[0] == 0xfe80 && addr.segments()[1] == 0 @@ -150,18 +172,22 @@ pub fn ipv6addr_is_unicast_link_local_strict(addr: &Ipv6Addr) -> bool { && addr.segments()[3] == 0 } +#[must_use] pub fn ipv6addr_is_unicast_link_local(addr: &Ipv6Addr) -> bool { (addr.segments()[0] & 0xffc0) == 0xfe80 } +#[must_use] pub fn ipv6addr_is_unicast_site_local(addr: &Ipv6Addr) -> bool { (addr.segments()[0] & 0xffc0) == 0xfec0 } +#[must_use] pub fn ipv6addr_is_documentation(addr: &Ipv6Addr) -> bool { (addr.segments()[0] == 0x2001) && (addr.segments()[1] == 0xdb8) } +#[must_use] pub fn ipv6addr_is_unicast_global(addr: &Ipv6Addr) -> bool { !ipv6addr_is_multicast(addr) && !ipv6addr_is_loopback(addr) @@ -171,6 +197,7 @@ pub fn ipv6addr_is_unicast_global(addr: &Ipv6Addr) -> bool { && !ipv6addr_is_documentation(addr) } +#[must_use] pub fn ipv6addr_multicast_scope(addr: &Ipv6Addr) -> Option { if ipv6addr_is_multicast(addr) { match addr.segments()[0] & 0x000f { @@ -188,6 +215,7 @@ pub fn ipv6addr_multicast_scope(addr: &Ipv6Addr) -> Option { } } +#[must_use] pub fn ipv6addr_is_multicast(addr: &Ipv6Addr) -> bool { (addr.segments()[0] & 0xff00) == 0xff00 } @@ -196,6 +224,7 @@ pub fn ipv6addr_is_multicast(addr: &Ipv6Addr) -> bool { // to the host part of the ip address // ipv4 addresses are treated as single hosts // ipv6 addresses are treated as prefix allocated blocks +#[must_use] pub fn ip_to_ipblock(ip6_prefix_size: usize, addr: IpAddr) -> IpAddr { match addr { IpAddr::V4(_) => addr, @@ -216,6 +245,7 @@ pub fn ip_to_ipblock(ip6_prefix_size: usize, addr: IpAddr) -> IpAddr { } } +#[must_use] pub fn ipaddr_apply_netmask(addr: IpAddr, netmask: IpAddr) -> IpAddr { match addr { IpAddr::V4(v4) => { @@ -257,6 +287,7 @@ pub fn ipaddr_apply_netmask(addr: IpAddr, netmask: IpAddr) -> IpAddr { } } +#[must_use] pub fn ipaddr_in_network(addr: IpAddr, netaddr: IpAddr, netmask: IpAddr) -> bool { if addr.is_ipv4() && !netaddr.is_ipv4() { return false; diff --git a/veilid-tools/src/ipc/ipc_async_std/unix.rs b/veilid-tools/src/ipc/ipc_async_std/unix.rs index 7679d246..cbc13b21 100644 --- a/veilid-tools/src/ipc/ipc_async_std/unix.rs +++ b/veilid-tools/src/ipc/ipc_async_std/unix.rs @@ -105,7 +105,8 @@ impl IpcListener { } /// Accepts a new incoming connection to this listener. - pub fn accept(&self) -> SendPinBoxFuture> { + #[must_use] + pub fn accept(&self) -> PinBoxFuture> { if self.path.is_none() { return Box::pin(std::future::ready(Err(io::Error::from( io::ErrorKind::NotConnected, diff --git a/veilid-tools/src/ipc/ipc_tokio/unix.rs b/veilid-tools/src/ipc/ipc_tokio/unix.rs index 761a2d73..873b58a4 100644 --- a/veilid-tools/src/ipc/ipc_tokio/unix.rs +++ b/veilid-tools/src/ipc/ipc_tokio/unix.rs @@ -106,6 +106,7 @@ pub struct IpcListener { impl IpcListener { /// Creates a new `IpcListener` bound to the specified path. + #[expect(clippy::unused_async)] pub async fn bind>(path: P) -> io::Result { Ok(Self { path: Some(path.as_ref().to_path_buf()), @@ -114,7 +115,8 @@ impl IpcListener { } /// Accepts a new incoming connection to this listener. - pub fn accept(&self) -> SendPinBoxFuture> { + #[must_use] + pub fn accept(&self) -> PinBoxFutureStatic> { if self.path.is_none() { return Box::pin(std::future::ready(Err(io::Error::from( io::ErrorKind::NotConnected, diff --git a/veilid-tools/src/ipc/ipc_tokio/windows.rs b/veilid-tools/src/ipc/ipc_tokio/windows.rs index 406b050e..d8e88840 100644 --- a/veilid-tools/src/ipc/ipc_tokio/windows.rs +++ b/veilid-tools/src/ipc/ipc_tokio/windows.rs @@ -116,7 +116,7 @@ impl FuturesAsyncWrite for IpcStream { pub struct IpcIncoming<'a> { listener: IpcListener, - unord: FuturesUnordered>>, + unord: FuturesUnordered>>, phantom: std::marker::PhantomData<&'a ()>, } @@ -149,6 +149,7 @@ pub struct IpcListener { impl IpcListener { /// Creates a new `IpcListener` bound to the specified path. + #[expect(clippy::unused_async)] pub async fn bind>(path: P) -> io::Result { let path = path.as_ref().to_path_buf(); let server = ServerOptions::new() @@ -161,7 +162,8 @@ impl IpcListener { } /// Accepts a new incoming connection to this listener. - pub fn accept(&self) -> SendPinBoxFuture> { + #[must_use] + pub fn accept(&self) -> PinBoxFuture> { if self.path.is_none() { return Box::pin(std::future::ready(Err(io::Error::from( io::ErrorKind::NotConnected, diff --git a/veilid-tools/src/lib.rs b/veilid-tools/src/lib.rs index fdabf632..1137601a 100644 --- a/veilid-tools/src/lib.rs +++ b/veilid-tools/src/lib.rs @@ -20,9 +20,6 @@ //! * `rt-async-std` - Uses `async-std` as the async runtime //! * `rt-wasm-bindgen` - When building for the `wasm32` architecture, use this to enable `wasm-bindgen-futures` as the async runtime //! -#![deny(clippy::all)] -#![allow(clippy::comparison_chain, clippy::upper_case_acronyms)] -#![deny(unused_must_use)] pub mod assembly_buffer; pub mod async_peek_stream; @@ -44,6 +41,7 @@ pub mod must_join_single_future; pub mod mutable_future; pub mod network_interfaces; pub mod network_result; +pub mod pin; pub mod random; pub mod single_shot_eventual; pub mod sleep; @@ -63,12 +61,6 @@ pub mod virtual_network; #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] pub mod wasm; -pub type PinBox = Pin>; -pub type PinBoxFuture = PinBox + 'static>; -pub type PinBoxFutureLifetime<'a, T> = PinBox + 'a>; -pub type SendPinBoxFuture = PinBox + Send + 'static>; -pub type SendPinBoxFutureLifetime<'a, T> = PinBox + Send + 'a>; - #[doc(no_inline)] pub use std::borrow::{Cow, ToOwned}; #[doc(no_inline)] @@ -216,6 +208,8 @@ pub use network_interfaces::*; #[doc(inline)] pub use network_result::*; #[doc(inline)] +pub use pin::*; +#[doc(inline)] pub use random::*; #[doc(inline)] pub use single_shot_eventual::*; diff --git a/veilid-tools/src/must_join_handle.rs b/veilid-tools/src/must_join_handle.rs index 0abeb399..c108c8fd 100644 --- a/veilid-tools/src/must_join_handle.rs +++ b/veilid-tools/src/must_join_handle.rs @@ -9,6 +9,7 @@ pub struct MustJoinHandle { } impl MustJoinHandle { + #[must_use] pub fn new(join_handle: LowLevelJoinHandle) -> Self { Self { join_handle: Some(join_handle), @@ -34,6 +35,10 @@ impl MustJoinHandle { } #[allow(unused_mut)] + #[cfg_attr( + all(target_arch = "wasm32", target_os = "unknown"), + expect(clippy::unused_async) + )] pub async fn abort(mut self) { if !self.completed { cfg_if! { diff --git a/veilid-tools/src/must_join_single_future.rs b/veilid-tools/src/must_join_single_future.rs index 858a6575..08eaad5a 100644 --- a/veilid-tools/src/must_join_single_future.rs +++ b/veilid-tools/src/must_join_single_future.rs @@ -35,6 +35,7 @@ impl MustJoinSingleFuture where T: 'static, { + #[must_use] pub fn new() -> Self { Self { inner: Arc::new(Mutex::new(MustJoinSingleFutureInner { diff --git a/veilid-tools/src/network_interfaces/apple.rs b/veilid-tools/src/network_interfaces/apple.rs index 0abba8f4..d15949e8 100644 --- a/veilid-tools/src/network_interfaces/apple.rs +++ b/veilid-tools/src/network_interfaces/apple.rs @@ -280,7 +280,7 @@ impl PlatformSupportApple { } } - async fn refresh_default_route_interfaces(&mut self) { + fn refresh_default_route_interfaces(&mut self) { loop { let mut mib = [CTL_NET, PF_ROUTE, 0, 0, NET_RT_FLAGS, RTF_GATEWAY]; let mut sa_tab: [*const sockaddr; RTAX_MAX as usize] = @@ -429,11 +429,12 @@ impl PlatformSupportApple { }) } + #[expect(clippy::unused_async)] pub async fn get_interfaces( &mut self, interfaces: &mut BTreeMap, ) -> io::Result<()> { - self.refresh_default_route_interfaces().await; + self.refresh_default_route_interfaces(); // Ask for all the addresses we have let ifaddrs = IfAddrs::new()?; diff --git a/veilid-tools/src/network_interfaces/mod.rs b/veilid-tools/src/network_interfaces/mod.rs index 0132a0a4..52c57ba0 100644 --- a/veilid-tools/src/network_interfaces/mod.rs +++ b/veilid-tools/src/network_interfaces/mod.rs @@ -34,12 +34,14 @@ pub enum IfAddr { } impl IfAddr { + #[must_use] pub fn ip(&self) -> IpAddr { match *self { IfAddr::V4(ref ifv4_addr) => IpAddr::V4(ifv4_addr.ip), IfAddr::V6(ref ifv6_addr) => IpAddr::V6(ifv6_addr.ip), } } + #[must_use] pub fn netmask(&self) -> IpAddr { match *self { IfAddr::V4(ref ifv4_addr) => IpAddr::V4(ifv4_addr.netmask), @@ -207,20 +209,27 @@ impl PartialOrd for InterfaceAddress { } impl InterfaceAddress { + #[must_use] pub fn new(if_addr: IfAddr, flags: AddressFlags) -> Self { Self { if_addr, flags } } + #[must_use] pub fn if_addr(&self) -> &IfAddr { &self.if_addr } + #[must_use] pub fn is_temporary(&self) -> bool { self.flags.is_temporary } + + #[must_use] pub fn is_dynamic(&self) -> bool { self.flags.is_dynamic } + + #[must_use] pub fn is_preferred(&self) -> bool { self.flags.is_preferred } @@ -257,6 +266,7 @@ impl fmt::Debug for NetworkInterface { } } impl NetworkInterface { + #[must_use] pub fn new(name: String, flags: InterfaceFlags) -> Self { Self { name, @@ -264,25 +274,31 @@ impl NetworkInterface { addrs: Vec::new(), } } + #[must_use] pub fn name(&self) -> String { self.name.clone() } + #[must_use] pub fn is_loopback(&self) -> bool { self.flags.is_loopback } + #[must_use] pub fn is_point_to_point(&self) -> bool { self.flags.is_point_to_point } + #[must_use] pub fn is_running(&self) -> bool { self.flags.is_running } + #[must_use] pub fn has_default_route(&self) -> bool { self.flags.has_default_route } + #[must_use] pub fn primary_ipv4(&self) -> Option { let mut ipv4addrs: Vec<&InterfaceAddress> = self .addrs @@ -293,6 +309,7 @@ impl NetworkInterface { ipv4addrs.last().cloned().cloned() } + #[must_use] pub fn primary_ipv6(&self) -> Option { let mut ipv6addrs: Vec<&InterfaceAddress> = self .addrs @@ -341,6 +358,7 @@ impl Default for NetworkInterfaces { } impl NetworkInterfaces { + #[must_use] pub fn new() -> Self { Self { inner: Arc::new(Mutex::new(NetworkInterfacesInner { @@ -351,6 +369,7 @@ impl NetworkInterfaces { } } + #[must_use] pub fn is_valid(&self) -> bool { let inner = self.inner.lock(); inner.valid @@ -399,6 +418,7 @@ impl NetworkInterfaces { f(&inner.interfaces) } + #[must_use] pub fn stable_addresses(&self) -> Vec { let inner = self.inner.lock(); inner.interface_address_cache.clone() diff --git a/veilid-tools/src/network_interfaces/openbsd.rs b/veilid-tools/src/network_interfaces/openbsd.rs index fc315f68..33eafa0d 100644 --- a/veilid-tools/src/network_interfaces/openbsd.rs +++ b/veilid-tools/src/network_interfaces/openbsd.rs @@ -282,7 +282,7 @@ impl PlatformSupportOpenBSD { } } - async fn refresh_default_route_interfaces(&mut self) { + fn refresh_default_route_interfaces(&mut self) { self.default_route_interfaces.clear(); let mut mib = [CTL_NET, PF_ROUTE, 0, 0, NET_RT_FLAGS, RTF_GATEWAY]; @@ -439,11 +439,12 @@ impl PlatformSupportOpenBSD { }) } + #[expect(clippy::unused_async)] pub async fn get_interfaces( &mut self, interfaces: &mut BTreeMap, ) -> io::Result<()> { - self.refresh_default_route_interfaces().await; + self.refresh_default_route_interfaces(); // Ask for all the addresses we have let ifaddrs = IfAddrs::new()?; diff --git a/veilid-tools/src/network_interfaces/sockaddr_tools.rs b/veilid-tools/src/network_interfaces/sockaddr_tools.rs index 91451714..952dc122 100644 --- a/veilid-tools/src/network_interfaces/sockaddr_tools.rs +++ b/veilid-tools/src/network_interfaces/sockaddr_tools.rs @@ -36,7 +36,7 @@ pub struct SockAddr { impl SockAddr { #[allow(clippy::new_ret_no_self)] pub fn new(sockaddr: *const sockaddr) -> Option { - NonNull::new(sockaddr as *mut _).map(|inner| Self { inner }) + NonNull::new(sockaddr.cast_mut()).map(|inner| Self { inner }) } #[cfg(not(windows))] diff --git a/veilid-tools/src/network_interfaces/wasm.rs b/veilid-tools/src/network_interfaces/wasm.rs index c2a3ec43..cdd050bb 100644 --- a/veilid-tools/src/network_interfaces/wasm.rs +++ b/veilid-tools/src/network_interfaces/wasm.rs @@ -8,6 +8,7 @@ impl PlatformSupportWasm { PlatformSupportWasm {} } + #[expect(clippy::unused_async)] pub async fn get_interfaces( &mut self, interfaces: &mut BTreeMap, diff --git a/veilid-tools/src/pin.rs b/veilid-tools/src/pin.rs new file mode 100644 index 00000000..d7ffa9fa --- /dev/null +++ b/veilid-tools/src/pin.rs @@ -0,0 +1,45 @@ +use super::*; + +pub type PinBox = Pin>; +pub type PinBoxFuture<'a, T> = PinBox + Send + 'a>; +pub type PinBoxFutureStatic = PinBoxFuture<'static, T>; + +// Pins a future to the heap and returns a concrete boxed future +// Moves the future to the heap from the caller's stack +// May allocate the future on the stack first and then move it +#[macro_export] +macro_rules! pin_future { + ($call: expr) => { + Box::pin($call) + }; +} + +// Pins a future to the heap inside a closure and returns a concrete boxed future +// Keeps the future off the calling function's stack completely +// Closure is still on the stack, but smaller than the future will be +#[macro_export] +macro_rules! pin_future_closure { + ($call: expr) => { + (|| Box::pin($call))() + }; +} + +// Pins a future to the heap and returns a dynamic boxed future +// Moves the future to the heap from the caller's stack +// May allocate the future on the stack first and then move it +#[macro_export] +macro_rules! pin_dyn_future { + ($call: expr) => { + Box::pin($call) as PinBoxFuture<_> + }; +} + +// Pins a future to the heap inside a closure and returns a dynamic boxed future +// Keeps the future off the calling function's stack completely +// Closure is still on the stack, but smaller than the future will be +#[macro_export] +macro_rules! pin_dyn_future_closure { + ($call: expr) => { + (|| Box::pin($call) as PinBoxFuture<_>)() + }; +} diff --git a/veilid-tools/src/random.rs b/veilid-tools/src/random.rs index 80fdecf4..fd07d3da 100644 --- a/veilid-tools/src/random.rs +++ b/veilid-tools/src/random.rs @@ -29,11 +29,13 @@ pub fn random_bytes(dest: &mut [u8]) { rng.fill_bytes(dest); } +#[must_use] pub fn get_random_u32() -> u32 { let mut rng = rand::thread_rng(); rng.next_u32() } +#[must_use] pub fn get_random_u64() -> u64 { let mut rng = rand::thread_rng(); rng.next_u64() diff --git a/veilid-tools/src/socket_tools.rs b/veilid-tools/src/socket_tools.rs index 12c14142..c5571570 100644 --- a/veilid-tools/src/socket_tools.rs +++ b/veilid-tools/src/socket_tools.rs @@ -279,6 +279,7 @@ async fn nonblocking_connect( } } +#[must_use] pub fn domain_for_address(address: SocketAddr) -> core::ffi::c_int { socket2::Domain::for_address(address).into() } diff --git a/veilid-tools/src/split_url.rs b/veilid-tools/src/split_url.rs index a9e24bb4..28082f33 100644 --- a/veilid-tools/src/split_url.rs +++ b/veilid-tools/src/split_url.rs @@ -300,6 +300,7 @@ impl SplitUrl { } } + #[must_use] pub fn host_port(&self, default_port: u16) -> String { format!("{}:{}", self.host, self.port.unwrap_or(default_port)) } diff --git a/veilid-tools/src/startup_lock.rs b/veilid-tools/src/startup_lock.rs index 086b2631..adb0918e 100644 --- a/veilid-tools/src/startup_lock.rs +++ b/veilid-tools/src/startup_lock.rs @@ -83,6 +83,7 @@ pub struct StartupLock { } impl StartupLock { + #[must_use] pub fn new() -> Self { Self { startup_state: Arc::new(AsyncRwLock::new(false)), diff --git a/veilid-tools/src/tests/common/test_event_bus.rs b/veilid-tools/src/tests/common/test_event_bus.rs index 65c67992..ef9395c2 100644 --- a/veilid-tools/src/tests/common/test_event_bus.rs +++ b/veilid-tools/src/tests/common/test_event_bus.rs @@ -6,18 +6,16 @@ pub async fn test_startup_shutdown() { let bus = EventBus::new(); // Normal case - bus.startup().await.expect("should startup"); + bus.startup().expect("should startup"); bus.shutdown().await; // Startup fail case - bus.startup().await.expect("should startup"); - bus.startup() - .await - .expect_err("should not startup a second time"); + bus.startup().expect("should startup"); + bus.startup().expect_err("should not startup a second time"); bus.shutdown().await; // Multiple shutdown case - bus.startup().await.expect("should startup"); + bus.startup().expect("should startup"); bus.shutdown().await; bus.shutdown().await; } @@ -38,7 +36,7 @@ pub async fn test_post() { bus.post("test").expect_err("should fail"); - bus.startup().await.expect("should startup"); + bus.startup().expect("should startup"); bus.post("test").expect("should post"); bus.post(Evt1 { field1: 0 }).expect("should post"); bus.post(Evt2 { @@ -62,7 +60,7 @@ pub async fn test_subscribe() { }); // Startup keeps existing subscriptions - bus.startup().await.expect("should startup"); + bus.startup().expect("should startup"); // Okay to subscribe at any time bus.subscribe(|evt: Arc| { @@ -97,7 +95,7 @@ pub async fn test_post_subscribe() { bus.post(Evt1 { field1: 0 }).expect_err("should fail"); // Startup keeps existing subscriptions - bus.startup().await.expect("should startup"); + bus.startup().expect("should startup"); bus.post("test").expect("should post"); bus.post(Evt1 { field1: 0 }).expect("should post"); @@ -143,7 +141,7 @@ pub async fn test_post_subscribe() { bus.post(Evt1 { field1: 0 }).expect_err("should fail"); // Startup keeps existing subscriptions - bus.startup().await.expect("should startup"); + bus.startup().expect("should startup"); // Succeeds but has no subscriptions bus.post(Evt1 { field1: 0 }).expect("should post"); diff --git a/veilid-tools/src/tests/common/test_host_interface.rs b/veilid-tools/src/tests/common/test_host_interface.rs index aa9d1dba..5ed4cbc6 100644 --- a/veilid-tools/src/tests/common/test_host_interface.rs +++ b/veilid-tools/src/tests/common/test_host_interface.rs @@ -8,11 +8,11 @@ cfg_if! { } } -pub async fn test_log() { +pub fn test_log() { info!("testing log"); } -pub async fn test_get_timestamp() { +pub fn test_get_timestamp() { info!("testing get_timestamp"); let t1 = get_timestamp(); let t2 = get_timestamp(); @@ -32,7 +32,7 @@ pub async fn test_eventual() { let jh = spawn("task", async move { sleep(1000).await; - e1.resolve(); + e1.resolve().await; }); assert_eq!(i1.await, 1u32); @@ -370,7 +370,7 @@ fn ip>(s: S) -> SplitUrlHost { SplitUrlHost::IpAddr(IpAddr::from_str(s.as_ref()).unwrap()) } -pub async fn test_split_url() { +pub fn test_split_url() { info!("testing split_url"); assert_split_url!("http://foo", "http", host("foo")); @@ -458,7 +458,7 @@ pub async fn test_split_url() { assert_split_url_parse!("s://s"); } -pub async fn test_get_random_u64() { +pub fn test_get_random_u64() { info!("testing random number generator for u64"); let t1 = get_timestamp(); let count = 10000; @@ -473,7 +473,7 @@ pub async fn test_get_random_u64() { ); } -pub async fn test_get_random_u32() { +pub fn test_get_random_u32() { info!("testing random number generator for u32"); let t1 = get_timestamp(); let count = 10000; @@ -528,7 +528,7 @@ pub async fn test_must_join_single_future() { assert_eq!(sf.check().await, Ok(None)); } -pub async fn test_tools() { +pub fn test_tools() { info!("testing retry_falloff_log"); let mut last_us = 0u64; for x in 0..1024 { @@ -541,12 +541,12 @@ pub async fn test_tools() { } pub async fn test_all() { - test_log().await; - test_get_timestamp().await; - test_tools().await; - test_split_url().await; - test_get_random_u64().await; - test_get_random_u32().await; + test_log(); + test_get_timestamp(); + test_tools(); + test_split_url(); + test_get_random_u64(); + test_get_random_u32(); test_sleep().await; #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] test_must_join_single_future().await; diff --git a/veilid-tools/src/tick_task.rs b/veilid-tools/src/tick_task.rs index 1b95f0c6..4a1da780 100644 --- a/veilid-tools/src/tick_task.rs +++ b/veilid-tools/src/tick_task.rs @@ -4,7 +4,7 @@ use core::sync::atomic::{AtomicU64, Ordering}; use once_cell::sync::OnceCell; type TickTaskRoutine = - dyn Fn(StopToken, u64, u64) -> SendPinBoxFuture> + Send + Sync + 'static; + dyn Fn(StopToken, u64, u64) -> PinBoxFutureStatic> + Send + Sync + 'static; /// Runs a single-future background processing task, attempting to run it once every 'tick period' microseconds. /// If the prior tick is still running, it will allow it to finish, and do another tick when the timer comes around again. @@ -20,6 +20,7 @@ pub struct TickTask { } impl TickTask { + #[must_use] pub fn new_us(name: &str, tick_period_us: u64) -> Self { Self { name: name.to_string(), @@ -31,6 +32,7 @@ impl TickTask { running: Arc::new(AtomicBool::new(false)), } } + #[must_use] pub fn new_ms(name: &str, tick_period_ms: u32) -> Self { Self { name: name.to_string(), @@ -42,6 +44,7 @@ impl TickTask { running: Arc::new(AtomicBool::new(false)), } } + #[must_use] pub fn new(name: &str, tick_period_sec: u32) -> Self { Self { name: name.to_string(), @@ -56,7 +59,10 @@ impl TickTask { pub fn set_routine( &self, - routine: impl Fn(StopToken, u64, u64) -> SendPinBoxFuture> + Send + Sync + 'static, + routine: impl Fn(StopToken, u64, u64) -> PinBoxFutureStatic> + + Send + + Sync + + 'static, ) { self.routine.set(Box::new(routine)).map_err(drop).unwrap(); } @@ -78,17 +84,17 @@ impl TickTask { pub async fn stop(&self) -> Result<(), E> { // drop the stop source if we have one - let opt_stop_source = &mut *self.stop_source.lock().await; - if opt_stop_source.is_none() { - // already stopped, just return - trace!(target: "veilid_tools", "tick task already stopped"); - return Ok(()); + { + let mut stop_source_guard = self.stop_source.lock().await; + if stop_source_guard.is_none() { + // already stopped, just return + return Ok(()); + } + drop(stop_source_guard.take()); } - drop(opt_stop_source.take()); // wait for completion of the tick task - trace!(target: "veilid_tools", "stopping single future"); - match self.single_future.join().await { + match pin_future!(self.single_future.join()).await { Ok(Some(Err(err))) => Err(err), _ => Ok(()), } @@ -120,11 +126,9 @@ impl TickTask { async fn internal_tick(&self, now: u64, last_timestamp_us: u64) -> Result { // Lock the stop source, tells us if we have ever started this future - let opt_stop_source_fut = self.stop_source.lock(); + let mut stop_source_guard = self.stop_source.lock().await; - let opt_stop_source = &mut *opt_stop_source_fut.await; - - if opt_stop_source.is_some() { + if stop_source_guard.is_some() { // See if the previous execution finished with an error match self.single_future.check().await { Ok(Some(Err(e))) => { @@ -172,7 +176,7 @@ impl TickTask { // Set new timer self.last_timestamp_us.store(now, Ordering::Release); // Save new stopper - *opt_stop_source = Some(stop_source); + *stop_source_guard = Some(stop_source); Ok(true) } // All other conditions should not be reachable diff --git a/veilid-tools/src/timeout_or.rs b/veilid-tools/src/timeout_or.rs index 43463e32..479bc7a3 100644 --- a/veilid-tools/src/timeout_or.rs +++ b/veilid-tools/src/timeout_or.rs @@ -10,6 +10,7 @@ use std::io; pub struct TimeoutError(); impl TimeoutError { + #[must_use] pub fn to_io(self) -> io::Error { io::Error::new(io::ErrorKind::TimedOut, self) } diff --git a/veilid-tools/src/timestamp.rs b/veilid-tools/src/timestamp.rs index 0913a1db..81b00b20 100644 --- a/veilid-tools/src/timestamp.rs +++ b/veilid-tools/src/timestamp.rs @@ -4,6 +4,7 @@ cfg_if! { if #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] { use js_sys::Date; + #[must_use] pub fn get_timestamp() -> u64 { if is_browser() { (Date::now() * 1000.0f64) as u64 @@ -12,6 +13,7 @@ cfg_if! { } } + #[must_use] pub fn display_ts(ts: u64) -> String { if is_browser() { let now = Date::new_0(); @@ -59,6 +61,7 @@ cfg_if! { use std::time::{SystemTime, UNIX_EPOCH}; use chrono::{Datelike, Timelike}; + #[must_use] pub fn get_timestamp() -> u64 { match SystemTime::now().duration_since(UNIX_EPOCH) { Ok(n) => n.as_micros() as u64, @@ -66,6 +69,7 @@ cfg_if! { } } + #[must_use] pub fn display_ts(ts: u64) -> String { let now = chrono::DateTime::::from(SystemTime::now()); let date = chrono::DateTime::::from(UNIX_EPOCH + Duration::from_micros(ts)); @@ -110,6 +114,7 @@ const MIN: u64 = 1_000_000u64 * 60; const SEC: u64 = 1_000_000u64; const MSEC: u64 = 1_000u64; +#[must_use] pub fn display_duration(dur: u64) -> String { let days = dur / DAY; let dur = dur % DAY; @@ -143,6 +148,7 @@ pub fn display_duration(dur: u64) -> String { ) } +#[must_use] pub fn parse_duration(s: &str) -> Option { let mut dur_total: u64 = 0; let mut dur: u64 = 0; diff --git a/veilid-tools/src/tools.rs b/veilid-tools/src/tools.rs index ae1dff04..eec24484 100644 --- a/veilid-tools/src/tools.rs +++ b/veilid-tools/src/tools.rs @@ -121,7 +121,7 @@ macro_rules! asyncrwlock_try_write_arc { pub fn system_boxed<'a, Out>( future: impl Future + Send + 'a, -) -> SendPinBoxFutureLifetime<'a, Out> { +) -> PinBoxFuture<'a, Out> { Box::pin(future) } @@ -129,6 +129,7 @@ pub fn system_boxed<'a, Out>( cfg_if! { if #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] { + #[must_use] pub fn get_concurrency() -> u32 { std::thread::available_parallelism() .map(|x| x.get()) @@ -156,6 +157,7 @@ pub fn split_port(name: &str) -> Result<(String, Option), String> { } } +#[must_use] pub fn prepend_slash(s: String) -> String { if s.starts_with('/') { return s; @@ -165,14 +167,17 @@ pub fn prepend_slash(s: String) -> String { out } +#[must_use] pub fn timestamp_to_secs(ts: u64) -> f64 { ts as f64 / 1000000.0f64 } +#[must_use] pub fn secs_to_timestamp(secs: f64) -> u64 { (secs * 1000000.0f64) as u64 } +#[must_use] pub fn ms_to_us(ms: u32) -> u64 { (ms as u64) * 1000u64 } @@ -182,6 +187,7 @@ pub fn us_to_ms(us: u64) -> Result { } // Calculate retry attempt with logarhythmic falloff +#[must_use] pub fn retry_falloff_log( last_us: u64, cur_us: u64, @@ -264,6 +270,7 @@ where } } +#[must_use] pub fn compatible_unspecified_socket_addr(socket_addr: &SocketAddr) -> SocketAddr { match socket_addr { SocketAddr::V4(_) => SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0), @@ -290,6 +297,7 @@ cfg_if! { } } +#[must_use] pub fn available_unspecified_addresses() -> Vec { if is_ipv6_supported() { vec![ @@ -455,6 +463,7 @@ struct AlignToEight([u8; 8]); /// # Safety /// Ensure you immediately initialize this vector as it could contain sensitive data +#[must_use] pub unsafe fn aligned_8_u8_vec_uninit(n_bytes: usize) -> Vec { let n_units = (n_bytes + mem::size_of::() - 1) / mem::size_of::(); let mut aligned: Vec = Vec::with_capacity(n_units); @@ -471,6 +480,7 @@ pub unsafe fn aligned_8_u8_vec_uninit(n_bytes: usize) -> Vec { /// # Safety /// Ensure you immediately initialize this vector as it could contain sensitive data +#[must_use] pub unsafe fn unaligned_u8_vec_uninit(n_bytes: usize) -> Vec { let mut unaligned: Vec = Vec::with_capacity(n_bytes); let ptr = unaligned.as_mut_ptr(); @@ -479,6 +489,7 @@ pub unsafe fn unaligned_u8_vec_uninit(n_bytes: usize) -> Vec { Vec::from_raw_parts(ptr, n_bytes, n_bytes) } +#[must_use] pub fn debug_backtrace() -> String { let bt = backtrace::Backtrace::new(); format!("{:?}", bt) @@ -490,6 +501,7 @@ pub fn debug_print_backtrace() { } } +#[must_use] pub fn is_debug_backtrace_enabled() -> bool { cfg_if! { if #[cfg(debug_assertions)] { diff --git a/veilid-tools/src/virtual_network/router_server/mod.rs b/veilid-tools/src/virtual_network/router_server/mod.rs index eeaeba1b..7bb74920 100644 --- a/veilid-tools/src/virtual_network/router_server/mod.rs +++ b/veilid-tools/src/virtual_network/router_server/mod.rs @@ -36,14 +36,14 @@ pub const DEFAULT_VIRTUAL_ROUTER_PORT_TCP: u16 = 5149u16; pub const DEFAULT_VIRTUAL_ROUTER_PORT_WS: u16 = 5148u16; enum RunLoopEvent { - AddClient(SendPinBoxFuture), + AddClient(PinBoxFuture), Done, } #[derive(Debug)] struct RouterServerUnlockedInner { - new_client_sender: flume::Sender>, - new_client_receiver: flume::Receiver>, + new_client_sender: flume::Sender>, + new_client_receiver: flume::Receiver>, server_processor: ServerProcessor, global_state_manager: GlobalStateManager, } @@ -257,7 +257,7 @@ impl RouterServer { /// Run the router server until a stop is requested pub async fn run(&self, stop_token: StopToken) -> RouterServerResult<()> { - let mut unord = FuturesUnordered::>::new(); + let mut unord = FuturesUnordered::>::new(); let mut need_new_client_fut = true; diff --git a/veilid-tools/src/virtual_network/router_server/server_processor.rs b/veilid-tools/src/virtual_network/router_server/server_processor.rs index e2379a26..5e5a693e 100644 --- a/veilid-tools/src/virtual_network/router_server/server_processor.rs +++ b/veilid-tools/src/virtual_network/router_server/server_processor.rs @@ -57,7 +57,7 @@ impl ServerProcessor { } } - pub fn run_loop_process_commands(&self) -> SendPinBoxFuture { + pub fn run_loop_process_commands(&self) -> PinBoxFuture { let receiver_stream = self.unlocked_inner.receiver.clone().into_stream(); let this = self.clone(); Box::pin(async move { diff --git a/veilid-tools/src/virtual_network/virtual_tcp_listener_stream.rs b/veilid-tools/src/virtual_network/virtual_tcp_listener_stream.rs index 31d79315..7524daef 100644 --- a/veilid-tools/src/virtual_network/virtual_tcp_listener_stream.rs +++ b/veilid-tools/src/virtual_network/virtual_tcp_listener_stream.rs @@ -11,7 +11,7 @@ use std::io; /// [`Stream`]: trait@futures_util::stream::Stream pub struct VirtualTcpListenerStream { inner: VirtualTcpListener, - current_accept_fut: Option>>, + current_accept_fut: Option>>, } impl fmt::Debug for VirtualTcpListenerStream { diff --git a/veilid-tools/src/virtual_network/virtual_tcp_stream.rs b/veilid-tools/src/virtual_network/virtual_tcp_stream.rs index 6cb63dc8..4a56b74b 100644 --- a/veilid-tools/src/virtual_network/virtual_tcp_stream.rs +++ b/veilid-tools/src/virtual_network/virtual_tcp_stream.rs @@ -15,9 +15,9 @@ pub struct VirtualTcpStream { socket_id: SocketId, local_address: SocketAddr, remote_address: SocketAddr, - current_recv_fut: Option, VirtualNetworkError>>>, - current_send_fut: Option>>, - current_tcp_shutdown_fut: Option>>, + current_recv_fut: Option, VirtualNetworkError>>>, + current_send_fut: Option>>, + current_tcp_shutdown_fut: Option>>, } impl fmt::Debug for VirtualTcpStream { diff --git a/veilid-tools/src/wasm.rs b/veilid-tools/src/wasm.rs index 5d854931..6340d0e6 100644 --- a/veilid-tools/src/wasm.rs +++ b/veilid-tools/src/wasm.rs @@ -57,6 +57,7 @@ pub fn get_wasm_global_string_value>(key: K) -> Option { #[error("JsValue error")] pub struct JsValueError(String); +#[must_use] pub fn map_jsvalue_error(x: JsValue) -> JsValueError { JsValueError(x.as_string().unwrap_or_default()) } @@ -92,6 +93,7 @@ pub fn get_concurrency() -> u32 { res } +#[must_use] pub fn ws_err_to_io_error(err: WsErr) -> io::Error { match err { WsErr::InvalidWsState { supplied: _ } => { diff --git a/veilid-wasm/Cargo.toml b/veilid-wasm/Cargo.toml index 732110c1..9a21ed4c 100644 --- a/veilid-wasm/Cargo.toml +++ b/veilid-wasm/Cargo.toml @@ -48,3 +48,6 @@ serde-wasm-bindgen = "0.6.5" [dev-dependencies] wasm-bindgen-test = "^0" parking_lot = "0.12.3" + +[lints] +workspace = true diff --git a/veilid-wasm/src/lib.rs b/veilid-wasm/src/lib.rs index 7bf2a5ca..c7cc3c79 100644 --- a/veilid-wasm/src/lib.rs +++ b/veilid-wasm/src/lib.rs @@ -1,9 +1,6 @@ -// wasm-bindgen and clippy don't play well together yet -#![deny(clippy::all)] -#![allow(clippy::comparison_chain, clippy::upper_case_acronyms)] -#![deny(unused_must_use)] #![cfg(all(target_arch = "wasm32", target_os = "unknown"))] #![no_std] +#![recursion_limit = "256"] /// Veilid WASM Bindings for Flutter/Dart, as well as Native Javascript /// The Flutter/Dart bindings are in this lib.rs directly @@ -82,6 +79,7 @@ pub fn unmarshall(b64: String) -> APIResult> { }) } +#[must_use] pub fn marshall(data: &[u8]) -> String { data_encoding::BASE64URL_NOPAD.encode(data) } @@ -381,6 +379,7 @@ pub fn routing_context() -> Promise { } #[wasm_bindgen()] +#[must_use] pub fn release_routing_context(id: u32) -> i32 { let mut rc = (*ROUTING_CONTEXTS).borrow_mut(); if rc.remove(&id).is_none() { @@ -390,6 +389,7 @@ pub fn release_routing_context(id: u32) -> i32 { } #[wasm_bindgen()] +#[must_use] pub fn routing_context_with_default_safety(id: u32) -> u32 { let routing_context = { let rc = (*ROUTING_CONTEXTS).borrow(); @@ -405,6 +405,7 @@ pub fn routing_context_with_default_safety(id: u32) -> u32 { } #[wasm_bindgen()] +#[must_use] pub fn routing_context_with_safety(id: u32, safety_selection: String) -> u32 { let safety_selection: veilid_core::SafetySelection = veilid_core::deserialize_json(&safety_selection).unwrap(); @@ -423,6 +424,7 @@ pub fn routing_context_with_safety(id: u32, safety_selection: String) -> u32 { } #[wasm_bindgen()] +#[must_use] pub fn routing_context_with_sequencing(id: u32, sequencing: String) -> u32 { let sequencing: veilid_core::Sequencing = veilid_core::deserialize_json(&sequencing).unwrap(); @@ -778,6 +780,7 @@ pub fn open_table_db(name: String, column_count: u32) -> Promise { } #[wasm_bindgen()] +#[must_use] pub fn release_table_db(id: u32) -> i32 { let mut tdbs = (*TABLE_DBS).borrow_mut(); if tdbs.remove(&id).is_none() { @@ -800,6 +803,7 @@ pub fn delete_table_db(name: String) -> Promise { } #[wasm_bindgen()] +#[must_use] pub fn table_db_get_column_count(id: u32) -> u32 { let table_dbs = (*TABLE_DBS).borrow(); let Some(table_db) = table_dbs.get(&id) else { @@ -846,6 +850,7 @@ fn add_table_db_transaction(tdbt: veilid_core::TableDBTransaction) -> u32 { } #[wasm_bindgen()] +#[must_use] pub fn table_db_transact(id: u32) -> u32 { let table_dbs = (*TABLE_DBS).borrow(); let Some(table_db) = table_dbs.get(&id) else { @@ -856,6 +861,7 @@ pub fn table_db_transact(id: u32) -> u32 { } #[wasm_bindgen()] +#[must_use] pub fn release_table_db_transaction(id: u32) -> i32 { let mut tdbts = (*TABLE_DB_TRANSACTIONS).borrow_mut(); if tdbts.remove(&id).is_none() { @@ -973,6 +979,7 @@ pub fn table_db_delete(id: u32, col: u32, key: String) -> Promise { } #[wasm_bindgen()] +#[must_use] pub fn valid_crypto_kinds() -> String { veilid_core::serialize_json( veilid_core::VALID_CRYPTO_KINDS @@ -983,6 +990,7 @@ pub fn valid_crypto_kinds() -> String { } #[wasm_bindgen()] +#[must_use] pub fn best_crypto_kind() -> u32 { veilid_core::best_crypto_kind().into() } @@ -1586,6 +1594,7 @@ pub fn crypto_crypt_no_auth( } #[wasm_bindgen()] +#[must_use] pub fn now() -> String { veilid_core::Timestamp::now().as_u64().to_string() } @@ -1600,6 +1609,7 @@ pub fn debug(command: String) -> Promise { } #[wasm_bindgen()] +#[must_use] pub fn veilid_version_string() -> String { veilid_core::veilid_version_string() } @@ -1614,6 +1624,7 @@ pub struct VeilidVersion { } #[wasm_bindgen()] +#[must_use] pub fn veilid_version() -> JsValue { let (major, minor, patch) = veilid_core::veilid_version(); let vv = VeilidVersion { @@ -1625,6 +1636,7 @@ pub fn veilid_version() -> JsValue { } #[wasm_bindgen()] +#[must_use] pub fn default_veilid_config() -> String { veilid_core::default_veilid_config() } diff --git a/veilid-wasm/src/veilid_client_js.rs b/veilid-wasm/src/veilid_client_js.rs index 80dbcf82..40a62586 100644 --- a/veilid-wasm/src/veilid_client_js.rs +++ b/veilid-wasm/src/veilid_client_js.rs @@ -29,6 +29,7 @@ pub struct VeilidClient {} // this is just a namespace/class of static functions. #[wasm_bindgen(js_class = veilidClient)] impl VeilidClient { + #[allow(clippy::unused_async)] pub async fn initializeCore(platformConfig: VeilidWASMConfig) { if INITIALIZED.swap(true, Ordering::AcqRel) { return; @@ -181,6 +182,7 @@ impl VeilidClient { } /// Get the current timestamp, in string format + #[must_use] pub fn now() -> String { veilid_core::Timestamp::now().as_u64().to_string() } @@ -193,6 +195,7 @@ impl VeilidClient { } /// Return the cargo package version of veilid-core, in object format. + #[must_use] pub fn version() -> VeilidVersion { let (major, minor, patch) = veilid_core::veilid_version(); super::VeilidVersion { @@ -203,11 +206,13 @@ impl VeilidClient { } /// Return the cargo package version of veilid-core, in string format. + #[must_use] pub fn versionString() -> String { veilid_core::veilid_version_string() } /// Return the default veilid configuration, in string format + #[must_use] pub fn defaultConfig() -> String { veilid_core::default_veilid_config() } diff --git a/veilid-wasm/src/veilid_crypto_js.rs b/veilid-wasm/src/veilid_crypto_js.rs index 55c4d82d..15bffaea 100644 --- a/veilid-wasm/src/veilid_crypto_js.rs +++ b/veilid-wasm/src/veilid_crypto_js.rs @@ -9,6 +9,7 @@ pub struct VeilidCrypto {} // this is just a namespace/class of static functions. #[wasm_bindgen(js_class = veilidCrypto)] impl VeilidCrypto { + #[must_use] pub fn validCryptoKinds() -> StringArray { let res = veilid_core::VALID_CRYPTO_KINDS .iter() @@ -17,6 +18,7 @@ impl VeilidCrypto { into_unchecked_string_array(res) } + #[must_use] pub fn bestCryptoKind() -> String { veilid_core::best_crypto_kind().to_string() } @@ -518,96 +520,112 @@ impl VeilidCrypto { /// Length of a crypto key in bytes #[wasm_bindgen(getter)] + #[must_use] pub fn CRYPTO_KEY_LENGTH() -> usize { veilid_core::CRYPTO_KEY_LENGTH } /// Length of a crypto key in bytes after encoding to base64url #[wasm_bindgen(getter)] + #[must_use] pub fn CRYPTO_KEY_LENGTH_ENCODED() -> usize { veilid_core::CRYPTO_KEY_LENGTH_ENCODED } /// Length of a hash digest in bytes #[wasm_bindgen(getter)] + #[must_use] pub fn HASH_DIGEST_LENGTH() -> usize { veilid_core::HASH_DIGEST_LENGTH } /// Length of a hash digest in bytes after encoding to base64url #[wasm_bindgen(getter)] + #[must_use] pub fn HASH_DIGEST_LENGTH_ENCODED() -> usize { veilid_core::HASH_DIGEST_LENGTH_ENCODED } /// Length of a nonce in bytes #[wasm_bindgen(getter)] + #[must_use] pub fn NONCE_LENGTH() -> usize { veilid_core::NONCE_LENGTH } /// Length of a nonce in bytes after encoding to base64url #[wasm_bindgen(getter)] + #[must_use] pub fn NONCE_LENGTH_ENCODED() -> usize { veilid_core::NONCE_LENGTH_ENCODED } /// Length of a crypto key in bytes #[wasm_bindgen(getter)] + #[must_use] pub fn PUBLIC_KEY_LENGTH() -> usize { veilid_core::PUBLIC_KEY_LENGTH } /// Length of a crypto key in bytes after encoding to base64url #[wasm_bindgen(getter)] + #[must_use] pub fn PUBLIC_KEY_LENGTH_ENCODED() -> usize { veilid_core::PUBLIC_KEY_LENGTH_ENCODED } /// Length of a route id in bytes #[wasm_bindgen(getter)] + #[must_use] pub fn ROUTE_ID_LENGTH() -> usize { veilid_core::ROUTE_ID_LENGTH } /// Length of a route id in bytes after encoding to base64url #[wasm_bindgen(getter)] + #[must_use] pub fn ROUTE_ID_LENGTH_ENCODED() -> usize { veilid_core::ROUTE_ID_LENGTH_ENCODED } /// Length of a secret key in bytes #[wasm_bindgen(getter)] + #[must_use] pub fn SECRET_KEY_LENGTH() -> usize { veilid_core::SECRET_KEY_LENGTH } /// Length of a secret key in bytes after encoding to base64url #[wasm_bindgen(getter)] + #[must_use] pub fn SECRET_KEY_LENGTH_ENCODED() -> usize { veilid_core::SECRET_KEY_LENGTH_ENCODED } /// Length of a shared secret in bytes #[wasm_bindgen(getter)] + #[must_use] pub fn SHARED_SECRET_LENGTH() -> usize { veilid_core::SHARED_SECRET_LENGTH } /// Length of a shared secret in bytes after encoding to base64url #[wasm_bindgen(getter)] + #[must_use] pub fn SHARED_SECRET_LENGTH_ENCODED() -> usize { veilid_core::SHARED_SECRET_LENGTH_ENCODED } /// Length of a signature in bytes #[wasm_bindgen(getter)] + #[must_use] pub fn SIGNATURE_LENGTH() -> usize { veilid_core::SIGNATURE_LENGTH } /// Length of a signature in bytes after encoding to base64url #[wasm_bindgen(getter)] + #[must_use] pub fn SIGNATURE_LENGTH_ENCODED() -> usize { veilid_core::SIGNATURE_LENGTH_ENCODED } diff --git a/veilid-wasm/src/veilid_routing_context_js.rs b/veilid-wasm/src/veilid_routing_context_js.rs index e2433b4d..484d0246 100644 --- a/veilid-wasm/src/veilid_routing_context_js.rs +++ b/veilid-wasm/src/veilid_routing_context_js.rs @@ -193,6 +193,7 @@ impl VeilidRoutingContext { /// DHT Records /// Deterministicly builds the record key for a given schema and owner public key + #[allow(clippy::unused_async)] pub async fn getDhtRecordKey( &self, schema: DHTSchema, diff --git a/veilid-wasm/src/veilid_table_db_js.rs b/veilid-wasm/src/veilid_table_db_js.rs index 1120fab5..971d25d5 100644 --- a/veilid-wasm/src/veilid_table_db_js.rs +++ b/veilid-wasm/src/veilid_table_db_js.rs @@ -13,6 +13,7 @@ impl VeilidTableDB { /// If the column count is greater than an existing TableDB's column count, /// the database will be upgraded to add the missing columns. #[wasm_bindgen(constructor)] + #[must_use] pub fn new(tableName: String, columnCount: u32) -> Self { Self { inner_table_db: None, @@ -139,6 +140,7 @@ impl VeilidTableDBTransaction { /// Use `.createTransaction()` on an instance of `VeilidTableDB` instead. /// @deprecated #[wasm_bindgen(constructor)] + #[must_use] pub fn new() -> Self { Self { inner_transaction: None,