feat: upgrade buttplug package to protocol v4 and WASM v10
All checks were successful
Build and Push Docker Image to Gitea / build-and-push (push) Successful in 7m30s
All checks were successful
Build and Push Docker Image to Gitea / build-and-push (push) Successful in 7m30s
Upgrade the buttplug TypeScript client from class-based v3 protocol to interface-based v4 protocol, and the Rust/WASM server from the monolithic buttplug 9.0.9 crate to the split buttplug_core/buttplug_server/ buttplug_server_device_config 10.0.0 crates. TypeScript changes: - Messages are now plain interfaces with msgId()/setMsgId() helpers - ActuatorType → OutputType, SensorType → InputType - ScalarCmd/RotateCmd/LinearCmd → OutputCmd, SensorReadCmd → InputCmd - Client.ts → ButtplugClient.ts, new DeviceCommand/DeviceFeature files - Devices getter returns Map instead of array - Removed class-transformer/reflect-metadata dependencies Rust/WASM changes: - Split imports across buttplug_core, buttplug_server, buttplug_server_device_config - Removed ButtplugServerDowngradeWrapper (use ButtplugServer directly) - Replaced ButtplugFuture/ButtplugFutureStateShared with tokio::sync::oneshot - Updated Hardware::new for new 6-arg signature - Uses git fork (valknarthing/buttplug) to fix missing wasm deps in buttplug_core Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,25 +1,17 @@
|
||||
use async_trait::async_trait;
|
||||
use buttplug::{
|
||||
core::{
|
||||
errors::ButtplugDeviceError,
|
||||
message::Endpoint,
|
||||
},
|
||||
server::device::{
|
||||
configuration::{BluetoothLESpecifier, ProtocolCommunicationSpecifier},
|
||||
hardware::{
|
||||
Hardware,
|
||||
HardwareConnector,
|
||||
HardwareEvent,
|
||||
HardwareInternal,
|
||||
HardwareReadCmd,
|
||||
HardwareReading,
|
||||
HardwareSpecializer,
|
||||
HardwareSubscribeCmd,
|
||||
HardwareUnsubscribeCmd,
|
||||
HardwareWriteCmd,
|
||||
},
|
||||
},
|
||||
util::future::{ButtplugFuture, ButtplugFutureStateShared},
|
||||
use buttplug_core::errors::ButtplugDeviceError;
|
||||
use buttplug_server_device_config::{BluetoothLESpecifier, Endpoint, ProtocolCommunicationSpecifier};
|
||||
use buttplug_server::device::hardware::{
|
||||
Hardware,
|
||||
HardwareConnector,
|
||||
HardwareEvent,
|
||||
HardwareInternal,
|
||||
HardwareReadCmd,
|
||||
HardwareReading,
|
||||
HardwareSpecializer,
|
||||
HardwareSubscribeCmd,
|
||||
HardwareUnsubscribeCmd,
|
||||
HardwareWriteCmd,
|
||||
};
|
||||
use futures::future::{self, BoxFuture};
|
||||
use js_sys::{DataView, Uint8Array};
|
||||
@@ -28,7 +20,7 @@ use std::{
|
||||
convert::TryFrom,
|
||||
fmt::{self, Debug},
|
||||
};
|
||||
use tokio::sync::{broadcast, mpsc};
|
||||
use tokio::sync::{broadcast, mpsc, oneshot};
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen::JsCast;
|
||||
use wasm_bindgen_futures::{spawn_local, JsFuture};
|
||||
@@ -41,9 +33,6 @@ use web_sys::{
|
||||
MessageEvent,
|
||||
};
|
||||
|
||||
type WebBluetoothResultFuture = ButtplugFuture<Result<(), ButtplugDeviceError>>;
|
||||
type WebBluetoothReadResultFuture = ButtplugFuture<Result<HardwareReading, ButtplugDeviceError>>;
|
||||
|
||||
struct BluetoothDeviceWrapper {
|
||||
pub device: BluetoothDevice
|
||||
}
|
||||
@@ -179,7 +168,7 @@ impl HardwareSpecializer for WebBluetoothHardwareSpecializer {
|
||||
receiver,
|
||||
command_sender,
|
||||
));
|
||||
Ok(Hardware::new(&name, &address, &[], device_impl))
|
||||
Ok(Hardware::new(&name, &address, &[], &None, false, device_impl))
|
||||
}
|
||||
WebBluetoothEvent::Disconnected => Err(
|
||||
ButtplugDeviceError::DeviceCommunicationError(
|
||||
@@ -202,19 +191,19 @@ pub enum WebBluetoothEvent {
|
||||
pub enum WebBluetoothDeviceCommand {
|
||||
Write(
|
||||
HardwareWriteCmd,
|
||||
ButtplugFutureStateShared<Result<(), ButtplugDeviceError>>,
|
||||
oneshot::Sender<Result<(), ButtplugDeviceError>>,
|
||||
),
|
||||
Read(
|
||||
HardwareReadCmd,
|
||||
ButtplugFutureStateShared<Result<HardwareReading, ButtplugDeviceError>>,
|
||||
oneshot::Sender<Result<HardwareReading, ButtplugDeviceError>>,
|
||||
),
|
||||
Subscribe(
|
||||
HardwareSubscribeCmd,
|
||||
ButtplugFutureStateShared<Result<(), ButtplugDeviceError>>,
|
||||
oneshot::Sender<Result<(), ButtplugDeviceError>>,
|
||||
),
|
||||
Unsubscribe(
|
||||
HardwareUnsubscribeCmd,
|
||||
ButtplugFutureStateShared<Result<(), ButtplugDeviceError>>,
|
||||
oneshot::Sender<Result<(), ButtplugDeviceError>>,
|
||||
),
|
||||
}
|
||||
|
||||
@@ -287,7 +276,7 @@ async fn run_webbluetooth_loop(
|
||||
.await;
|
||||
while let Some(msg) = device_command_receiver.recv().await {
|
||||
match msg {
|
||||
WebBluetoothDeviceCommand::Write(write_cmd, waker) => {
|
||||
WebBluetoothDeviceCommand::Write(write_cmd, sender) => {
|
||||
debug!("Writing to endpoint {:?}", write_cmd.endpoint());
|
||||
let chr = char_map.get(&write_cmd.endpoint()).unwrap().clone();
|
||||
spawn_local(async move {
|
||||
@@ -295,10 +284,10 @@ async fn run_webbluetooth_loop(
|
||||
JsFuture::from(chr.write_value_with_u8_array(&uint8buf).unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
waker.set_reply(Ok(()));
|
||||
let _ = sender.send(Ok(()));
|
||||
});
|
||||
}
|
||||
WebBluetoothDeviceCommand::Read(read_cmd, waker) => {
|
||||
WebBluetoothDeviceCommand::Read(read_cmd, sender) => {
|
||||
debug!("Writing to endpoint {:?}", read_cmd.endpoint());
|
||||
let chr = char_map.get(&read_cmd.endpoint()).unwrap().clone();
|
||||
spawn_local(async move {
|
||||
@@ -307,10 +296,10 @@ async fn run_webbluetooth_loop(
|
||||
let mut body = vec![0; data_view.byte_length() as usize];
|
||||
Uint8Array::new(&data_view).copy_to(&mut body[..]);
|
||||
let reading = HardwareReading::new(read_cmd.endpoint(), &body);
|
||||
waker.set_reply(Ok(reading));
|
||||
let _ = sender.send(Ok(reading));
|
||||
});
|
||||
}
|
||||
WebBluetoothDeviceCommand::Subscribe(subscribe_cmd, waker) => {
|
||||
WebBluetoothDeviceCommand::Subscribe(subscribe_cmd, sender) => {
|
||||
debug!("Subscribing to endpoint {:?}", subscribe_cmd.endpoint());
|
||||
let chr = char_map.get(&subscribe_cmd.endpoint()).unwrap().clone();
|
||||
let ep = subscribe_cmd.endpoint();
|
||||
@@ -335,10 +324,10 @@ async fn run_webbluetooth_loop(
|
||||
spawn_local(async move {
|
||||
JsFuture::from(chr.start_notifications()).await.unwrap();
|
||||
debug!("Endpoint subscribed");
|
||||
waker.set_reply(Ok(()));
|
||||
let _ = sender.send(Ok(()));
|
||||
});
|
||||
}
|
||||
WebBluetoothDeviceCommand::Unsubscribe(_unsubscribe_cmd, _waker) => {}
|
||||
WebBluetoothDeviceCommand::Unsubscribe(_unsubscribe_cmd, _sender) => {}
|
||||
}
|
||||
}
|
||||
debug!("run_webbluetooth_loop exited!");
|
||||
@@ -388,12 +377,13 @@ impl HardwareInternal for WebBluetoothHardware {
|
||||
let sender = self.device_command_sender.clone();
|
||||
let msg = msg.clone();
|
||||
Box::pin(async move {
|
||||
let fut = WebBluetoothReadResultFuture::default();
|
||||
let waker = fut.get_state_clone();
|
||||
sender
|
||||
.send(WebBluetoothDeviceCommand::Read(msg, waker))
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let _ = sender
|
||||
.send(WebBluetoothDeviceCommand::Read(msg, tx))
|
||||
.await;
|
||||
fut.await
|
||||
rx.await.unwrap_or(Err(ButtplugDeviceError::DeviceCommunicationError(
|
||||
"Device command channel closed".to_string(),
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -401,12 +391,13 @@ impl HardwareInternal for WebBluetoothHardware {
|
||||
let sender = self.device_command_sender.clone();
|
||||
let msg = msg.clone();
|
||||
Box::pin(async move {
|
||||
let fut = WebBluetoothResultFuture::default();
|
||||
let waker = fut.get_state_clone();
|
||||
sender
|
||||
.send(WebBluetoothDeviceCommand::Write(msg.clone(), waker))
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let _ = sender
|
||||
.send(WebBluetoothDeviceCommand::Write(msg, tx))
|
||||
.await;
|
||||
fut.await
|
||||
rx.await.unwrap_or(Err(ButtplugDeviceError::DeviceCommunicationError(
|
||||
"Device command channel closed".to_string(),
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -414,12 +405,13 @@ impl HardwareInternal for WebBluetoothHardware {
|
||||
let sender = self.device_command_sender.clone();
|
||||
let msg = msg.clone();
|
||||
Box::pin(async move {
|
||||
let fut = WebBluetoothResultFuture::default();
|
||||
let waker = fut.get_state_clone();
|
||||
sender
|
||||
.send(WebBluetoothDeviceCommand::Subscribe(msg.clone(), waker))
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let _ = sender
|
||||
.send(WebBluetoothDeviceCommand::Subscribe(msg, tx))
|
||||
.await;
|
||||
fut.await
|
||||
rx.await.unwrap_or(Err(ButtplugDeviceError::DeviceCommunicationError(
|
||||
"Device command channel closed".to_string(),
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
use super::webbluetooth_hardware::WebBluetoothHardwareConnector;
|
||||
|
||||
use buttplug::{
|
||||
core::ButtplugResultFuture,
|
||||
server::device::{
|
||||
configuration::{ProtocolCommunicationSpecifier},
|
||||
hardware::communication::{
|
||||
HardwareCommunicationManager, HardwareCommunicationManagerBuilder,
|
||||
HardwareCommunicationManagerEvent,
|
||||
},
|
||||
}
|
||||
use buttplug_core::ButtplugResultFuture;
|
||||
use buttplug_server_device_config::ProtocolCommunicationSpecifier;
|
||||
use buttplug_server::device::hardware::communication::{
|
||||
HardwareCommunicationManager, HardwareCommunicationManagerBuilder,
|
||||
HardwareCommunicationManagerEvent,
|
||||
};
|
||||
use futures::future;
|
||||
use js_sys::Array;
|
||||
@@ -69,8 +65,8 @@ impl HardwareCommunicationManager for WebBluetoothCommunicationManager {
|
||||
let options = web_sys::RequestDeviceOptions::new();
|
||||
let filters = Array::new();
|
||||
let optional_services = Array::new();
|
||||
for vals in config_manager.protocol_device_configurations().iter() {
|
||||
for config in vals.1 {
|
||||
for vals in config_manager.base_communication_specifiers().iter() {
|
||||
for config in vals.1.iter() {
|
||||
if let ProtocolCommunicationSpecifier::BluetoothLE(btle) = &config {
|
||||
for name in btle.names() {
|
||||
let filter = web_sys::BluetoothLeScanFilterInit::new();
|
||||
|
||||
Reference in New Issue
Block a user