Buttplug sex toy control library

chore: Clean up rest device list, commands, etc...

+119 -90
+26 -18
crates/buttplug_client/src/device/command.rs
··· 1 1 use buttplug_core::message::OutputType; 2 2 3 + use crate::ButtplugClientError; 4 + 3 5 pub enum ClientDeviceCommandValue { 4 6 Int(u32), 5 7 Float(f64), ··· 42 44 PositionWithDurationFloat(f64, u32), 43 45 } 44 46 45 - impl From<&ClientDeviceOutputCommand> for OutputType { 46 - fn from(val: &ClientDeviceOutputCommand) -> Self { 47 - match val { 48 - ClientDeviceOutputCommand::Vibrate(_) | ClientDeviceOutputCommand::VibrateFloat(_) => { 49 - OutputType::Vibrate 50 - } 51 - ClientDeviceOutputCommand::Oscillate(_) | ClientDeviceOutputCommand::OscillateFloat(_) => { 52 - OutputType::Oscillate 53 - } 54 - ClientDeviceOutputCommand::Rotate(_) | ClientDeviceOutputCommand::RotateFloat(_) => { 55 - OutputType::Rotate 56 - } 57 - ClientDeviceOutputCommand::Constrict(_) | ClientDeviceOutputCommand::ConstrictFloat(_) => { 58 - OutputType::Constrict 59 - } 60 - ClientDeviceOutputCommand::Heater(_) | ClientDeviceOutputCommand::HeaterFloat(_) => { 61 - OutputType::Heater 62 - } 47 + impl ClientDeviceOutputCommand { 48 + pub fn from_command_value_float(output_type: OutputType, value: f64) -> Result<Self, ButtplugClientError> { 49 + match output_type { 50 + OutputType::Vibrate => Ok(ClientDeviceOutputCommand::VibrateFloat(value)), 51 + OutputType::Oscillate => Ok(ClientDeviceOutputCommand::OscillateFloat(value)), 52 + OutputType::Rotate => Ok(ClientDeviceOutputCommand::RotateFloat(value)), 53 + OutputType::Constrict => Ok(ClientDeviceOutputCommand::ConstrictFloat(value)), 54 + OutputType::Heater => Ok(ClientDeviceOutputCommand::HeaterFloat(value)), 55 + OutputType::Led => Ok(ClientDeviceOutputCommand::LedFloat(value)), 56 + OutputType::Spray => Ok(ClientDeviceOutputCommand::SprayFloat(value)), 57 + OutputType::Position => Ok(ClientDeviceOutputCommand::PositionFloat(value)), 58 + _ => Err(ButtplugClientError::ButtplugOutputCommandConversionError("Cannot use PositionWithDuration or RotateWithDirection with this method".to_owned())) 59 + } 60 + } 61 + } 62 + 63 + impl Into<OutputType> for &ClientDeviceOutputCommand { 64 + fn into(self) -> OutputType { 65 + match self { 66 + ClientDeviceOutputCommand::Vibrate(_) | ClientDeviceOutputCommand::VibrateFloat(_) => OutputType::Vibrate, 67 + ClientDeviceOutputCommand::Oscillate(_) | ClientDeviceOutputCommand::OscillateFloat(_) => OutputType::Oscillate, 68 + ClientDeviceOutputCommand::Rotate(_) | ClientDeviceOutputCommand::RotateFloat(_) => OutputType::Rotate, 69 + ClientDeviceOutputCommand::Constrict(_) | ClientDeviceOutputCommand::ConstrictFloat(_) => OutputType::Constrict, 70 + ClientDeviceOutputCommand::Heater(_) | ClientDeviceOutputCommand::HeaterFloat(_) => OutputType::Heater, 63 71 ClientDeviceOutputCommand::Led(_) | ClientDeviceOutputCommand::LedFloat(_) => OutputType::Led, 64 72 ClientDeviceOutputCommand::Spray(_) | ClientDeviceOutputCommand::SprayFloat(_) => { 65 73 OutputType::Spray
+1 -1
crates/buttplug_core/src/message/device_feature.rs
··· 11 11 use serde::{Deserialize, Serialize, Serializer, ser::SerializeSeq}; 12 12 use std::{collections::HashSet, hash::Hash, ops::RangeInclusive}; 13 13 14 - #[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash, EnumIter)] 14 + #[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash, EnumIter, EnumString)] 15 15 pub enum OutputType { 16 16 Unknown, 17 17 #[serde(alias = "vibrate")]
+92 -71
crates/intiface_engine/src/rest_server.rs
··· 1 - use std::{collections::BTreeMap, io, net::SocketAddr, process::Output, str::FromStr, sync::Arc}; 1 + use std::{collections::BTreeMap, io, net::SocketAddr, str::FromStr, sync::Arc}; 2 2 3 - use anyhow::Context; 4 3 use axum::{ 5 4 Json, Router, 6 5 extract::{Path, State, rejection::JsonRejection}, ··· 8 7 response::{IntoResponse, Response}, 9 8 routing::{get, put}, 10 9 }; 11 - use buttplug_client::{device::ClientDeviceOutputCommand, ButtplugClient, ButtplugClientDevice, ButtplugClientError}; 10 + use buttplug_client::{ 11 + ButtplugClient, ButtplugClientDevice, ButtplugClientError, device::ClientDeviceOutputCommand, 12 + }; 12 13 use buttplug_client_in_process::ButtplugInProcessClientConnectorBuilder; 13 14 use buttplug_core::message::{DeviceFeature, OutputType}; 14 15 use buttplug_server::ButtplugServer; ··· 90 91 91 92 pub struct IntifaceRestServer {} 92 93 93 - async fn start_scanning(State(client): State<Arc<ButtplugClient>>) { 94 - client.start_scanning().await; 94 + fn get_device( 95 + client: &ButtplugClient, 96 + index: u32, 97 + ) -> Result<ButtplugClientDevice, IntifaceRestError> { 98 + client 99 + .devices() 100 + .get(&index) 101 + .ok_or(IntifaceRestError::InvalidDevice(index)) 102 + .cloned() 95 103 } 96 104 97 - async fn stop_scanning(State(client): State<Arc<ButtplugClient>>) { 98 - client.stop_scanning().await; 105 + async fn start_scanning( 106 + State(client): State<Arc<ButtplugClient>>, 107 + ) -> Result<(), IntifaceRestError> { 108 + client 109 + .start_scanning() 110 + .await 111 + .map_err(|e| IntifaceRestError::ButtplugClientError(e)) 99 112 } 100 113 101 - async fn stop_all_devices(State(client): State<Arc<ButtplugClient>>) { 102 - client.stop_all_devices().await; 114 + async fn stop_scanning(State(client): State<Arc<ButtplugClient>>) -> Result<(), IntifaceRestError> { 115 + client 116 + .stop_scanning() 117 + .await 118 + .map_err(|e| IntifaceRestError::ButtplugClientError(e)) 119 + } 120 + 121 + async fn stop_all_devices( 122 + State(client): State<Arc<ButtplugClient>>, 123 + ) -> Result<(), IntifaceRestError> { 124 + client 125 + .stop_all_devices() 126 + .await 127 + .map_err(|e| IntifaceRestError::ButtplugClientError(e)) 103 128 } 104 129 105 130 async fn stop_device( ··· 107 132 Path(index): Path<u32>, 108 133 ) -> Result<(), IntifaceRestError> { 109 134 Ok( 110 - client 111 - .devices() 112 - .get(&index) 113 - .ok_or(IntifaceRestError::InvalidDevice(index))? 135 + get_device(&client, index)? 114 136 .stop() 115 137 .await 116 138 .map_err(|e| IntifaceRestError::ButtplugClientError(e))?, ··· 121 143 State(client): State<Arc<ButtplugClient>>, 122 144 Path((index, command, level)): Path<(u32, String, f64)>, 123 145 ) -> Result<(), IntifaceRestError> { 124 - let command_type = OutputType::from_str(&command).map_err(|_| 125 - IntifaceRestError::InvalidOutputType( 126 - command, 127 - OutputType::iter().collect::<Vec<OutputType>>() 128 - ) 129 - )?; 146 + let command_type = OutputType::from_str(&command).map_err(|_| { 147 + IntifaceRestError::InvalidOutputType(command, OutputType::iter().collect::<Vec<OutputType>>()) 148 + })?; 130 149 131 - Ok(()) 132 - /* 133 - let cmd = ClientDeviceOutputCommand:: 150 + let cmd = ClientDeviceOutputCommand::from_command_value_float(command_type, level) 151 + .map_err(|e| IntifaceRestError::ButtplugClientError(e))?; 134 152 135 - Ok(client 136 - .devices() 137 - .get(&index) 138 - .ok_or(IntifaceRestError::InvalidDevice(index))? 139 - .send_command(client_device_command) 140 - .await 141 - .map_err(|e| IntifaceRestError::ButtplugClientError(e))?) 142 - */ 153 + Ok( 154 + get_device(&client, index)? 155 + .send_command(&cmd) 156 + .await 157 + .map_err(|e| IntifaceRestError::ButtplugClientError(e))?, 158 + ) 143 159 } 144 160 145 161 async fn get_devices( ··· 153 169 .into() 154 170 } 155 171 156 - async fn get_device( 172 + async fn get_device_info( 157 173 State(client): State<Arc<ButtplugClient>>, 158 174 Path(index): Path<u32>, 159 175 ) -> Result<Json<IntifaceRestDevice>, IntifaceRestError> { 160 - Ok(IntifaceRestDevice::from(client.devices().get(&index).ok_or(IntifaceRestError::InvalidDevice(index))?).into()) 176 + Ok( 177 + IntifaceRestDevice::from( 178 + client 179 + .devices() 180 + .get(&index) 181 + .ok_or(IntifaceRestError::InvalidDevice(index))?, 182 + ) 183 + .into(), 184 + ) 161 185 } 162 186 163 187 async fn get_features( ··· 165 189 Path(index): Path<u32>, 166 190 ) -> Result<Json<BTreeMap<u32, DeviceFeature>>, IntifaceRestError> { 167 191 Ok( 168 - client 169 - .devices() 170 - .get(&index) 171 - .ok_or(IntifaceRestError::InvalidDevice(index))? 192 + get_device(&client, index)? 172 193 .device_features() 173 194 .iter() 174 195 .map(|(i, f)| (*i, f.feature().clone())) ··· 182 203 Path((index, feature_index)): Path<(u32, u32)>, 183 204 ) -> Result<Json<DeviceFeature>, IntifaceRestError> { 184 205 Ok( 185 - client 186 - .devices() 187 - .get(&index) 188 - .ok_or(IntifaceRestError::InvalidDevice(index))? 206 + get_device(&client, index)? 189 207 .device_features() 190 208 .get(&feature_index) 191 209 .ok_or(IntifaceRestError::InvalidFeature(index, feature_index))? ··· 204 222 client.connect(connector).await.unwrap(); 205 223 info!("Setting up app!"); 206 224 // pass incoming GET requests on "/hello-world" to "hello_world" handler. 207 - let app = Router::new() 208 - .route("/start-scanning", get(start_scanning)) 209 - .route("/stop-scanning", get(stop_scanning)) 210 - .route("/devices", get(get_devices)) 211 - .route("/devices/stop", put(stop_all_devices)) 212 - .route("/devices/{index}", put(get_device)) 213 - .route("/devices/{index}/stop", put(stop_device)) 214 - .route("/devices/{index}/features", get(get_features)) 215 - .route("/devices/{index}/features/{index}/", put(get_feature)) 216 - .route( 217 - "/devices/{index}/outputs/{output_type}/", 218 - put(set_device_output), 219 - ) 220 - /* 221 - .route( 222 - "/devices/{index}/features/{index}/outputs/{output_type}/", 223 - put(set_feature_output), 224 - ) 225 - .route( 226 - "/devices/{index}/inputs/{input_type}/{input_command}", 227 - put(set_device_input), 228 - ) 229 - .route( 230 - "/devices/{index}/features/{index}/inputs/{input_type}/{input_command}", 231 - put(set_feature_input), 232 - ) 233 - .route("/devices/{index}/events", get(device_sse)) 234 - .route("/events", get(server_sse)) 235 - */ 236 - //.route("/devices/{*index}/vibrate", post(set_feature_vibrate_speed)) 237 - .with_state(Arc::new(client)); 225 + let app = Router::new().nest( 226 + "/api/v1", 227 + Router::new() 228 + .route("/start-scanning", get(start_scanning)) 229 + .route("/stop-scanning", get(stop_scanning)) 230 + .route("/devices", get(get_devices)) 231 + .route("/devices/stop", put(stop_all_devices)) 232 + .route("/devices/{index}", get(get_device_info)) 233 + .route("/devices/{index}/stop", put(stop_device)) 234 + .route("/devices/{index}/features", get(get_features)) 235 + .route("/devices/{index}/features/{index}/", put(get_feature)) 236 + .route( 237 + "/devices/{index}/outputs/{output_type}/", 238 + put(set_device_output), 239 + ) 240 + /* 241 + .route( 242 + "/devices/{index}/features/{index}/outputs/{output_type}/", 243 + put(set_feature_output), 244 + ) 245 + .route( 246 + "/devices/{index}/inputs/{input_type}/{input_command}", 247 + put(set_device_input), 248 + ) 249 + .route( 250 + "/devices/{index}/features/{index}/inputs/{input_type}/{input_command}", 251 + put(set_feature_input), 252 + ) 253 + .route("/devices/{index}/events", get(device_sse)) 254 + .route("/events", get(server_sse)) 255 + */ 256 + //.route("/devices/{*index}/vibrate", post(set_feature_vibrate_speed)) 257 + .with_state(Arc::new(client)), 258 + ); 238 259 239 260 // write address like this to not make typos 240 261 let addr = SocketAddr::from(([127, 0, 0, 1], 3000));