Something went wrong. Try again.
Buttplug sex toy control library
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375// Buttplug Rust Source Code File - See https://buttplug.io for more info.//// Copyright 2016-2025 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 tracing::Level;
/*use buttplug_client::device::{ClientDeviceFeature, ClientDeviceOutputCommand};use buttplug_client::{ButtplugClient, ButtplugClientDevice, ButtplugClientEvent};use buttplug_client_in_process::ButtplugInProcessClientConnectorBuilder;use buttplug_core::message::ButtplugDeviceMessageNameV4::OutputCmd;use buttplug_core::message::{ DeviceFeature, DeviceFeatureOutput, OutputCommand, OutputType, OutputValue,};use buttplug_server::ButtplugServerBuilder;use buttplug_server::device::ServerDeviceManagerBuilder;use buttplug_server_device_config::load_protocol_configs;use buttplug_server_hwmgr_btleplug::BtlePlugCommunicationManagerBuilder;use futures::StreamExt;use futures::future::try_join;use log::error;use std::collections::{HashMap, HashSet};use std::{fs, sync::Arc, time::Duration};use tokio::time::sleep;
async fn set_level_and_wait( dev: &ButtplugClientDevice, feature: &ClientDeviceFeature, output: &DeviceFeatureOutput, output_type: &OutputType, level: f64,) { let cmd = match (output_type) { OutputType::Vibrate => Ok(ClientDeviceOutputCommand::VibrateFloat(level)), OutputType::Rotate => Ok(ClientDeviceOutputCommand::RotateFloat(level)), OutputType::Oscillate => Ok(ClientDeviceOutputCommand::OscillateFloat(level)), OutputType::Constrict => Ok(ClientDeviceOutputCommand::ConstrictFloat(level)), OutputType::Heater => Ok(ClientDeviceOutputCommand::HeaterFloat(level)), OutputType::Led => Ok(ClientDeviceOutputCommand::LedFloat(level)), OutputType::Position => Ok(ClientDeviceOutputCommand::PositionFloat(level)), OutputType::Spray => Ok(ClientDeviceOutputCommand::SprayFloat(level)), _ => Err(format!("Unknown output type {:?}", output_type)), } .unwrap(); feature.send_command(&cmd).await.unwrap(); println!( "{} ({}) Testing feature {}: {}, output {:?} - {}%", dev.name(), dev.index(), feature.feature().feature_index(), feature.feature().description(), output_type, (level * 100.0) as u8 ); sleep(Duration::from_secs(1)).await;}
async fn device_tester() { let mut dc = None; let mut uc = None;
dc = None; //Some(fs::read_to_string("C:\\Users\\NickPoole\\AppData\\Roaming\\com.nonpolynomial\\intiface_central\\config\\buttplug-device-config-v3.json").expect("Should have been able to read dc")); uc = None; //Some(fs::read_to_string("C:\\Users\\NickPoole\\AppData\\Roaming\\com.nonpolynomial\\intiface_central\\config\\buttplug-user-device-config-v3.json").expect("Should have been able to read uc"));
let dcm = load_protocol_configs(&dc, &uc, false) .unwrap() .finish() .unwrap();
let mut server_builder = ServerDeviceManagerBuilder::new(dcm); server_builder.comm_manager(BtlePlugCommunicationManagerBuilder::default()); //server_builder.comm_manager(LovenseConnectServiceCommunicationManagerBuilder::default()); //server_builder.comm_manager(LovenseHIDDongleCommunicationManagerBuilder::default()); //server_builder.comm_manager(LovenseSerialDongleCommunicationManagerBuilder::default()); //server_builder.comm_manager(WebsocketServerDeviceCommunicationManagerBuilder::default()); //server_builder.comm_manager(HidCommunicationManagerBuilder::default()); //server_builder.comm_manager(SerialPortCommunicationManagerBuilder::default());
let sb = ButtplugServerBuilder::new(server_builder.finish().unwrap()); let server = sb.finish().unwrap(); let connector = ButtplugInProcessClientConnectorBuilder::default() .server(server) .finish(); let client = ButtplugClient::new("device-tester"); client.connect(connector).await.unwrap();
let mut event_stream = client.event_stream();
// We'll mostly be doing the same thing we did in example #3, up until we get // a device. if let Err(err) = client.start_scanning().await { println!("Client errored when starting scan! {}", err); return; }
let exercise_device = |dev: ButtplugClientDevice| async move { let mut cmds = vec![]; dev.device_features().iter().for_each(|(_, feature)| { let outs = feature.feature().output().clone().unwrap_or_default(); if let Some(out) = outs.get(&OutputType::Vibrate) { cmds.push(feature.vibrate(out.step_count())); println!( "{} ({}) should start vibrating on feature {}!", dev.name(), dev.index(), feature.feature_index() ); } else if let Some(out) = outs.get(&OutputType::Rotate) { cmds.push(feature.rotate(out.step_count())); println!( "{} ({}) should start rotating on feature {}!", dev.name(), dev.index(), feature.feature_index() ); } else if let Some(out) = outs.get(&OutputType::Oscillate) { cmds.push(feature.oscillate(out.step_count())); println!( "{} ({}) should start oscillating on feature {}!", dev.name(), dev.index(), feature.feature_index() ); } else if let Some(out) = outs.get(&OutputType::Constrict) { cmds.push(feature.constrict(out.step_count())); println!( "{} ({}) should start constricting on feature {}!", dev.name(), dev.index(), feature.feature_index() ); } else if let Some(out) = outs.get(&OutputType::Heater) { cmds.push(feature.send_command(&ClientDeviceOutputCommand::Heater(out.step_count()))); println!( "{} ({}) should start heating on feature {}!", dev.name(), dev.index(), feature.feature_index() ); } else if let Some(out) = outs.get(&OutputType::Position) { cmds.push(feature.position(out.step_count())); println!( "{} ({}) should start moving to position {} on feature {}!", dev.name(), dev.index(), out.step_count(), feature.feature_index() ); } }); futures::future::join_all(cmds) .await .iter() .for_each(|cmd| { if let Err(err) = cmd { error!("{:?}", err); } });
sleep(Duration::from_secs(5)).await;
let mut cmds = vec![]; dev.device_features().iter().for_each(|(_, feature)| { let outs = feature.feature().output().clone().unwrap_or_default(); if let Some(out) = outs.get(&OutputType::Vibrate) { cmds.push(feature.vibrate(0)); println!( "{} ({}) should stop vibrating on feature {}!", dev.name(), dev.index(), feature.feature_index() ); } else if let Some(out) = outs.get(&OutputType::Rotate) { cmds.push(feature.rotate(0)); println!( "{} ({}) should stop rotating on feature {}!", dev.name(), dev.index(), feature.feature_index() ); } else if let Some(out) = outs.get(&OutputType::Oscillate) { cmds.push(feature.oscillate(0)); println!( "{} ({}) should stop oscillating on feature {}!", dev.name(), dev.index(), feature.feature_index() ); } else if let Some(out) = outs.get(&OutputType::Constrict) { cmds.push(feature.constrict(0)); println!( "{} ({}) should stop constricting on feature {}!", dev.name(), dev.index(), feature.feature_index() ); } else if let Some(out) = outs.get(&OutputType::Heater) { cmds.push(feature.send_command(&ClientDeviceOutputCommand::Heater(0))); println!( "{} ({}) should stop heating on feature {}!", dev.name(), dev.index(), feature.feature_index() ); } else if let Some(out) = outs.get(&OutputType::Position) { cmds.push(feature.position(0)); println!( "{} ({}) should start moving to position 0 on feature {}!", dev.name(), dev.index(), feature.feature_index() ); } });
futures::future::join_all(cmds) .await .iter() .for_each(|cmd| { if let Err(err) = cmd { error!("{:?}", err); } });
sleep(Duration::from_secs(2)).await;
for (_, feature) in dev.device_features() { for outputs in feature.feature().output() { for otype in outputs.keys() { let output = outputs.get(otype).unwrap(); let test_feature = async |command, output_str| { feature.send_command(&command).await; println!( "{} ({}) Testing feature {} ({}), output {:?} - {}", dev.name(), dev.index(), feature.feature().feature_index(), feature.feature().description(), otype, output_str ); sleep(Duration::from_secs(1)).await; }; match otype { OutputType::Vibrate | OutputType::Rotate | OutputType::Constrict | OutputType::Oscillate | OutputType::Heater | OutputType::Spray | OutputType::Led | OutputType::Position => { set_level_and_wait(&dev, feature, &output, otype, 0.25).await; set_level_and_wait(&dev, feature, &output, otype, 0.5).await; set_level_and_wait(&dev, feature, &output, otype, 0.75).await; set_level_and_wait(&dev, feature, &output, otype, 1.0).await; set_level_and_wait(&dev, feature, &output, otype, 0.0).await; } OutputType::Unknown => { error!( "{} ({}) Can't test unknown feature {} ({}), output {:?}", dev.name(), dev.index(), feature.feature().feature_index(), feature.feature().description(), otype ); } OutputType::RotateWithDirection => { test_feature( ClientDeviceOutputCommand::RotateWithDirection(output.step_count() / 4, true), "25% clockwise", ) .await; test_feature( ClientDeviceOutputCommand::RotateWithDirection(output.step_count() / 4, false), "25% anti-clockwise", ) .await; test_feature( ClientDeviceOutputCommand::RotateWithDirection(output.step_count() / 2, true), "50% clockwise", ) .await; test_feature( ClientDeviceOutputCommand::RotateWithDirection(output.step_count() / 2, false), "50% anti-clockwise", ) .await; test_feature( ClientDeviceOutputCommand::RotateWithDirection((output.step_count() / 4) * 3, true), "75% clockwise", ) .await; test_feature( ClientDeviceOutputCommand::RotateWithDirection( (output.step_count() / 4) * 3, false, ), "75% anti-clockwise", ) .await; test_feature( ClientDeviceOutputCommand::RotateWithDirection(output.step_count(), true), "100% clockwise", ) .await; test_feature( ClientDeviceOutputCommand::RotateWithDirection(output.step_count(), false), "100% anti-clockwise", ) .await; test_feature( ClientDeviceOutputCommand::RotateWithDirection(0, false), "stop", ) .await; } OutputType::PositionWithDuration => {} } } } } };
loop { match event_stream .next() .await .expect("We own the client so the event stream shouldn't die.") { ButtplugClientEvent::DeviceAdded(dev) => { println!("We got a device: {}", dev.name()); let fut = exercise_device(dev); tokio::spawn(async move { fut.await; }); // break; } ButtplugClientEvent::ServerDisconnect => { // The server disconnected, which means we're done here, so just // break up to the top level. println!("Server disconnected!"); break; } _ => { // Something else happened, like scanning finishing, devices // getting removed, etc... Might as well say something about it. println!("Got some other kind of event we don't care about"); } } }
// And now we're done! println!("Exiting example");}*/#[tokio::main(flavor = "current_thread")]async fn main() { tracing_subscriber::fmt() .with_max_level(Level::DEBUG) .init(); panic!("Reimplement me!"); /* device_tester().await; */}