From eb4a4d81f82c1ddd5ea215ee61e2100489e15fcb Mon Sep 17 00:00:00 2001 From: Jasmin Bom Date: Sun, 15 Mar 2026 14:28:56 +0100 Subject: [PATCH 01/10] Make async manager a trait with global instance and spawn macro --- crates/buttplug_core/Cargo.toml | 10 +- .../src/connector/remote_connector.rs | 2 +- .../src/connector/transport/stream.rs | 2 +- .../src/util/async_manager/dummy.rs | 35 ------- .../src/util/async_manager/mod.rs | 95 ++++++++++++++++--- .../src/util/async_manager/tokio.rs | 38 ++------ .../src/util/async_manager/wasm.rs | 23 +++++ .../src/util/async_manager/wasm_bindgen.rs | 38 -------- crates/buttplug_core/src/util/mod.rs | 5 - 9 files changed, 126 insertions(+), 122 deletions(-) delete mode 100644 crates/buttplug_core/src/util/async_manager/dummy.rs create mode 100644 crates/buttplug_core/src/util/async_manager/wasm.rs delete mode 100644 crates/buttplug_core/src/util/async_manager/wasm_bindgen.rs diff --git a/crates/buttplug_core/Cargo.toml b/crates/buttplug_core/Cargo.toml index 2f991d169..fd06660e0 100644 --- a/crates/buttplug_core/Cargo.toml +++ b/crates/buttplug_core/Cargo.toml @@ -20,8 +20,8 @@ doc = true [features] default=["tokio-runtime"] -tokio-runtime=["tokio/rt"] -wasm=[] +tokio-runtime=["tokio/rt", "tokio/time"] +wasm=["wasm-bindgen-futures", "wasmtimer"] # Only build docs on one platform (linux) [package.metadata.docs.rs] @@ -46,9 +46,13 @@ log = "0.4.29" getset = "0.1.6" jsonschema = { version = "0.45.0", default-features = false } cfg-if = "1.0.4" -tokio = { version = "1.50.0", features = ["sync", "time", "macros"] } +tokio = { version = "1.50.0", features = ["sync", "macros"] } async-stream = "0.3.6" strum_macros = "0.28.0" strum = "0.28.0" derive_builder = "0.20.2" enum_dispatch = "0.3" +tracing = "0.1.44" +wasm-bindgen-futures = { version = "0.4.64", optional = true } +wasmtimer = { version = "0.4.3", optional = true } + diff --git a/crates/buttplug_core/src/connector/remote_connector.rs b/crates/buttplug_core/src/connector/remote_connector.rs index dc328534a..c65e3e5b2 100644 --- a/crates/buttplug_core/src/connector/remote_connector.rs +++ b/crates/buttplug_core/src/connector/remote_connector.rs @@ -234,7 +234,7 @@ where // If we connect successfully, we get back the channel from the transport // to send outgoing messages and receieve incoming events, all serialized. Ok(()) => { - async_manager::spawn(async move { + crate::spawn!("ButtplugRemoteConnector event loop", async move { remote_connector_event_loop::< TransportType, SerializerType, diff --git a/crates/buttplug_core/src/connector/transport/stream.rs b/crates/buttplug_core/src/connector/transport/stream.rs index 8e6676e4f..3562c2ce6 100644 --- a/crates/buttplug_core/src/connector/transport/stream.rs +++ b/crates/buttplug_core/src/connector/transport/stream.rs @@ -63,7 +63,7 @@ impl ButtplugConnectorTransport for ButtplugStreamTransport { .await .take() .ok_or(ButtplugConnectorError::ConnectorAlreadyConnected)?; - async_manager::spawn(async move { + crate::spawn!("ButtplugStreamTransport", async move { loop { select! { msg = outgoing_receiver.recv() => { diff --git a/crates/buttplug_core/src/util/async_manager/dummy.rs b/crates/buttplug_core/src/util/async_manager/dummy.rs deleted file mode 100644 index 1368e110d..000000000 --- a/crates/buttplug_core/src/util/async_manager/dummy.rs +++ /dev/null @@ -1,35 +0,0 @@ -// Buttplug Rust Source Code File - See https://buttplug.io for more info. -// -// Copyright 2016-2026 Nonpolynomial Labs LLC. All rights reserved. -// -// Licensed under the BSD 3-Clause license. See LICENSE file in the project root -// for full license information. - -use futures::{ - future::{Future, RemoteHandle}, - task::{FutureObj, Spawn, SpawnError}, -}; - -#[derive(Default)] -pub struct DummyAsyncManager {} - -impl Spawn for DummyAsyncManager { - fn spawn_obj(&self, _: FutureObj<'static, ()>) -> Result<(), SpawnError> { - unimplemented!("Dummy executor can't actually spawn!") - } -} - -pub fn spawn(_: Fut) -where - Fut: Future + Send + 'static, -{ - unimplemented!("Dummy executor can't actually spawn!") -} - -pub fn spawn_with_handle(_: Fut) -> Result, SpawnError> -where - Fut: Future + Send + 'static, - Fut::Output: Send, -{ - unimplemented!("Dummy executor can't actually spawn!") -} diff --git a/crates/buttplug_core/src/util/async_manager/mod.rs b/crates/buttplug_core/src/util/async_manager/mod.rs index 38bd98496..effc4a960 100644 --- a/crates/buttplug_core/src/util/async_manager/mod.rs +++ b/crates/buttplug_core/src/util/async_manager/mod.rs @@ -5,16 +5,89 @@ // Licensed under the BSD 3-Clause license. See LICENSE file in the project root // for full license information. -cfg_if::cfg_if! { - if #[cfg(feature = "wasm")] { - mod wasm_bindgen; - pub use self::wasm_bindgen::{WasmBindgenAsyncManager as AsyncManager, spawn, spawn_with_handle}; - } else if #[cfg(feature = "tokio-runtime")] { - mod tokio; - pub use self::tokio::{TokioAsyncManager as AsyncManager, spawn, spawn_with_handle}; - } else { - mod dummy; - pub use dummy::{DummyAsyncManager as AsyncManager, spawn, spawn_with_handle}; - //std::compile_error!("Please choose a runtime feature: tokio-runtime, wasm-bindgen-runtime, dummy-runtime"); +use futures::{future::BoxFuture, task::FutureObj}; +use std::{future::Future, sync::OnceLock, time::Duration}; +use tracing::Span; + +#[cfg(feature = "wasm")] +mod wasm; + +#[cfg(feature = "tokio-runtime")] +mod tokio; + +static GLOBAL_ASYNC_MANAGER: OnceLock> = OnceLock::new(); + +/// Set a custom global async manager. +/// +/// Call this once at startup to plug in a non-default async runtime. If not +/// called, the default manager for the enabled feature flag is used. +/// +/// # Panics +/// Panics if called more than once. +pub fn set_global_async_manager(manager: Box) { + GLOBAL_ASYNC_MANAGER + .set(manager) + .expect("Global async manager can only be set once."); +} + +/// Get the default async manager based on enabled feature flags. +fn get_default_async_manager() -> Box { + cfg_if::cfg_if! { + if #[cfg(feature = "wasm")] { + return Box::new(wasm::WasmBindgenAsyncManager::default()); + } else if #[cfg(feature = "tokio-runtime")] { + return Box::new(tokio::TokioAsyncManager::default()); + } else { + unimplemented!( + "No async runtime configured. Enable the `tokio-runtime` or `wasm` feature, \ + or call `set_global_async_manager` before performing async operations." + ); + } } } + +fn get_global_async_manager() -> &'static dyn AsyncManager { + GLOBAL_ASYNC_MANAGER + .get_or_init(|| get_default_async_manager()) + .as_ref() +} + +/// Trait for async runtime abstraction in Buttplug. +/// +/// Implement this trait to plug in a custom async runtime, then pass it to +/// [`set_global_async_manager`] before any async operations are performed. +/// +/// Built-in implementations are provided for Tokio (via `tokio-runtime` feature) +/// and WASM (via `wasm` feature). For other runtimes (e.g. Embassy, esp-idf), +/// implement this trait and call [`set_global_async_manager`] at startup. +pub trait AsyncManager: std::fmt::Debug + Send + Sync { + /// Spawn a fire-and-forget task on the async runtime. + /// + /// The `span` should be used to instrument the task with tracing context. + fn spawn(&self, future: FutureObj<'static, ()>, span: Span); + + /// Sleep for the given duration. + fn sleep(&self, duration: Duration) -> BoxFuture<'static, ()>; +} + +/// Spawn a fire-and-forget task on the global async manager. +/// +/// Prefer the [`spawn!`][crate::spawn] macro for ergonomic use with a task name. +pub fn spawn(future: F, span: Span) +where + F: Future + Send + 'static, +{ + get_global_async_manager().spawn(Box::new(future).into(), span); +} + +/// Sleep for the given duration using the global async manager. +pub async fn sleep(duration: Duration) { + get_global_async_manager().sleep(duration).await; +} + +#[macro_export] +macro_rules! spawn { + ($name:expr, $future:expr) => { + $crate::util::async_manager::spawn($future, tracing::span!(tracing::Level::INFO, $name)) + }; +} diff --git a/crates/buttplug_core/src/util/async_manager/tokio.rs b/crates/buttplug_core/src/util/async_manager/tokio.rs index b52c14d0e..7e4655713 100644 --- a/crates/buttplug_core/src/util/async_manager/tokio.rs +++ b/crates/buttplug_core/src/util/async_manager/tokio.rs @@ -5,37 +5,19 @@ // Licensed under the BSD 3-Clause license. See LICENSE file in the project root // for full license information. -use futures::{ - future::{Future, RemoteHandle}, - task::{FutureObj, Spawn, SpawnError, SpawnExt}, -}; -use tokio; +use futures::{future::BoxFuture, task::FutureObj}; +use std::time::Duration; +use tracing::{Instrument, Span}; -#[derive(Default)] +#[derive(Default, Debug)] pub struct TokioAsyncManager {} -impl Spawn for TokioAsyncManager { - fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> { - tokio::spawn(future); - Ok(()) +impl super::AsyncManager for TokioAsyncManager { + fn spawn(&self, future: FutureObj<'static, ()>, span: Span) { + tokio::task::spawn(future.instrument(span)); } -} - -pub fn spawn(future: Fut) -where - Fut: Future + Send + 'static, -{ - // SAFETY: TokioAsyncManager::spawn_obj always returns Ok(()). The Result type is only - // present to satisfy the Spawn trait interface. - TokioAsyncManager::default() - .spawn(future) - .expect("TokioAsyncManager::spawn_obj always returns Ok") -} -pub fn spawn_with_handle(future: Fut) -> Result, SpawnError> -where - Fut: Future + Send + 'static, - Fut::Output: Send, -{ - TokioAsyncManager::default().spawn_with_handle(future) + fn sleep(&self, duration: Duration) -> BoxFuture<'static, ()> { + Box::pin(tokio::time::sleep(duration)) + } } diff --git a/crates/buttplug_core/src/util/async_manager/wasm.rs b/crates/buttplug_core/src/util/async_manager/wasm.rs new file mode 100644 index 000000000..336ca43dc --- /dev/null +++ b/crates/buttplug_core/src/util/async_manager/wasm.rs @@ -0,0 +1,23 @@ +// Buttplug Rust Source Code File - See https://buttplug.io for more info. +// +// Copyright 2016-2026 Nonpolynomial Labs LLC. All rights reserved. +// +// Licensed under the BSD 3-Clause license. See LICENSE file in the project root +// for full license information. + +use futures::{future::BoxFuture, task::FutureObj}; +use std::time::Duration; +use tracing::{Instrument, Span}; + +#[derive(Default, Debug)] +pub struct WasmBindgenAsyncManager {} + +impl super::AsyncManager for WasmBindgenAsyncManager { + fn spawn(&self, future: FutureObj<'static, ()>, span: Span) { + wasm_bindgen_futures::spawn_local(future.instrument(span)); + } + + fn sleep(&self, duration: Duration) -> BoxFuture<'static, ()> { + Box::pin(wasmtimer::tokio::sleep(duration)) + } +} diff --git a/crates/buttplug_core/src/util/async_manager/wasm_bindgen.rs b/crates/buttplug_core/src/util/async_manager/wasm_bindgen.rs deleted file mode 100644 index 2851e1099..000000000 --- a/crates/buttplug_core/src/util/async_manager/wasm_bindgen.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Buttplug Rust Source Code File - See https://buttplug.io for more info. -// -// Copyright 2016-2026 Nonpolynomial Labs LLC. All rights reserved. -// -// Licensed under the BSD 3-Clause license. See LICENSE file in the project root -// for full license information. - -use futures::{ - future::{Future, RemoteHandle}, - task::{FutureObj, Spawn, SpawnError, SpawnExt}, -}; - -use wasm_bindgen_futures::spawn_local; - -#[derive(Default)] -pub struct WasmBindgenAsyncManager {} - -impl Spawn for WasmBindgenAsyncManager { - fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> { - spawn_local(future); - Ok(()) - } -} - -pub fn spawn(future: Fut) -where - Fut: Future + 'static, -{ - spawn_local(future); -} - -pub fn spawn_with_handle(future: Fut) -> Result, SpawnError> -where - Fut: Future + Send + 'static, - Fut::Output: Send, -{ - WasmBindgenAsyncManager::default().spawn_with_handle(future) -} diff --git a/crates/buttplug_core/src/util/mod.rs b/crates/buttplug_core/src/util/mod.rs index a8f87820a..63cdc8040 100644 --- a/crates/buttplug_core/src/util/mod.rs +++ b/crates/buttplug_core/src/util/mod.rs @@ -12,8 +12,3 @@ pub mod async_manager; pub mod json; pub mod range_serialize; pub mod stream; - -#[cfg(not(feature = "wasm"))] -pub use tokio::time::sleep; -#[cfg(feature = "wasm")] -pub use wasmtimer::tokio::sleep; From 9bbf9f7e6e6ff86e242c89005b4863fab2de66ce Mon Sep 17 00:00:00 2001 From: Jasmin Bom Date: Sun, 15 Mar 2026 14:42:19 +0100 Subject: [PATCH 02/10] buttplug_client: migrate to new async_manager spawn! macro --- crates/buttplug_client/src/lib.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/crates/buttplug_client/src/lib.rs b/crates/buttplug_client/src/lib.rs index e72e751b4..d1b837e5b 100644 --- a/crates/buttplug_client/src/lib.rs +++ b/crates/buttplug_client/src/lib.rs @@ -32,7 +32,7 @@ use buttplug_core::{ StopCmdV4, StopScanningV0, }, - util::{async_manager, stream::convert_broadcast_receiver_to_stream}, + util::stream::convert_broadcast_receiver_to_stream, }; use client_event_loop::{ButtplugClientEventLoop, ButtplugClientRequest}; use dashmap::DashMap; @@ -320,12 +320,9 @@ impl ButtplugClient { ); // Start the event loop before we run the handshake. - async_manager::spawn( - async move { - client_event_loop.run().await; - } - .instrument(tracing::info_span!("Client Loop Span")), - ); + buttplug_core::spawn!("ButtplugClient event loop", async move { + client_event_loop.run().await; + }); self.run_handshake().await } From 7eff1a34e0089b930cae96791abd8761a21ef91f Mon Sep 17 00:00:00 2001 From: Jasmin Bom Date: Sun, 15 Mar 2026 14:42:25 +0100 Subject: [PATCH 03/10] buttplug_client_in_process: migrate to new async_manager spawn! macro --- .../buttplug_client_in_process/src/in_process_connector.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/buttplug_client_in_process/src/in_process_connector.rs b/crates/buttplug_client_in_process/src/in_process_connector.rs index 95ca314f5..aac874933 100644 --- a/crates/buttplug_client_in_process/src/in_process_connector.rs +++ b/crates/buttplug_client_in_process/src/in_process_connector.rs @@ -11,7 +11,6 @@ use buttplug_core::{ connector::{ButtplugConnector, ButtplugConnectorError, ButtplugConnectorResultFuture}, errors::{ButtplugError, ButtplugMessageError}, message::{ButtplugClientMessageV4, ButtplugServerMessageV4}, - util::async_manager, }; use buttplug_server::{ ButtplugServer, @@ -116,7 +115,7 @@ impl ButtplugConnector self.server_outbound_sender = message_sender; let server_recv = self.server.server_version_event_stream(); async move { - async_manager::spawn(async move { + buttplug_core::spawn!("InProcessClientConnector event sender loop", async move { info!("Starting In Process Client Connector Event Sender Loop"); pin_mut!(server_recv); while let Some(event) = server_recv.next().await { @@ -130,7 +129,7 @@ impl ButtplugConnector } } info!("Stopping In Process Client Connector Event Sender Loop, due to channel receiver being dropped."); - }.instrument(tracing::info_span!("InProcessClientConnectorEventSenderLoop"))); + }); connected.store(true, Ordering::Relaxed); Ok(()) }.boxed() From c5c029deb4abdb68826aa2bff80f665fcff9d0bb Mon Sep 17 00:00:00 2001 From: Jasmin Bom Date: Sun, 15 Mar 2026 14:58:11 +0100 Subject: [PATCH 04/10] buttplug_server: migrate to new async_manager spawn! macro and async_manager::sleep --- crates/buttplug_server/Cargo.toml | 1 - crates/buttplug_server/src/device/device_handle.rs | 4 ++-- crates/buttplug_server/src/device/device_task.rs | 8 ++++---- .../src/device/hardware/communication.rs | 6 +++--- .../src/device/protocol_impl/cowgirl_cone.rs | 4 ++-- .../src/device/protocol_impl/fredorch.rs | 6 +++--- .../src/device/protocol_impl/fredorch_rotary.rs | 8 ++++---- .../buttplug_server/src/device/protocol_impl/hgod.rs | 6 +++--- .../src/device/protocol_impl/honeyplaybox.rs | 10 +++++----- .../src/device/protocol_impl/kgoal_boost.rs | 4 ++-- .../src/device/protocol_impl/kiiroo_v21.rs | 2 +- .../device/protocol_impl/lovense/lovense_stroker.rs | 8 ++++---- .../src/device/protocol_impl/lovense/mod.rs | 4 ++-- .../src/device/protocol_impl/nintendo_joycon.rs | 10 ++++------ .../src/device/protocol_impl/xuanhuan.rs | 8 ++++---- .../src/device/server_device_manager.rs | 4 ++-- .../src/device/server_device_manager_event_loop.rs | 7 ++----- crates/buttplug_server/src/ping_timer.rs | 8 ++++---- crates/buttplug_server/src/server.rs | 3 +-- crates/buttplug_server/src/server_builder.rs | 3 +-- 20 files changed, 53 insertions(+), 61 deletions(-) diff --git a/crates/buttplug_server/Cargo.toml b/crates/buttplug_server/Cargo.toml index 1e53927fe..9c684d957 100644 --- a/crates/buttplug_server/Cargo.toml +++ b/crates/buttplug_server/Cargo.toml @@ -33,7 +33,6 @@ log = "0.4.29" getset = "0.1.6" tokio = { version = "1.50.0", features = ["macros"] } dashmap = { version = "6.1.0" } -tracing-futures = "0.2.5" tracing = "0.1.44" serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.149" diff --git a/crates/buttplug_server/src/device/device_handle.rs b/crates/buttplug_server/src/device/device_handle.rs index 9846107ba..841ec7b2b 100644 --- a/crates/buttplug_server/src/device/device_handle.rs +++ b/crates/buttplug_server/src/device/device_handle.rs @@ -27,7 +27,7 @@ use buttplug_core::{ OutputValue, StopCmdV4, }, - util::{async_manager, stream::convert_broadcast_receiver_to_stream}, + util::stream::convert_broadcast_receiver_to_stream, }; use buttplug_server_device_config::{ DeviceConfigurationManager, @@ -596,7 +596,7 @@ pub(super) async fn build_device_handle( // to the device manager event loop via the provided sender. let event_stream = device_handle.event_stream(); let identifier = device_handle.identifier().clone(); - async_manager::spawn(async move { + buttplug_core::spawn!("DeviceEventForwarding", async move { futures::pin_mut!(event_stream); loop { let event = futures::StreamExt::next(&mut event_stream).await; diff --git a/crates/buttplug_server/src/device/device_task.rs b/crates/buttplug_server/src/device/device_task.rs index f2884d1c8..b57cd0628 100644 --- a/crates/buttplug_server/src/device/device_task.rs +++ b/crates/buttplug_server/src/device/device_task.rs @@ -14,7 +14,7 @@ use std::{collections::VecDeque, sync::Arc, time::Duration}; -use buttplug_core::util::{self, async_manager}; +use buttplug_core::util::async_manager; use futures::future; use tokio::{select, sync::mpsc::Receiver, time::Instant}; @@ -48,7 +48,7 @@ pub fn spawn_device_task( config: DeviceTaskConfig, mut command_receiver: Receiver>, ) { - async_manager::spawn(async move { + buttplug_core::spawn!("DeviceTask", async move { run_device_task(hardware, config, &mut command_receiver).await; }); } @@ -94,9 +94,9 @@ async fn run_device_task( // Calculate keepalive timeout let keepalive_fut = async { if let Some(duration) = strategy_duration { - util::sleep(duration).await; + async_manager::sleep(duration).await; } else if requires_keepalive { - util::sleep(Duration::from_secs(5)).await; // iOS Bluetooth default + async_manager::sleep(Duration::from_secs(5)).await; // iOS Bluetooth default } else { future::pending::<()>().await; } diff --git a/crates/buttplug_server/src/device/hardware/communication.rs b/crates/buttplug_server/src/device/hardware/communication.rs index a9d521977..441265329 100644 --- a/crates/buttplug_server/src/device/hardware/communication.rs +++ b/crates/buttplug_server/src/device/hardware/communication.rs @@ -8,7 +8,7 @@ use crate::device::hardware::HardwareConnector; use async_trait::async_trait; use buttplug_core::{ - util::{async_manager, sleep}, + util::async_manager, {ButtplugResultFuture, errors::ButtplugDeviceError}, }; use futures::future::{self, FutureExt}; @@ -95,14 +95,14 @@ impl HardwareCommunicationManager self.cancellation_token = Some(token); let duration = self.comm_manager.rescan_wait_duration(); async move { - async_manager::spawn(async move { + buttplug_core::spawn!("TimedDeviceCommunicationManager scanning", async move { loop { if let Err(err) = comm_manager.scan().await { error!("Timed Device Communication Manager Failure: {}", err); break; } tokio::select! { - _ = sleep(duration) => continue, + _ = async_manager::sleep(duration) => continue, _ = child_token.cancelled() => break, } } diff --git a/crates/buttplug_server/src/device/protocol_impl/cowgirl_cone.rs b/crates/buttplug_server/src/device/protocol_impl/cowgirl_cone.rs index c9201e95b..dfeedd0b6 100644 --- a/crates/buttplug_server/src/device/protocol_impl/cowgirl_cone.rs +++ b/crates/buttplug_server/src/device/protocol_impl/cowgirl_cone.rs @@ -15,7 +15,7 @@ use crate::device::{ }, }; use async_trait::async_trait; -use buttplug_core::{errors::ButtplugDeviceError, util::sleep}; +use buttplug_core::{errors::ButtplugDeviceError, util::async_manager}; use buttplug_server_device_config::{ Endpoint, ProtocolCommunicationSpecifier, @@ -47,7 +47,7 @@ impl ProtocolInitializer for CowgirlConeInitializer { false, )) .await?; - sleep(Duration::from_millis(3000)).await; + async_manager::sleep(Duration::from_millis(3000)).await; Ok(Arc::new(CowgirlCone::default())) } } diff --git a/crates/buttplug_server/src/device/protocol_impl/fredorch.rs b/crates/buttplug_server/src/device/protocol_impl/fredorch.rs index 2c03bffbd..9b85fbeea 100644 --- a/crates/buttplug_server/src/device/protocol_impl/fredorch.rs +++ b/crates/buttplug_server/src/device/protocol_impl/fredorch.rs @@ -15,7 +15,7 @@ use crate::device::{ }, }; use async_trait::async_trait; -use buttplug_core::{errors::ButtplugDeviceError, util::sleep}; +use buttplug_core::{errors::ButtplugDeviceError, util::async_manager}; use buttplug_server_device_config::{ Endpoint, ProtocolCommunicationSpecifier, @@ -137,7 +137,7 @@ impl ProtocolInitializer for FredorchInitializer { ); } } - _ = sleep(Duration::from_millis(FREDORCH_COMMAND_TIMEOUT_MS)).fuse() => { + _ = async_manager::sleep(Duration::from_millis(FREDORCH_COMMAND_TIMEOUT_MS)).fuse() => { // Or not? } } @@ -169,7 +169,7 @@ impl ProtocolInitializer for FredorchInitializer { ); } } - _ = sleep(Duration::from_millis(FREDORCH_COMMAND_TIMEOUT_MS)).fuse() => { + _ = async_manager::sleep(Duration::from_millis(FREDORCH_COMMAND_TIMEOUT_MS)).fuse() => { return Err( ButtplugDeviceError::ProtocolSpecificError( "Fredorch".to_owned(), diff --git a/crates/buttplug_server/src/device/protocol_impl/fredorch_rotary.rs b/crates/buttplug_server/src/device/protocol_impl/fredorch_rotary.rs index f63111b94..92864fed4 100644 --- a/crates/buttplug_server/src/device/protocol_impl/fredorch_rotary.rs +++ b/crates/buttplug_server/src/device/protocol_impl/fredorch_rotary.rs @@ -16,7 +16,7 @@ use crate::device::{ use async_trait::async_trait; use buttplug_core::{ errors::ButtplugDeviceError, - util::{async_manager, sleep}, + util::async_manager, }; use buttplug_server_device_config::{ Endpoint, @@ -106,7 +106,7 @@ impl ProtocolInitializer for FredorchRotaryInitializer { ); } } - _ = sleep(Duration::from_millis(FREDORCH_COMMAND_TIMEOUT_MS)).fuse() => { + _ = async_manager::sleep(Duration::from_millis(FREDORCH_COMMAND_TIMEOUT_MS)).fuse() => { // The after the password check, we won't get anything } } @@ -183,7 +183,7 @@ async fn speed_update_handler( } } - sleep(Duration::from_millis(FREDORCH_COMMAND_TIMEOUT_MS)).await; + async_manager::sleep(Duration::from_millis(FREDORCH_COMMAND_TIMEOUT_MS)).await; } info!("FredorchRotary control loop exiting, most likely due to device disconnection."); } @@ -194,7 +194,7 @@ impl FredorchRotary { let target_speed = Arc::new(AtomicU8::new(0)); let current_speed_clone = current_speed.clone(); let target_speed_clone = target_speed.clone(); - async_manager::spawn(async move { + buttplug_core::spawn!("FredorchRotarySpeedUpdate", async move { speed_update_handler(device, current_speed_clone, target_speed_clone).await }); Self { diff --git a/crates/buttplug_server/src/device/protocol_impl/hgod.rs b/crates/buttplug_server/src/device/protocol_impl/hgod.rs index 1beecd570..aca1b5df1 100644 --- a/crates/buttplug_server/src/device/protocol_impl/hgod.rs +++ b/crates/buttplug_server/src/device/protocol_impl/hgod.rs @@ -17,7 +17,7 @@ use crate::device::{ use async_trait::async_trait; use buttplug_core::{ errors::ButtplugDeviceError, - util::{async_manager, sleep}, + util::async_manager, }; use buttplug_server_device_config::{ Endpoint, @@ -63,7 +63,7 @@ impl Hgod { let last_command = Arc::new(AtomicU8::new(0)); let last_command_clone = last_command.clone(); - async_manager::spawn(async move { + buttplug_core::spawn!("Hgod update loop", async move { send_hgod_updates(hardware, last_command_clone).await; }); @@ -92,7 +92,7 @@ async fn send_hgod_updates(device: Arc, data: Arc) { ); break; } - sleep(Duration::from_millis(HGOD_COMMAND_DELAY_MS)).await; + async_manager::sleep(Duration::from_millis(HGOD_COMMAND_DELAY_MS)).await; } } diff --git a/crates/buttplug_server/src/device/protocol_impl/honeyplaybox.rs b/crates/buttplug_server/src/device/protocol_impl/honeyplaybox.rs index 9561523eb..26145e713 100644 --- a/crates/buttplug_server/src/device/protocol_impl/honeyplaybox.rs +++ b/crates/buttplug_server/src/device/protocol_impl/honeyplaybox.rs @@ -18,7 +18,7 @@ use crate::device::{ use async_trait::async_trait; use buttplug_core::message::{InputReadingV4, InputTypeReading, InputValue}; use buttplug_core::util::async_manager; -use buttplug_core::{errors::ButtplugDeviceError, util::sleep}; +use buttplug_core::errors::ButtplugDeviceError; use buttplug_server_device_config::Endpoint; use buttplug_server_device_config::{ ProtocolCommunicationSpecifier, @@ -129,7 +129,7 @@ impl ProtocolInitializer for HoneyPlayBoxInitializer { ); } } - _ = sleep(Duration::from_secs(count+1)).fuse() => { + _ = async_manager::sleep(Duration::from_secs(count+1)).fuse() => { count += 1; if count > HONEY_PLAYBOX_COMMAND_RETRY { error!("HoneyPlayBox Device timed out while waiting for handshake. ({} retries)", HONEY_PLAYBOX_COMMAND_RETRY); @@ -204,7 +204,7 @@ async fn hpb_keepalive( } } } - sleep(Duration::from_millis(HONEY_PLAYBOX_KEEPALIVE_INTERVAL)).await; + async_manager::sleep(Duration::from_millis(HONEY_PLAYBOX_KEEPALIVE_INTERVAL)).await; } } @@ -217,7 +217,7 @@ impl HoneyPlayBox { ); let packet_id = Arc::new(AtomicU8::new(count)); let last_send = Arc::new(RwLock::new(Instant::now())); - async_manager::spawn(hpb_keepalive( + buttplug_core::spawn!("HoneyPlayboxKeepalive", hpb_keepalive( hardware.clone(), random_key, last_command.clone(), @@ -240,7 +240,7 @@ impl HoneyPlayBox { ) -> Result, ButtplugDeviceError> { // Best effort last command time update let last_send = self.last_send.clone(); - async_manager::spawn(async move { + buttplug_core::spawn!("HoneyPlaybox last send update", async move { if let Ok(mut last_time) = last_send.try_write() { *last_time = Instant::now(); } diff --git a/crates/buttplug_server/src/device/protocol_impl/kgoal_boost.rs b/crates/buttplug_server/src/device/protocol_impl/kgoal_boost.rs index b4a6a205d..7e99fef18 100644 --- a/crates/buttplug_server/src/device/protocol_impl/kgoal_boost.rs +++ b/crates/buttplug_server/src/device/protocol_impl/kgoal_boost.rs @@ -15,7 +15,7 @@ use crate::{ use buttplug_core::{ errors::ButtplugDeviceError, message::{InputReadingV4, InputType, InputValue}, - util::{async_manager, stream::convert_broadcast_receiver_to_stream}, + util::stream::convert_broadcast_receiver_to_stream, }; use buttplug_server_device_config::Endpoint; use futures::{ @@ -90,7 +90,7 @@ impl ProtocolHandler for KGoalBoost { let stream_sensors = stream_sensors.clone(); info!("Starting Kgoal subscription"); // If we subscribe successfully, we need to set up our event handler. - async_manager::spawn(async move { + buttplug_core::spawn!("Kgoal subscription event handler", async move { let mut cached_values = vec![0u32, 0u32]; while let Ok(info) = hardware_stream.recv().await { let subscribed_sensors = stream_sensors.load(Ordering::Relaxed); diff --git a/crates/buttplug_server/src/device/protocol_impl/kiiroo_v21.rs b/crates/buttplug_server/src/device/protocol_impl/kiiroo_v21.rs index 9dc79ac1f..ecc656abb 100644 --- a/crates/buttplug_server/src/device/protocol_impl/kiiroo_v21.rs +++ b/crates/buttplug_server/src/device/protocol_impl/kiiroo_v21.rs @@ -162,7 +162,7 @@ impl ProtocolHandler for KiirooV21 { let mut hardware_stream = device.event_stream(); let stream_sensors = sensors.clone(); // If we subscribe successfully, we need to set up our event handler. - async_manager::spawn(async move { + buttplug_core::spawn!("KiirooV21EventHandler", async move { while let Ok(info) = hardware_stream.recv().await { // If we have no receivers, quit. if sender.receiver_count() == 0 || stream_sensors.is_empty() { diff --git a/crates/buttplug_server/src/device/protocol_impl/lovense/lovense_stroker.rs b/crates/buttplug_server/src/device/protocol_impl/lovense/lovense_stroker.rs index beb60046d..2858b1497 100644 --- a/crates/buttplug_server/src/device/protocol_impl/lovense/lovense_stroker.rs +++ b/crates/buttplug_server/src/device/protocol_impl/lovense/lovense_stroker.rs @@ -12,7 +12,7 @@ use crate::device::{ use buttplug_core::{ errors::ButtplugDeviceError, message::InputReadingV4, - util::{async_manager, sleep}, + util::async_manager, }; use buttplug_server_device_config::Endpoint; use futures::future::BoxFuture; @@ -35,7 +35,7 @@ pub struct LovenseStroker { impl LovenseStroker { pub fn new(hardware: Arc, need_range_zerod: bool) -> Self { let linear_info = Arc::new((AtomicU32::new(0), AtomicU32::new(0))); - async_manager::spawn(update_linear_movement( + buttplug_core::spawn!("LovenseStroker update linear movement", update_linear_movement( hardware.clone(), linear_info.clone(), )); @@ -119,7 +119,7 @@ async fn update_linear_movement(device: Arc, linear_info: Arc<(AtomicU // If we aren't going anywhere, just pause then restart if current_position == last_goal_position { - sleep(Duration::from_millis(100)).await; + async_manager::sleep(Duration::from_millis(100)).await; continue; } @@ -144,6 +144,6 @@ async fn update_linear_movement(device: Arc, linear_info: Arc<(AtomicU if device.write_value(&hardware_cmd).await.is_err() { return; } - sleep(Duration::from_millis(100)).await; + async_manager::sleep(Duration::from_millis(100)).await; } } diff --git a/crates/buttplug_server/src/device/protocol_impl/lovense/mod.rs b/crates/buttplug_server/src/device/protocol_impl/lovense/mod.rs index 168efcb9f..03a086277 100644 --- a/crates/buttplug_server/src/device/protocol_impl/lovense/mod.rs +++ b/crates/buttplug_server/src/device/protocol_impl/lovense/mod.rs @@ -27,7 +27,7 @@ use async_trait::async_trait; use buttplug_core::{ errors::ButtplugDeviceError, message::{self, InputReadingV4, InputTypeReading, InputValue, OutputType}, - util::sleep, + util::async_manager, }; use buttplug_server_device_config::{ Endpoint, @@ -134,7 +134,7 @@ impl ProtocolIdentifier for LovenseIdentifier { ); } } - _ = sleep(Duration::from_millis(LOVENSE_COMMAND_TIMEOUT_MS)).fuse() => { + _ = async_manager::sleep(Duration::from_millis(LOVENSE_COMMAND_TIMEOUT_MS)).fuse() => { count += 1; if count > LOVENSE_COMMAND_RETRY { warn!("Lovense Device timed out while getting DeviceType info. ({} retries)", LOVENSE_COMMAND_RETRY); diff --git a/crates/buttplug_server/src/device/protocol_impl/nintendo_joycon.rs b/crates/buttplug_server/src/device/protocol_impl/nintendo_joycon.rs index c823ff0c8..7a4bd711b 100644 --- a/crates/buttplug_server/src/device/protocol_impl/nintendo_joycon.rs +++ b/crates/buttplug_server/src/device/protocol_impl/nintendo_joycon.rs @@ -263,9 +263,7 @@ impl NintendoJoycon { let notifier_clone = notifier.clone(); let is_stopped = Arc::new(AtomicBool::new(false)); let is_stopped_clone = is_stopped.clone(); - async_manager::spawn(async move { - #[cfg(feature = "wasm")] - use buttplug_core::util; + buttplug_core::spawn!("NintendoJoycon update loop", async move { loop { if is_stopped_clone.load(Ordering::Relaxed) { return; @@ -283,14 +281,14 @@ impl NintendoJoycon { error!("Joycon command failed, exiting update loop"); break; } - #[cfg(not(feature = "wasm"))] + #[cfg(feature = "tokio-runtime")] let _ = tokio::time::timeout(Duration::from_millis(15), notifier_clone.notified()).await; // If we're using WASM, we can't use tokio's timeout due to lack of time library in WASM. // I'm also too lazy to make this a select. So, this'll do. We can't even access this // protocol in a web context yet since there's no WebHID comm manager yet. - #[cfg(feature = "wasm")] - util::sleep(Duration::from_millis(15)).await; + #[cfg(not(feature = "tokio-runtime"))] + unimplemented!("Nintendo Joycon protocol is not supported in non-tokio runtimes yet"); } }); Self { diff --git a/crates/buttplug_server/src/device/protocol_impl/xuanhuan.rs b/crates/buttplug_server/src/device/protocol_impl/xuanhuan.rs index 65834fa99..048fbb812 100644 --- a/crates/buttplug_server/src/device/protocol_impl/xuanhuan.rs +++ b/crates/buttplug_server/src/device/protocol_impl/xuanhuan.rs @@ -17,7 +17,7 @@ use crate::device::{ use async_trait::async_trait; use buttplug_core::{ errors::ButtplugDeviceError, - util::{async_manager, sleep}, + util::async_manager, }; use buttplug_server_device_config::{ Endpoint, @@ -70,7 +70,7 @@ async fn vibration_update_handler(device: Arc, command_holder: Arc) -> Self { let current_command = Arc::new(AtomicU8::new(0)); let current_command_clone = current_command.clone(); - async_manager::spawn( - async move { vibration_update_handler(device, current_command_clone).await }, + buttplug_core::spawn!("Xuanhuan vibration update", + async move { vibration_update_handler(device, current_command_clone).await } ); Self { current_command } } diff --git a/crates/buttplug_server/src/device/server_device_manager.rs b/crates/buttplug_server/src/device/server_device_manager.rs index 3086d60f6..af686e7aa 100644 --- a/crates/buttplug_server/src/device/server_device_manager.rs +++ b/crates/buttplug_server/src/device/server_device_manager.rs @@ -35,7 +35,7 @@ use buttplug_core::{ DeviceListV4, StopCmdV4, }, - util::{async_manager, stream::convert_broadcast_receiver_to_stream}, + util::stream::convert_broadcast_receiver_to_stream, }; use buttplug_server_device_config::{DeviceConfigurationManager, UserDeviceIdentifier}; use dashmap::DashMap; @@ -159,7 +159,7 @@ impl ServerDeviceManagerBuilder { device_event_receiver, device_command_receiver, ); - async_manager::spawn(async move { + buttplug_core::spawn!("ServerDeviceManager event loop", async move { event_loop.run().await; }); Ok(ServerDeviceManager { diff --git a/crates/buttplug_server/src/device/server_device_manager_event_loop.rs b/crates/buttplug_server/src/device/server_device_manager_event_loop.rs index d568612d0..030f8754a 100644 --- a/crates/buttplug_server/src/device/server_device_manager_event_loop.rs +++ b/crates/buttplug_server/src/device/server_device_manager_event_loop.rs @@ -7,7 +7,6 @@ use buttplug_core::{ message::{ButtplugServerMessageV4, DeviceListV4, ScanningFinishedV0}, - util::async_manager, }; use buttplug_server_device_config::DeviceConfigurationManager; use tracing::info_span; @@ -24,8 +23,6 @@ use futures::{FutureExt, future}; use std::sync::Arc; use tokio::sync::{broadcast, mpsc}; use tokio_util::sync::CancellationToken; -use tracing_futures::Instrument; - use super::server_device_manager::DeviceManagerCommand; /// Scanning state machine for the device manager event loop. @@ -289,7 +286,7 @@ impl ServerDeviceManagerEventLoop { // Clone sender again for the forwarding task that build_device_handle will spawn let device_event_sender_for_forwarding = self.device_event_sender.clone(); - async_manager::spawn(async move { + buttplug_core::util::async_manager::spawn(async move { match build_device_handle( device_config_manager, creator, @@ -309,7 +306,7 @@ impl ServerDeviceManagerEventLoop { } } connecting_devices.remove(&address); - }.instrument(span)); + }, span); } } } diff --git a/crates/buttplug_server/src/ping_timer.rs b/crates/buttplug_server/src/ping_timer.rs index fdf2c9489..4b7ec5a9d 100644 --- a/crates/buttplug_server/src/ping_timer.rs +++ b/crates/buttplug_server/src/ping_timer.rs @@ -5,7 +5,7 @@ // Licensed under the BSD 3-Clause license. See LICENSE file in the project root // for full license information. -use buttplug_core::util::{async_manager, sleep}; +use buttplug_core::util::async_manager; use futures::Future; use std::{sync::Arc, time::Duration}; use tokio::{ @@ -33,7 +33,7 @@ async fn ping_timer( let mut pinged = false; loop { select! { - _ = sleep(Duration::from_millis(max_ping_time.into())) => { + _ = async_manager::sleep(Duration::from_millis(max_ping_time.into())) => { if started { if !pinged { // Ping timeout occurred - call the callback @@ -70,7 +70,7 @@ impl Drop for PingTimer { // This cannot block, otherwise it will throw in WASM contexts on // destruction. We must use send(), not blocking_send(). let sender = self.ping_msg_sender.clone(); - async_manager::spawn(async move { + buttplug_core::spawn!("PingTimerDrop", async move { if sender.send(PingMessage::End).await.is_err() { debug!("Receiver does not exist, assuming ping timer event loop already dead."); } @@ -92,7 +92,7 @@ impl PingTimer { if max_ping_time > 0 { let callback = Arc::new(Mutex::new(on_ping_timeout)); let fut = ping_timer(max_ping_time, receiver, callback); - async_manager::spawn(fut); + buttplug_core::spawn!("PingTimer", fut); } Self { max_ping_time, diff --git a/crates/buttplug_server/src/server.rs b/crates/buttplug_server/src/server.rs index 409fc98a5..d41a9bacb 100644 --- a/crates/buttplug_server/src/server.rs +++ b/crates/buttplug_server/src/server.rs @@ -47,8 +47,7 @@ use std::{ }; use tokio::sync::broadcast; use tokio_stream::StreamExt; -use tracing::info_span; -use tracing_futures::Instrument; +use tracing::{Instrument, info_span}; /// Connection state for the ButtplugServer. /// Replaces separate connected/client_name/spec_version fields with explicit states. diff --git a/crates/buttplug_server/src/server_builder.rs b/crates/buttplug_server/src/server_builder.rs index d0a3ff65a..d5ab30e5b 100644 --- a/crates/buttplug_server/src/server_builder.rs +++ b/crates/buttplug_server/src/server_builder.rs @@ -14,7 +14,6 @@ use super::{ use buttplug_core::{ errors::*, message::{self, ButtplugServerMessageV4, StopCmdV4}, - util::async_manager, }; use buttplug_server_device_config::DeviceConfigurationManagerBuilder; use std::sync::{Arc, RwLock}; @@ -114,7 +113,7 @@ impl ButtplugServerBuilder { *state_guard = ConnectionState::PingedOut; } // Stop all devices (spawn async task since callback is sync) - async_manager::spawn(async move { + buttplug_core::spawn!("PingTimeoutStopDevices", async move { if let Err(e) = device_manager_clone .stop_devices(&StopCmdV4::default()) .await From 5dea54d624998e47c29c71a35458792a333a2c81 Mon Sep 17 00:00:00 2001 From: Jasmin Bom Date: Sun, 15 Mar 2026 15:01:27 +0100 Subject: [PATCH 05/10] buttplug_server_hwmgr_btleplug: migrate to new async_manager spawn! macro --- .../src/btleplug_comm_manager.rs | 4 ++-- .../buttplug_server_hwmgr_btleplug/src/btleplug_hardware.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/buttplug_server_hwmgr_btleplug/src/btleplug_comm_manager.rs b/crates/buttplug_server_hwmgr_btleplug/src/btleplug_comm_manager.rs index 957b9a4c5..934eb2393 100644 --- a/crates/buttplug_server_hwmgr_btleplug/src/btleplug_comm_manager.rs +++ b/crates/buttplug_server_hwmgr_btleplug/src/btleplug_comm_manager.rs @@ -6,7 +6,7 @@ // for full license information. use super::btleplug_adapter_task::{BtleplugAdapterCommand, BtleplugAdapterTask}; -use buttplug_core::{ButtplugResultFuture, errors::ButtplugDeviceError, util::async_manager}; +use buttplug_core::{ButtplugResultFuture, errors::ButtplugDeviceError}; use buttplug_server::device::hardware::communication::{ HardwareCommunicationManager, HardwareCommunicationManagerBuilder, @@ -57,7 +57,7 @@ impl BtlePlugCommunicationManager { let (sender, receiver) = channel(256); let adapter_connected = Arc::new(AtomicBool::new(false)); let adapter_connected_clone = adapter_connected.clone(); - async_manager::spawn(async move { + buttplug_core::spawn!("BtleplugAdapterTask", async move { let mut task = BtleplugAdapterTask::new( event_sender, receiver, diff --git a/crates/buttplug_server_hwmgr_btleplug/src/btleplug_hardware.rs b/crates/buttplug_server_hwmgr_btleplug/src/btleplug_hardware.rs index 061ff44c0..63d8d9ab0 100644 --- a/crates/buttplug_server_hwmgr_btleplug/src/btleplug_hardware.rs +++ b/crates/buttplug_server_hwmgr_btleplug/src/btleplug_hardware.rs @@ -11,7 +11,7 @@ use btleplug::{ api::{Central, CentralEvent, Characteristic, Peripheral, ValueNotification, WriteType}, platform::Adapter, }; -use buttplug_core::{errors::ButtplugDeviceError, util::async_manager}; +use buttplug_core::{errors::ButtplugDeviceError}; use buttplug_server::device::hardware::{ Hardware, HardwareConnector, @@ -243,7 +243,7 @@ impl BtlePlugHardware { let event_stream_clone = event_stream.clone(); let address = device.id(); let name_clone = name.to_owned(); - async_manager::spawn(async move { + buttplug_core::spawn!("BtlePlugHardare notification loop", async move { let mut error_notification = false; loop { select! { @@ -517,7 +517,7 @@ impl HardwareInternal for BtlePlugHardware { impl Drop for BtlePlugHardware { fn drop(&mut self) { let disconnect_fut = self.disconnect(); - async_manager::spawn(async move { + buttplug_core::spawn!("BtlePlugHardware Drop", async move { if let Err(e) = disconnect_fut.await { error!("Error disconnecting btleplug device: {:?}", e); } From f787b84e55af586135af7e77d3782af424eb85b3 Mon Sep 17 00:00:00 2001 From: Jasmin Bom Date: Sun, 15 Mar 2026 15:09:00 +0100 Subject: [PATCH 06/10] buttplug_server_hwmgr_*: Replace async_manager with buttplug_core::spawn --- .../src/lovense_connect_service_hardware.rs | 6 ++--- .../Cargo.toml | 1 - .../src/lovense_dongle_hardware.rs | 4 ++-- .../src/lovense_hid_dongle_comm_manager.rs | 23 +++++++------------ .../src/serialport_hardware.rs | 4 ++-- .../src/websocket_server_comm_manager.rs | 4 ++-- .../src/websocket_server_hardware.rs | 4 ++-- .../src/xinput_hardware.rs | 4 ++-- 8 files changed, 21 insertions(+), 29 deletions(-) diff --git a/crates/buttplug_server_hwmgr_lovense_connect/src/lovense_connect_service_hardware.rs b/crates/buttplug_server_hwmgr_lovense_connect/src/lovense_connect_service_hardware.rs index 45cc145f4..f59212b6f 100644 --- a/crates/buttplug_server_hwmgr_lovense_connect/src/lovense_connect_service_hardware.rs +++ b/crates/buttplug_server_hwmgr_lovense_connect/src/lovense_connect_service_hardware.rs @@ -7,7 +7,7 @@ use super::lovense_connect_service_comm_manager::{LovenseServiceToyInfo, get_local_info}; use async_trait::async_trait; -use buttplug_core::{errors::ButtplugDeviceError, util::async_manager}; +use buttplug_core::errors::ButtplugDeviceError; use buttplug_server::device::hardware::{ GenericHardwareSpecializer, Hardware, @@ -93,7 +93,7 @@ impl LovenseServiceHardware { let host = http_host.to_owned(); let battery_level = Arc::new(AtomicU8::new(100)); let battery_level_clone = battery_level.clone(); - async_manager::spawn(async move { + buttplug_core::spawn!("LovenseServiceHardware loop", async move { loop { // SutekhVRC/VibeCheck patch for delay because Lovense Connect HTTP servers crash (Perma DOS) tokio::time::sleep(Duration::from_secs(1)).await; @@ -167,7 +167,7 @@ impl HardwareInternal for LovenseServiceHardware { async move { match reqwest::get(command_url).await { Ok(res) => { - async_manager::spawn(async move { + buttplug_core::spawn!("LovenseServiceHardware HTTP Response", async move { trace!( "Got http response: {}", res.text().await.unwrap_or("no response".to_string()) diff --git a/crates/buttplug_server_hwmgr_lovense_dongle/Cargo.toml b/crates/buttplug_server_hwmgr_lovense_dongle/Cargo.toml index e965db11c..32c8f32e1 100644 --- a/crates/buttplug_server_hwmgr_lovense_dongle/Cargo.toml +++ b/crates/buttplug_server_hwmgr_lovense_dongle/Cargo.toml @@ -36,7 +36,6 @@ serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.149" serde_repr = "0.1.20" tokio-util = "0.7.18" -tracing-futures = "0.2.5" [target.'cfg(target_os = "windows")'.dependencies] hidapi = { version = "2.6.5", default-features = false, features = ["windows-native"] } diff --git a/crates/buttplug_server_hwmgr_lovense_dongle/src/lovense_dongle_hardware.rs b/crates/buttplug_server_hwmgr_lovense_dongle/src/lovense_dongle_hardware.rs index ea0b82f35..f255d11ee 100644 --- a/crates/buttplug_server_hwmgr_lovense_dongle/src/lovense_dongle_hardware.rs +++ b/crates/buttplug_server_hwmgr_lovense_dongle/src/lovense_dongle_hardware.rs @@ -13,7 +13,7 @@ use super::lovense_dongle_messages::{ OutgoingLovenseData, }; use async_trait::async_trait; -use buttplug_core::{errors::ButtplugDeviceError, util::async_manager}; +use buttplug_core::errors::ButtplugDeviceError; use buttplug_server::device::hardware::{ GenericHardwareSpecializer, Hardware, @@ -128,7 +128,7 @@ impl LovenseDongleHardware { let address_clone = address.to_owned(); let (device_event_sender, _) = broadcast::channel(256); let device_event_sender_clone = device_event_sender.clone(); - async_manager::spawn(async move { + buttplug_core::spawn!("LovenseDongleHardware data loop", async move { while let Some(msg) = device_incoming.recv().await { if msg.func != LovenseDongleMessageFunc::ToyData { continue; diff --git a/crates/buttplug_server_hwmgr_lovense_dongle/src/lovense_hid_dongle_comm_manager.rs b/crates/buttplug_server_hwmgr_lovense_dongle/src/lovense_hid_dongle_comm_manager.rs index 23ace40e8..297fa0c1d 100644 --- a/crates/buttplug_server_hwmgr_lovense_dongle/src/lovense_hid_dongle_comm_manager.rs +++ b/crates/buttplug_server_hwmgr_lovense_dongle/src/lovense_hid_dongle_comm_manager.rs @@ -13,7 +13,7 @@ use super::{ }, lovense_dongle_state_machine::create_lovense_dongle_machine, }; -use buttplug_core::{ButtplugResultFuture, errors::ButtplugDeviceError, util::async_manager}; +use buttplug_core::{ButtplugResultFuture, errors::ButtplugDeviceError}; use buttplug_server::device::hardware::communication::{ HardwareCommunicationManager, HardwareCommunicationManagerBuilder, @@ -38,7 +38,6 @@ use tokio::{ }, }; use tokio_util::sync::CancellationToken; -use tracing_futures::Instrument; fn hid_write_thread( dongle: HidDevice, @@ -190,22 +189,16 @@ impl LovenseHIDDongleCommunicationManager { dongle_available, }; let dongle_fut = mgr.find_dongle(); - async_manager::spawn( - async move { - let _ = dongle_fut.await; - } - .instrument(tracing::info_span!("Lovense HID Dongle Finder Task")), - ); + buttplug_core::spawn!("LovenseHIDDongleCommunicationManager find dongle", async move { + let _ = dongle_fut.await; + }); let mut machine = create_lovense_dongle_machine(event_sender, machine_receiver, mgr.is_scanning.clone()); - async_manager::spawn( - async move { - while let Some(next) = machine.transition().await { - machine = next; - } + buttplug_core::spawn!("LovenseHIDDongleCommunicationManager state machine", async move { + while let Some(next) = machine.transition().await { + machine = next; } - .instrument(tracing::info_span!("Lovense HID Dongle State Machine")), - ); + }); mgr } diff --git a/crates/buttplug_server_hwmgr_serial/src/serialport_hardware.rs b/crates/buttplug_server_hwmgr_serial/src/serialport_hardware.rs index 5181f16f3..9ce4d51d4 100644 --- a/crates/buttplug_server_hwmgr_serial/src/serialport_hardware.rs +++ b/crates/buttplug_server_hwmgr_serial/src/serialport_hardware.rs @@ -6,7 +6,7 @@ // for full license information. use async_trait::async_trait; -use buttplug_core::{errors::ButtplugDeviceError, util::async_manager}; +use buttplug_core::errors::ButtplugDeviceError; use buttplug_server::device::hardware::{ Hardware, HardwareConnector, @@ -348,7 +348,7 @@ impl HardwareInternal for SerialPortHardware { let event_sender = self.device_event_sender.clone(); let address = self.address.clone(); async move { - async_manager::spawn(async move { + buttplug_core::spawn!("SerialPortHardware subscription", async move { // TODO There's only one subscribable endpoint on a serial port, so we // should check to make sure we don't have multiple subscriptions so we // don't deadlock. diff --git a/crates/buttplug_server_hwmgr_websocket/src/websocket_server_comm_manager.rs b/crates/buttplug_server_hwmgr_websocket/src/websocket_server_comm_manager.rs index aa693bb0c..8ac1d3115 100644 --- a/crates/buttplug_server_hwmgr_websocket/src/websocket_server_comm_manager.rs +++ b/crates/buttplug_server_hwmgr_websocket/src/websocket_server_comm_manager.rs @@ -6,7 +6,7 @@ // for full license information. use super::websocket_server_hardware::WebsocketServerHardwareConnector; -use buttplug_core::{ButtplugResultFuture, util::async_manager}; +use buttplug_core::ButtplugResultFuture; use buttplug_server::device::hardware::communication::{ HardwareCommunicationManager, HardwareCommunicationManagerBuilder, @@ -82,7 +82,7 @@ impl WebsocketServerDeviceCommunicationManager { trace!("Websocket server port created."); let server_cancellation_token = CancellationToken::new(); let child_token = server_cancellation_token.child_token(); - async_manager::spawn(async move { + buttplug_core::spawn!("WebsocketServerDeviceCommunicationManager loop", async move { let base_addr = if listen_on_all_interfaces { "0.0.0.0" } else { diff --git a/crates/buttplug_server_hwmgr_websocket/src/websocket_server_hardware.rs b/crates/buttplug_server_hwmgr_websocket/src/websocket_server_hardware.rs index 8ae1778d4..2d776ce74 100644 --- a/crates/buttplug_server_hwmgr_websocket/src/websocket_server_hardware.rs +++ b/crates/buttplug_server_hwmgr_websocket/src/websocket_server_hardware.rs @@ -7,7 +7,7 @@ use super::websocket_server_comm_manager::WebsocketServerDeviceCommManagerInitInfo; use async_trait::async_trait; -use buttplug_core::{errors::ButtplugDeviceError, util::async_manager}; +use buttplug_core::errors::ButtplugDeviceError; use buttplug_server::device::hardware::{ GenericHardwareSpecializer, Hardware, @@ -305,7 +305,7 @@ impl HardwareInternal for WebsocketServerHardware { subscribed.store(true, Ordering::Relaxed); let token = CancellationToken::new(); *(subscribed_token.lock().await) = Some(token.child_token()); - async_manager::spawn(async move { + buttplug_core::spawn!("WebsocketServerHardware subscription", async move { loop { select! { result = data_receiver.recv().fuse() => { diff --git a/crates/buttplug_server_hwmgr_xinput/src/xinput_hardware.rs b/crates/buttplug_server_hwmgr_xinput/src/xinput_hardware.rs index 29d3a4fe3..578174c67 100644 --- a/crates/buttplug_server_hwmgr_xinput/src/xinput_hardware.rs +++ b/crates/buttplug_server_hwmgr_xinput/src/xinput_hardware.rs @@ -7,7 +7,7 @@ use super::xinput_device_comm_manager::XInputControllerIndex; use async_trait::async_trait; -use buttplug_core::{errors::ButtplugDeviceError, util::async_manager}; +use buttplug_core::errors::ButtplugDeviceError; use buttplug_server::device::hardware::{ GenericHardwareSpecializer, Hardware, @@ -113,7 +113,7 @@ impl XInputHardware { let token = CancellationToken::new(); let child = token.child_token(); let sender = device_event_sender.clone(); - async_manager::spawn(async move { + buttplug_core::spawn!("XInputHardware connectivity check", async move { check_gamepad_connectivity(index, sender, child).await; }); Self { From 3b3f2d106f800af01d2b24780a8860a3f84c0c06 Mon Sep 17 00:00:00 2001 From: Jasmin Bom Date: Sun, 15 Mar 2026 15:12:10 +0100 Subject: [PATCH 07/10] buttplug_transport_websocket_tungstenite: migrate from async_manager to buttplug_core::spawn --- .../src/websocket_client.rs | 4 +--- .../src/websocket_server.rs | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/crates/buttplug_transport_websocket_tungstenite/src/websocket_client.rs b/crates/buttplug_transport_websocket_tungstenite/src/websocket_client.rs index d5dba5444..b48621e9a 100644 --- a/crates/buttplug_transport_websocket_tungstenite/src/websocket_client.rs +++ b/crates/buttplug_transport_websocket_tungstenite/src/websocket_client.rs @@ -18,7 +18,6 @@ use buttplug_core::{ }, }, message::serializer::ButtplugSerializedMessage, - util::async_manager, }; use futures::{FutureExt, SinkExt, StreamExt, future::BoxFuture}; use rustls::{ @@ -183,7 +182,7 @@ impl ButtplugConnectorTransport for ButtplugWebsocketClientTransport { Ok((stream, _)) => { let (mut writer, mut reader) = stream.split(); - async_manager::spawn( + buttplug_core::spawn!("ButtplugWebsocketClientTransport I/O", async move { loop { select! { @@ -288,7 +287,6 @@ impl ButtplugConnectorTransport for ButtplugWebsocketClientTransport { } } } - .instrument(tracing::info_span!("Websocket Client I/O Task")), ); Ok(()) } diff --git a/crates/buttplug_transport_websocket_tungstenite/src/websocket_server.rs b/crates/buttplug_transport_websocket_tungstenite/src/websocket_server.rs index 0c2addbb3..288cb199a 100644 --- a/crates/buttplug_transport_websocket_tungstenite/src/websocket_server.rs +++ b/crates/buttplug_transport_websocket_tungstenite/src/websocket_server.rs @@ -16,7 +16,6 @@ use buttplug_core::{ }, }, message::serializer::ButtplugSerializedMessage, - util::async_manager, }; use futures::{FutureExt, SinkExt, StreamExt, future::BoxFuture}; use std::{sync::Arc, time::Duration}; @@ -237,7 +236,7 @@ impl ButtplugConnectorTransport for ButtplugWebsocketServerTransport { ButtplugConnectorTransportSpecificError::GenericNetworkError(format!("{err:?}")), ) })?; - async_manager::spawn(async move { + buttplug_core::spawn!("ButtplugWebsocketServerTransport connection loop", async move { run_connection_loop( ws_stream, outgoing_receiver, From ba30897d89f945342a0b3a075163c43eee86fb5a Mon Sep 17 00:00:00 2001 From: Jasmin Bom Date: Sun, 15 Mar 2026 15:25:06 +0100 Subject: [PATCH 08/10] Allow unnamed tasks in spawn! macro, and use it for tests. --- crates/buttplug_core/src/util/async_manager/mod.rs | 5 +++++ crates/buttplug_tests/tests/test_serializers.rs | 5 ++--- crates/buttplug_tests/tests/util/channel_transport.rs | 5 ++--- .../tests/util/device_test/client/client_v2/client.rs | 11 ++++------- .../client/client_v2/in_process_connector.rs | 4 ++-- .../tests/util/device_test/client/client_v2/mod.rs | 5 ++--- .../tests/util/device_test/client/client_v3/client.rs | 11 ++++------- .../client_v3/connector/in_process_connector.rs | 5 ++--- .../tests/util/device_test/client/client_v3/mod.rs | 5 ++--- .../tests/util/device_test/client/client_v4/mod.rs | 6 +++--- .../util/device_test/connector/channel_transport.rs | 3 +-- .../tests/util/test_device_manager/test_device.rs | 4 ++-- crates/buttplug_tests/tests/util/test_server.rs | 3 +-- crates/intiface_engine/src/remote_server.rs | 4 ++-- 14 files changed, 34 insertions(+), 42 deletions(-) diff --git a/crates/buttplug_core/src/util/async_manager/mod.rs b/crates/buttplug_core/src/util/async_manager/mod.rs index effc4a960..d24312736 100644 --- a/crates/buttplug_core/src/util/async_manager/mod.rs +++ b/crates/buttplug_core/src/util/async_manager/mod.rs @@ -85,8 +85,13 @@ pub async fn sleep(duration: Duration) { get_global_async_manager().sleep(duration).await; } +/// Spawn a fire-and-forget task on the global async manager. +/// Always prefer to add a name to the task for better tracing context. #[macro_export] macro_rules! spawn { + ($future:expr) => { + $crate::util::async_manager::spawn($future, tracing::span!(tracing::Level::INFO, "Buttplug Async Task")) + }; ($name:expr, $future:expr) => { $crate::util::async_manager::spawn($future, tracing::span!(tracing::Level::INFO, $name)) }; diff --git a/crates/buttplug_tests/tests/test_serializers.rs b/crates/buttplug_tests/tests/test_serializers.rs index 906f84ec2..5dd3f5a87 100644 --- a/crates/buttplug_tests/tests/test_serializers.rs +++ b/crates/buttplug_tests/tests/test_serializers.rs @@ -19,7 +19,6 @@ use buttplug_core::{ ErrorV0, serializer::ButtplugSerializedMessage, }, - util::async_manager, }; use buttplug_server::message::{ ButtplugClientMessageVariant, @@ -38,7 +37,7 @@ async fn test_garbled_client_rsi_response() { let helper_clone = helper.clone(); let finish_notifier = Arc::new(Notify::new()); let finish_notifier_clone = finish_notifier.clone(); - async_manager::spawn(async move { + buttplug_core::spawn!(async move { helper_clone .connect_without_reply() .await @@ -72,7 +71,7 @@ async fn test_serialized_error_relay() { let helper = Arc::new(ChannelClientTestHelper::new()); helper.simulate_successful_connect().await; let helper_clone = helper.clone(); - async_manager::spawn(async move { + buttplug_core::spawn!(async move { assert!(matches!( helper_clone.next_client_message().await, ButtplugClientMessageVariant::V4(ButtplugClientMessageV4::StartScanning(..)) diff --git a/crates/buttplug_tests/tests/util/channel_transport.rs b/crates/buttplug_tests/tests/util/channel_transport.rs index f38cdcad5..6da2f36fe 100644 --- a/crates/buttplug_tests/tests/util/channel_transport.rs +++ b/crates/buttplug_tests/tests/util/channel_transport.rs @@ -29,7 +29,6 @@ use buttplug_core::{ ServerInfoV4, serializer::{ButtplugMessageSerializer, ButtplugSerializedMessage}, }, - util::async_manager, }; use buttplug_server::{ connector::ButtplugRemoteServerConnector, @@ -80,7 +79,7 @@ impl ButtplugConnectorTransport for ChannelTransport { let disconnect_notifier = self.disconnect_notifier.clone(); let outside_sender = self.outside_sender.clone(); let outside_receiver_mutex = self.outside_receiver.clone(); - async_manager::spawn(async move { + buttplug_core::spawn!(async move { let mut outside_receiver = outside_receiver_mutex .lock() .await @@ -191,7 +190,7 @@ impl ChannelClientTestHelper { .expect("Test, assuming infallible"); let finish_notifier = Arc::new(Notify::new()); let finish_notifier_clone = finish_notifier.clone(); - async_manager::spawn(async move { + buttplug_core::spawn!(async move { if let Err(e) = client_clone.connect(connector).await { assert!(false, "Error connecting to client: {:?}", e); } diff --git a/crates/buttplug_tests/tests/util/device_test/client/client_v2/client.rs b/crates/buttplug_tests/tests/util/device_test/client/client_v2/client.rs index 4a53a6743..8d1350173 100644 --- a/crates/buttplug_tests/tests/util/device_test/client/client_v2/client.rs +++ b/crates/buttplug_tests/tests/util/device_test/client/client_v2/client.rs @@ -18,7 +18,7 @@ use buttplug_core::{ StartScanningV0, StopScanningV0, }, - util::{async_manager, stream::convert_broadcast_receiver_to_stream}, + util::stream::convert_broadcast_receiver_to_stream, }; use buttplug_server::message::{ ButtplugClientMessageV2, @@ -220,12 +220,9 @@ impl ButtplugClient { ); // Start the event loop before we run the handshake. - async_manager::spawn( - async move { - client_event_loop.run().await; - } - .instrument(tracing::info_span!("Client Loop Span")), - ); + buttplug_core::spawn!("ButtplugClient event loop", async move { + client_event_loop.run().await; + }); self.run_handshake().await } diff --git a/crates/buttplug_tests/tests/util/device_test/client/client_v2/in_process_connector.rs b/crates/buttplug_tests/tests/util/device_test/client/client_v2/in_process_connector.rs index 7138d18cd..e4e5254cf 100644 --- a/crates/buttplug_tests/tests/util/device_test/client/client_v2/in_process_connector.rs +++ b/crates/buttplug_tests/tests/util/device_test/client/client_v2/in_process_connector.rs @@ -115,7 +115,7 @@ impl ButtplugConnector self.server_outbound_sender = message_sender; let server_recv = self.server.event_stream(); async move { - async_manager::spawn(async move { + buttplug_core::spawn!("InProcessClientConnector event sender loop", async move { info!("Starting In Process Client Connector Event Sender Loop"); pin_mut!(server_recv); while let Some(event) = server_recv.next().await { @@ -133,7 +133,7 @@ impl ButtplugConnector } } info!("Stopping In Process Client Connector Event Sender Loop, due to channel receiver being dropped."); - }.instrument(tracing::info_span!("InProcessClientConnectorEventSenderLoop"))); + }); connected.store(true, Ordering::Relaxed); Ok(()) }.boxed() diff --git a/crates/buttplug_tests/tests/util/device_test/client/client_v2/mod.rs b/crates/buttplug_tests/tests/util/device_test/client/client_v2/mod.rs index 1a738edf0..6ef25a783 100644 --- a/crates/buttplug_tests/tests/util/device_test/client/client_v2/mod.rs +++ b/crates/buttplug_tests/tests/util/device_test/client/client_v2/mod.rs @@ -16,7 +16,6 @@ use crate::util::{ TestDeviceChannelHost, device_test::connector::build_channel_connector_v2, }; -use buttplug_core::util::async_manager; use buttplug_server::{ButtplugServer, ButtplugServerBuilder, device::ServerDeviceManagerBuilder}; use buttplug_server_device_config::load_protocol_configs; @@ -78,7 +77,7 @@ async fn run_test_client_command(command: &TestClientCommand, device: &Arc self.server_outbound_sender = message_sender; let server_recv = self.server.event_stream(); async move { - async_manager::spawn(async move { + buttplug_core::spawn!("InProcessClientConnector event sender loop", async move { info!("Starting In Process Client Connector Event Sender Loop"); pin_mut!(server_recv); while let Some(event) = server_recv.next().await { @@ -131,7 +130,7 @@ impl ButtplugConnector } } info!("Stopping In Process Client Connector Event Sender Loop, due to channel receiver being dropped."); - }.instrument(tracing::info_span!("InProcessClientConnectorEventSenderLoop"))); + }); connected.store(true, Ordering::Relaxed); Ok(()) }.boxed() diff --git a/crates/buttplug_tests/tests/util/device_test/client/client_v3/mod.rs b/crates/buttplug_tests/tests/util/device_test/client/client_v3/mod.rs index 8ef64567b..fe8613e81 100644 --- a/crates/buttplug_tests/tests/util/device_test/client/client_v3/mod.rs +++ b/crates/buttplug_tests/tests/util/device_test/client/client_v3/mod.rs @@ -21,7 +21,6 @@ use crate::util::{ use client::{ButtplugClient, ButtplugClientDevice, ButtplugClientEvent}; use device::{LinearCommand, RotateCommand, ScalarCommand, ScalarValueCommand}; -use buttplug_core::util::async_manager; use buttplug_server::{ButtplugServer, ButtplugServerBuilder, device::ServerDeviceManagerBuilder}; use buttplug_server_device_config::load_protocol_configs; use tokio::sync::Notify; @@ -89,7 +88,7 @@ async fn run_test_client_command(command: &TestClientCommand, device: &Arc { diff --git a/crates/buttplug_tests/tests/util/test_server.rs b/crates/buttplug_tests/tests/util/test_server.rs index d8056d3f5..4576b932a 100644 --- a/crates/buttplug_tests/tests/util/test_server.rs +++ b/crates/buttplug_tests/tests/util/test_server.rs @@ -9,7 +9,6 @@ use buttplug_core::{ connector::ButtplugConnector, errors::ButtplugError, message::{ButtplugMessage, ButtplugMessageValidator, ErrorV0}, - util::async_manager, }; use buttplug_server::{ ButtplugServer, @@ -57,7 +56,7 @@ async fn run_server( trace!("Got message from connector: {:?}", client_message); let server_clone = server.clone(); let connector_clone = shared_connector.clone(); - async_manager::spawn(async move { + buttplug_core::spawn!(async move { if let Err(e) = client_message.is_valid() { error!("Message not valid: {:?} - Error: {}", client_message, e); let mut err_msg = ErrorV0::from(ButtplugError::from(e)); diff --git a/crates/intiface_engine/src/remote_server.rs b/crates/intiface_engine/src/remote_server.rs index d0c375369..2fa88cafb 100644 --- a/crates/intiface_engine/src/remote_server.rs +++ b/crates/intiface_engine/src/remote_server.rs @@ -8,7 +8,7 @@ use buttplug_core::{ connector::ButtplugConnector, errors::{ButtplugError, ButtplugHandshakeError}, message::{ButtplugMessageSpecVersion, ButtplugServerMessageV4}, - util::{async_manager, stream::convert_broadcast_receiver_to_stream}, + util::{stream::convert_broadcast_receiver_to_stream}, }; use buttplug_server::{ ButtplugServer, ButtplugServerBuilder, @@ -151,7 +151,7 @@ async fn run_server( let connector_clone = shared_connector.clone(); let remote_event_sender_clone = remote_event_sender.clone(); let disconnect_notifier = disconnect_notifier.clone(); - async_manager::spawn(async move { + buttplug_core::spawn!("ButtplugRemoteServer loop", async move { match server_clone.parse_message(client_message.clone()).await { Ok(ret_msg) => { // Only send event if we just connected. Sucks to check it on every message but the boolean check should be quick. From 0418b2400d4dec2fb5126f7db3f6f07fab8aa575 Mon Sep 17 00:00:00 2001 From: Jasmin Bom Date: Sun, 15 Mar 2026 15:37:02 +0100 Subject: [PATCH 09/10] Fix feature propagation Makes it so it's possible to disable for downstream users to disable default features and not have to worry about features being re-enabled by dependencies. --- crates/buttplug_client/Cargo.toml | 7 ++++++- crates/buttplug_client_in_process/Cargo.toml | 10 ++++++---- crates/buttplug_server/Cargo.toml | 7 ++++--- .../src/device/protocol_impl/nintendo_joycon.rs | 2 +- crates/buttplug_server_device_config/Cargo.toml | 2 +- crates/buttplug_server_hwmgr_btleplug/Cargo.toml | 4 ++-- crates/buttplug_server_hwmgr_hid/Cargo.toml | 4 ++-- .../buttplug_server_hwmgr_lovense_connect/Cargo.toml | 4 ++-- crates/buttplug_server_hwmgr_lovense_dongle/Cargo.toml | 4 ++-- crates/buttplug_server_hwmgr_serial/Cargo.toml | 4 ++-- crates/buttplug_server_hwmgr_websocket/Cargo.toml | 4 ++-- crates/buttplug_server_hwmgr_xinput/Cargo.toml | 4 ++-- 12 files changed, 32 insertions(+), 24 deletions(-) diff --git a/crates/buttplug_client/Cargo.toml b/crates/buttplug_client/Cargo.toml index 30c8aa900..9e9538b66 100644 --- a/crates/buttplug_client/Cargo.toml +++ b/crates/buttplug_client/Cargo.toml @@ -18,8 +18,13 @@ test = true doctest = true doc = true +[features] +default = ["tokio-runtime"] +tokio-runtime = ["buttplug_core/tokio-runtime"] +wasm = ["buttplug_core/wasm"] + [dependencies] -buttplug_core = { version = "10.0.1", path = "../buttplug_core" } +buttplug_core = { version = "10.0.1", path = "../buttplug_core", default-features = false } futures = "0.3.32" thiserror = "2.0.18" log = "0.4.29" diff --git a/crates/buttplug_client_in_process/Cargo.toml b/crates/buttplug_client_in_process/Cargo.toml index 305653926..d968c9d69 100644 --- a/crates/buttplug_client_in_process/Cargo.toml +++ b/crates/buttplug_client_in_process/Cargo.toml @@ -20,7 +20,7 @@ doc = true [features] -default = ["btleplug-manager", "hid-manager", "lovense-dongle-manager", "lovense-connect-service-manager", "serial-manager", "websocket-manager", "xinput-manager"] +default = ["tokio-runtime", "btleplug-manager", "hid-manager", "lovense-dongle-manager", "lovense-connect-service-manager", "serial-manager", "websocket-manager", "xinput-manager"] btleplug-manager=["buttplug_server_hwmgr_btleplug"] hid-manager=["buttplug_server_hwmgr_hid"] lovense-dongle-manager=["buttplug_server_hwmgr_lovense_dongle"] @@ -28,11 +28,13 @@ lovense-connect-service-manager=["buttplug_server_hwmgr_lovense_connect"] serial-manager=["buttplug_server_hwmgr_serial"] websocket-manager=["buttplug_server_hwmgr_websocket"] xinput-manager=["buttplug_server_hwmgr_xinput"] +tokio-runtime = ["buttplug_core/tokio-runtime", "buttplug_client/tokio-runtime", "buttplug_server/tokio-runtime"] +wasm = ["buttplug_core/wasm", "buttplug_client/wasm", "buttplug_server/wasm"] [dependencies] -buttplug_core = { version = "10.0.1", path = "../buttplug_core" } -buttplug_client = { version = "10.0.1", path = "../buttplug_client" } -buttplug_server = { version = "10.0.1", path = "../buttplug_server" } +buttplug_core = { version = "10.0.1", path = "../buttplug_core", default-features = false } +buttplug_client = { version = "10.0.1", path = "../buttplug_client", default-features = false } +buttplug_server = { version = "10.0.1", path = "../buttplug_server", default-features = false } buttplug_server_device_config = { version = "10.0.2", path = "../buttplug_server_device_config" } buttplug_server_hwmgr_btleplug = { version = "10.0.1", path = "../buttplug_server_hwmgr_btleplug", optional = true} buttplug_server_hwmgr_hid = { version = "10.0.0", path = "../buttplug_server_hwmgr_hid", optional = true} diff --git a/crates/buttplug_server/Cargo.toml b/crates/buttplug_server/Cargo.toml index 9c684d957..c5672105c 100644 --- a/crates/buttplug_server/Cargo.toml +++ b/crates/buttplug_server/Cargo.toml @@ -20,11 +20,12 @@ doc = true crate-type = ["cdylib", "rlib"] [features] -default=[] -wasm=["uuid/js"] +default=["tokio-runtime"] +tokio-runtime=["buttplug_core/tokio-runtime"] +wasm=["buttplug_core/wasm", "uuid/js"] [dependencies] -buttplug_core = { version = "10.0.1", path = "../buttplug_core" } +buttplug_core = { version = "10.0.1", path = "../buttplug_core", default-features = false } buttplug_server_device_config = { version = "10.0.2", path = "../buttplug_server_device_config" } futures = "0.3.32" futures-util = "0.3.32" diff --git a/crates/buttplug_server/src/device/protocol_impl/nintendo_joycon.rs b/crates/buttplug_server/src/device/protocol_impl/nintendo_joycon.rs index 7a4bd711b..4ce09c161 100644 --- a/crates/buttplug_server/src/device/protocol_impl/nintendo_joycon.rs +++ b/crates/buttplug_server/src/device/protocol_impl/nintendo_joycon.rs @@ -259,7 +259,7 @@ impl NintendoJoycon { let speed_val = Arc::new(AtomicU16::new(0)); let speed_val_clone = speed_val.clone(); let notifier = Arc::new(Notify::new()); - #[cfg(not(feature = "wasm"))] + #[cfg(feature = "tokio-runtime")] let notifier_clone = notifier.clone(); let is_stopped = Arc::new(AtomicBool::new(false)); let is_stopped_clone = is_stopped.clone(); diff --git a/crates/buttplug_server_device_config/Cargo.toml b/crates/buttplug_server_device_config/Cargo.toml index 036cf4a98..035d76b50 100644 --- a/crates/buttplug_server_device_config/Cargo.toml +++ b/crates/buttplug_server_device_config/Cargo.toml @@ -19,7 +19,7 @@ doctest = true doc = true [dependencies] -buttplug_core = { version = "10.0.1", path = "../buttplug_core" } +buttplug_core = { version = "10.0.1", path = "../buttplug_core", default-features = false } futures = "0.3.32" futures-util = "0.3.32" serde = { version = "1.0.228", features = ["derive"] } diff --git a/crates/buttplug_server_hwmgr_btleplug/Cargo.toml b/crates/buttplug_server_hwmgr_btleplug/Cargo.toml index 287be6607..b9c2ef205 100644 --- a/crates/buttplug_server_hwmgr_btleplug/Cargo.toml +++ b/crates/buttplug_server_hwmgr_btleplug/Cargo.toml @@ -20,8 +20,8 @@ doc = true [dependencies] -buttplug_core = { version = "10.0.1", path = "../buttplug_core" } -buttplug_server = { version = "10.0.1", path = "../buttplug_server" } +buttplug_core = { version = "10.0.1", path = "../buttplug_core", default-features = false } +buttplug_server = { version = "10.0.1", path = "../buttplug_server", default-features = false } buttplug_server_device_config = { version = "10.0.2", path = "../buttplug_server_device_config" } futures = "0.3.32" futures-util = "0.3.32" diff --git a/crates/buttplug_server_hwmgr_hid/Cargo.toml b/crates/buttplug_server_hwmgr_hid/Cargo.toml index f58001d7d..244c680f1 100644 --- a/crates/buttplug_server_hwmgr_hid/Cargo.toml +++ b/crates/buttplug_server_hwmgr_hid/Cargo.toml @@ -20,8 +20,8 @@ doc = true [dependencies] -buttplug_core = { version = "10.0.1", path = "../buttplug_core" } -buttplug_server = { version = "10.0.1", path = "../buttplug_server" } +buttplug_core = { version = "10.0.1", path = "../buttplug_core", default-features = false } +buttplug_server = { version = "10.0.1", path = "../buttplug_server", default-features = false } buttplug_server_device_config = { version = "10.0.2", path = "../buttplug_server_device_config" } futures = "0.3.32" futures-util = "0.3.32" diff --git a/crates/buttplug_server_hwmgr_lovense_connect/Cargo.toml b/crates/buttplug_server_hwmgr_lovense_connect/Cargo.toml index 167c7c469..4dfb44ac8 100644 --- a/crates/buttplug_server_hwmgr_lovense_connect/Cargo.toml +++ b/crates/buttplug_server_hwmgr_lovense_connect/Cargo.toml @@ -27,8 +27,8 @@ targets = [] features = ["default", "unstable"] [dependencies] -buttplug_core = { version = "10.0.1", path = "../buttplug_core" } -buttplug_server = { version = "10.0.1", path = "../buttplug_server" } +buttplug_core = { version = "10.0.1", path = "../buttplug_core", default-features = false } +buttplug_server = { version = "10.0.1", path = "../buttplug_server", default-features = false } buttplug_server_device_config = { version = "10.0.2", path = "../buttplug_server_device_config" } futures = "0.3.32" futures-util = "0.3.32" diff --git a/crates/buttplug_server_hwmgr_lovense_dongle/Cargo.toml b/crates/buttplug_server_hwmgr_lovense_dongle/Cargo.toml index 32c8f32e1..456f44d68 100644 --- a/crates/buttplug_server_hwmgr_lovense_dongle/Cargo.toml +++ b/crates/buttplug_server_hwmgr_lovense_dongle/Cargo.toml @@ -20,8 +20,8 @@ doc = true [dependencies] -buttplug_core = { version = "10.0.1", path = "../buttplug_core" } -buttplug_server = { version = "10.0.1", path = "../buttplug_server" } +buttplug_core = { version = "10.0.1", path = "../buttplug_core", default-features = false } +buttplug_server = { version = "10.0.1", path = "../buttplug_server", default-features = false } buttplug_server_device_config = { version = "10.0.2", path = "../buttplug_server_device_config" } futures = "0.3.32" futures-util = "0.3.32" diff --git a/crates/buttplug_server_hwmgr_serial/Cargo.toml b/crates/buttplug_server_hwmgr_serial/Cargo.toml index 1b5daed24..fb2290300 100644 --- a/crates/buttplug_server_hwmgr_serial/Cargo.toml +++ b/crates/buttplug_server_hwmgr_serial/Cargo.toml @@ -20,8 +20,8 @@ doc = true [dependencies] -buttplug_core = { version = "10.0.1", path = "../buttplug_core" } -buttplug_server = { version = "10.0.1", path = "../buttplug_server" } +buttplug_core = { version = "10.0.1", path = "../buttplug_core", default-features = false } +buttplug_server = { version = "10.0.1", path = "../buttplug_server", default-features = false } buttplug_server_device_config = { version = "10.0.2", path = "../buttplug_server_device_config" } futures = "0.3.32" futures-util = "0.3.32" diff --git a/crates/buttplug_server_hwmgr_websocket/Cargo.toml b/crates/buttplug_server_hwmgr_websocket/Cargo.toml index 7f150a080..f3019608d 100644 --- a/crates/buttplug_server_hwmgr_websocket/Cargo.toml +++ b/crates/buttplug_server_hwmgr_websocket/Cargo.toml @@ -27,8 +27,8 @@ targets = [] features = ["default", "unstable"] [dependencies] -buttplug_core = { version = "10.0.1", path = "../buttplug_core" } -buttplug_server = { version = "10.0.1", path = "../buttplug_server" } +buttplug_core = { version = "10.0.1", path = "../buttplug_core", default-features = false } +buttplug_server = { version = "10.0.1", path = "../buttplug_server", default-features = false } buttplug_server_device_config = { version = "10.0.2", path = "../buttplug_server_device_config" } futures = "0.3.32" futures-util = "0.3.32" diff --git a/crates/buttplug_server_hwmgr_xinput/Cargo.toml b/crates/buttplug_server_hwmgr_xinput/Cargo.toml index d3b0c0050..7a30c4cdf 100644 --- a/crates/buttplug_server_hwmgr_xinput/Cargo.toml +++ b/crates/buttplug_server_hwmgr_xinput/Cargo.toml @@ -20,8 +20,8 @@ doc = true [dependencies] -buttplug_core = { version = "10.0.1", path = "../buttplug_core" } -buttplug_server = { version = "10.0.1", path = "../buttplug_server" } +buttplug_core = { version = "10.0.1", path = "../buttplug_core", default-features = false} +buttplug_server = { version = "10.0.1", path = "../buttplug_server", default-features = false} buttplug_server_device_config = { version = "10.0.2", path = "../buttplug_server_device_config" } futures = "0.3.32" futures-util = "0.3.32" From b35eb1496eeea3dc0845257fec7b58453a86453f Mon Sep 17 00:00:00 2001 From: Jasmin Bom Date: Sun, 15 Mar 2026 15:44:07 +0100 Subject: [PATCH 10/10] Cleanup unused imports and dependencies --- crates/buttplug_client/Cargo.toml | 1 - crates/buttplug_client/src/lib.rs | 1 - crates/buttplug_client_in_process/Cargo.toml | 1 - crates/buttplug_client_in_process/src/in_process_connector.rs | 1 - crates/buttplug_core/src/connector/remote_connector.rs | 1 - crates/buttplug_core/src/connector/transport/stream.rs | 1 - .../buttplug_server/src/device/protocol_impl/nintendo_joycon.rs | 2 +- crates/buttplug_tests/Cargo.toml | 1 - crates/buttplug_tests/tests/test_client_device.rs | 2 +- .../tests/util/device_test/client/client_v2/client.rs | 1 - .../tests/util/device_test/client/client_v2/device.rs | 2 +- .../util/device_test/client/client_v2/in_process_connector.rs | 2 -- .../tests/util/device_test/client/client_v3/client.rs | 1 - .../client/client_v3/connector/in_process_connector.rs | 1 - .../src/websocket_client.rs | 1 - 15 files changed, 3 insertions(+), 16 deletions(-) diff --git a/crates/buttplug_client/Cargo.toml b/crates/buttplug_client/Cargo.toml index 9e9538b66..6095cef6d 100644 --- a/crates/buttplug_client/Cargo.toml +++ b/crates/buttplug_client/Cargo.toml @@ -31,7 +31,6 @@ log = "0.4.29" getset = "0.1.6" tokio = { version = "1.50.0", features = ["macros"] } dashmap = { version = "6.1.0" } -tracing-futures = "0.2.5" tracing = "0.1.44" serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.149" diff --git a/crates/buttplug_client/src/lib.rs b/crates/buttplug_client/src/lib.rs index d1b837e5b..d9cd1197c 100644 --- a/crates/buttplug_client/src/lib.rs +++ b/crates/buttplug_client/src/lib.rs @@ -53,7 +53,6 @@ use std::{ use strum_macros::Display; use thiserror::Error; use tokio::sync::{Mutex, broadcast, mpsc}; -use tracing_futures::Instrument; /// Result type used for public APIs. /// diff --git a/crates/buttplug_client_in_process/Cargo.toml b/crates/buttplug_client_in_process/Cargo.toml index d968c9d69..513518bc5 100644 --- a/crates/buttplug_client_in_process/Cargo.toml +++ b/crates/buttplug_client_in_process/Cargo.toml @@ -50,5 +50,4 @@ log = "0.4.29" getset = "0.1.6" tokio = { version = "1.50.0", features = ["macros"] } dashmap = { version = "6.1.0" } -tracing-futures = "0.2.5" tracing = "0.1.44" diff --git a/crates/buttplug_client_in_process/src/in_process_connector.rs b/crates/buttplug_client_in_process/src/in_process_connector.rs index aac874933..fb20ecd37 100644 --- a/crates/buttplug_client_in_process/src/in_process_connector.rs +++ b/crates/buttplug_client_in_process/src/in_process_connector.rs @@ -28,7 +28,6 @@ use std::sync::{ atomic::{AtomicBool, Ordering}, }; use tokio::sync::mpsc::{Sender, channel}; -use tracing_futures::Instrument; #[derive(Default)] pub struct ButtplugInProcessClientConnectorBuilder { diff --git a/crates/buttplug_core/src/connector/remote_connector.rs b/crates/buttplug_core/src/connector/remote_connector.rs index c65e3e5b2..7bb34f1c9 100644 --- a/crates/buttplug_core/src/connector/remote_connector.rs +++ b/crates/buttplug_core/src/connector/remote_connector.rs @@ -18,7 +18,6 @@ use crate::{ ButtplugMessage, serializer::{ButtplugMessageSerializer, ButtplugSerializedMessage}, }, - util::async_manager, }; use futures::{FutureExt, future::BoxFuture, select}; use log::*; diff --git a/crates/buttplug_core/src/connector/transport/stream.rs b/crates/buttplug_core/src/connector/transport/stream.rs index 3562c2ce6..edd26fe5a 100644 --- a/crates/buttplug_core/src/connector/transport/stream.rs +++ b/crates/buttplug_core/src/connector/transport/stream.rs @@ -15,7 +15,6 @@ use crate::{ transport::{ButtplugConnectorTransport, ButtplugTransportIncomingMessage}, }, message::serializer::ButtplugSerializedMessage, - util::async_manager, }; use futures::{ FutureExt, diff --git a/crates/buttplug_server/src/device/protocol_impl/nintendo_joycon.rs b/crates/buttplug_server/src/device/protocol_impl/nintendo_joycon.rs index 4ce09c161..dc5f1e335 100644 --- a/crates/buttplug_server/src/device/protocol_impl/nintendo_joycon.rs +++ b/crates/buttplug_server/src/device/protocol_impl/nintendo_joycon.rs @@ -15,7 +15,7 @@ use crate::device::{ }, }; use async_trait::async_trait; -use buttplug_core::{errors::ButtplugDeviceError, util::async_manager}; +use buttplug_core::{errors::ButtplugDeviceError}; use buttplug_server_device_config::{ Endpoint, ProtocolCommunicationSpecifier, diff --git a/crates/buttplug_tests/Cargo.toml b/crates/buttplug_tests/Cargo.toml index d90e683a1..6ae39ea96 100644 --- a/crates/buttplug_tests/Cargo.toml +++ b/crates/buttplug_tests/Cargo.toml @@ -22,7 +22,6 @@ uuid = "1.22.0" futures = "0.3.32" tracing = "0.1.44" tracing-subscriber = "0.3.23" -tracing-futures = "0.2.5" tokio-test = "0.4.5" serde = "1.0.228" async-trait = "0.1.89" diff --git a/crates/buttplug_tests/tests/test_client_device.rs b/crates/buttplug_tests/tests/test_client_device.rs index 496a54949..5b480a674 100644 --- a/crates/buttplug_tests/tests/test_client_device.rs +++ b/crates/buttplug_tests/tests/test_client_device.rs @@ -7,7 +7,7 @@ mod util; use buttplug_client::{ButtplugClientDeviceEvent, ButtplugClientError, ButtplugClientEvent}; -use buttplug_core::{errors::ButtplugError, message::OutputType, util::async_manager}; +use buttplug_core::{errors::ButtplugError, message::OutputType}; use buttplug_server::device::hardware::{HardwareCommand, HardwareWriteCmd}; use buttplug_server_device_config::{ Endpoint, diff --git a/crates/buttplug_tests/tests/util/device_test/client/client_v2/client.rs b/crates/buttplug_tests/tests/util/device_test/client/client_v2/client.rs index 8d1350173..c1b272f91 100644 --- a/crates/buttplug_tests/tests/util/device_test/client/client_v2/client.rs +++ b/crates/buttplug_tests/tests/util/device_test/client/client_v2/client.rs @@ -40,7 +40,6 @@ use std::sync::{ use thiserror::Error; use tokio::sync::{Mutex, broadcast, mpsc, mpsc::error::SendError}; use tracing::{Level, Span, span}; -use tracing_futures::Instrument; /// Result type used for public APIs. /// diff --git a/crates/buttplug_tests/tests/util/device_test/client/client_v2/device.rs b/crates/buttplug_tests/tests/util/device_test/client/client_v2/device.rs index c0ffc0bb9..c019e0f6a 100644 --- a/crates/buttplug_tests/tests/util/device_test/client/client_v2/device.rs +++ b/crates/buttplug_tests/tests/util/device_test/client/client_v2/device.rs @@ -49,7 +49,7 @@ use std::{ }, }; use tokio::sync::{broadcast, mpsc}; -use tracing_futures::Instrument; +use tracing::Instrument; /// Enum for messages going to a [ButtplugClientDevice] instance. #[derive(Clone, Debug)] diff --git a/crates/buttplug_tests/tests/util/device_test/client/client_v2/in_process_connector.rs b/crates/buttplug_tests/tests/util/device_test/client/client_v2/in_process_connector.rs index e4e5254cf..f4f3e63c8 100644 --- a/crates/buttplug_tests/tests/util/device_test/client/client_v2/in_process_connector.rs +++ b/crates/buttplug_tests/tests/util/device_test/client/client_v2/in_process_connector.rs @@ -10,7 +10,6 @@ use buttplug_core::{ connector::{ButtplugConnector, ButtplugConnectorError, ButtplugConnectorResultFuture}, errors::{ButtplugError, ButtplugMessageError}, - util::async_manager, }; use buttplug_server::{ ButtplugServer, @@ -28,7 +27,6 @@ use std::sync::{ atomic::{AtomicBool, Ordering}, }; use tokio::sync::mpsc::{Sender, channel}; -use tracing_futures::Instrument; #[derive(Default)] pub struct ButtplugInProcessClientConnectorBuilder { diff --git a/crates/buttplug_tests/tests/util/device_test/client/client_v3/client.rs b/crates/buttplug_tests/tests/util/device_test/client/client_v3/client.rs index f27ef3d0b..2408a1221 100644 --- a/crates/buttplug_tests/tests/util/device_test/client/client_v3/client.rs +++ b/crates/buttplug_tests/tests/util/device_test/client/client_v3/client.rs @@ -38,7 +38,6 @@ use std::sync::{ }; use thiserror::Error; use tokio::sync::{Mutex, broadcast, mpsc}; -use tracing_futures::Instrument; /// Result type used for public APIs. /// diff --git a/crates/buttplug_tests/tests/util/device_test/client/client_v3/connector/in_process_connector.rs b/crates/buttplug_tests/tests/util/device_test/client/client_v3/connector/in_process_connector.rs index 3a936e7af..01b6c7e46 100644 --- a/crates/buttplug_tests/tests/util/device_test/client/client_v3/connector/in_process_connector.rs +++ b/crates/buttplug_tests/tests/util/device_test/client/client_v3/connector/in_process_connector.rs @@ -27,7 +27,6 @@ use std::sync::{ atomic::{AtomicBool, Ordering}, }; use tokio::sync::mpsc::{Sender, channel}; -use tracing_futures::Instrument; #[derive(Default)] pub struct ButtplugInProcessClientConnectorBuilder { diff --git a/crates/buttplug_transport_websocket_tungstenite/src/websocket_client.rs b/crates/buttplug_transport_websocket_tungstenite/src/websocket_client.rs index b48621e9a..89dc33d19 100644 --- a/crates/buttplug_transport_websocket_tungstenite/src/websocket_client.rs +++ b/crates/buttplug_transport_websocket_tungstenite/src/websocket_client.rs @@ -39,7 +39,6 @@ use tokio_tungstenite::{ connect_async_tls_with_config, tungstenite::protocol::Message, }; -use tracing::Instrument; use url::Url; pub fn get_rustls_config_dangerous() -> ClientConfig {