Buttplug sex toy control library
1// Buttplug Rust Source Code File - See https://buttplug.io for more info. 2// 3// Copyright 2016-2024 Nonpolynomial Labs LLC. All rights reserved. 4// 5// Licensed under the BSD 3-Clause license. See LICENSE file in the project root 6// for full license information. 7 8use super::Endpoint; 9use getset::{Getters, MutGetters, Setters}; 10use serde::{Deserialize, Serialize}; 11use std::collections::{HashMap, HashSet}; 12use uuid::Uuid; 13 14#[derive(Serialize, Deserialize, Debug, Clone, Getters, MutGetters, Setters, Eq)] 15#[getset(get = "pub", set = "pub", get_mut = "pub(crate)")] 16pub struct BluetoothLEManufacturerData { 17 company: u16, 18 data: Option<Vec<u8>>, 19} 20 21impl BluetoothLEManufacturerData { 22 pub fn new(company: u16, data: &Option<Vec<u8>>) -> Self { 23 Self { 24 company, 25 data: data.clone(), 26 } 27 } 28} 29 30impl PartialEq for BluetoothLEManufacturerData { 31 fn eq(&self, other: &Self) -> bool { 32 if self.company != *other.company() { 33 return false; 34 } 35 36 // Only the deserialized device config can have none has a data value. If it does, that means 37 // all we care about is the company value, at which point we can return true here. 38 if self.data.is_none() || other.data.is_none() { 39 return true; 40 } 41 42 let data = self.data().as_ref().expect("Already checked existence"); 43 let other_data = other.data().as_ref().expect("Already checked existence"); 44 45 if data.len() == other_data.len() { 46 if *data == *other_data { 47 return true; 48 } 49 return false; 50 } 51 52 // If our data lengths are different, see if one is a subsequence of the other. 53 // 54 // Since we don't have the information to know if either self or other is what was loaded from 55 // the JSON file, we have to blindly guess for needle and haystack here based on length. This 56 // means if manufacturer data comes back from a device shorter than the data the device config 57 // expects, we could have a false match. This needs to be contexualized but that would require a 58 // large device config system rewrite at the moment, so we'll just live with the bug for now. 59 let needle = if data.len() < other_data.len() { 60 data 61 } else { 62 other_data 63 }; 64 let mut haystack = if data.len() > other_data.len() { 65 data.as_slice() 66 } else { 67 other_data.as_slice() 68 }; 69 while !haystack.is_empty() { 70 if haystack.starts_with(needle) { 71 return true; 72 } 73 haystack = &haystack[1..]; 74 } 75 76 false 77 } 78} 79 80/// Specifier for Bluetooth LE Devices 81/// 82/// Used by protocols for identifying bluetooth devices via their advertisements, as well as 83/// defining the services and characteristics they are expected to have. 84#[derive(Serialize, Deserialize, Debug, Clone, Getters, MutGetters, Setters)] 85#[getset(get = "pub", set = "pub", get_mut = "pub(crate)")] 86pub struct BluetoothLESpecifier { 87 /// Set of expected advertised names for this device. 88 names: HashSet<String>, 89 /// Array of possible manufacturer data values. 90 #[serde(default)] 91 manufacturer_data: Vec<BluetoothLEManufacturerData>, 92 /// Set of expected advertised services for this device. 93 #[serde(default)] 94 advertised_services: HashSet<Uuid>, 95 /// Services we expect the device may have. More services may be listed in a specifier than any 96 /// one device may have, but we expect at least one to be matched by a device in order to consider 97 /// the device part of the protocol that has this specifier. 98 services: HashMap<Uuid, HashMap<Endpoint, Uuid>>, 99} 100 101impl PartialEq for BluetoothLESpecifier { 102 fn eq(&self, other: &Self) -> bool { 103 // If names or manufacturer data are found, use those automatically. 104 if self.names.intersection(&other.names).count() > 0 { 105 return true; 106 } 107 // Otherwise, try wildcarded names. 108 for name in &self.names { 109 for other_name in &other.names { 110 let compare_name: &String; 111 let mut wildcard: String; 112 if name.ends_with('*') { 113 wildcard = name.clone(); 114 compare_name = other_name; 115 } else if other_name.ends_with('*') { 116 wildcard = other_name.clone(); 117 compare_name = name; 118 } else { 119 continue; 120 } 121 // Remove asterisk from the end of the wildcard 122 wildcard.pop(); 123 if compare_name.starts_with(&wildcard) { 124 return true; 125 } 126 } 127 } 128 129 if !self.manufacturer_data.is_empty() && !other.manufacturer_data.is_empty() { 130 for data in &self.manufacturer_data { 131 if other.manufacturer_data.contains(data) { 132 return true; 133 } 134 } 135 } 136 137 if self 138 .advertised_services 139 .intersection(&other.advertised_services) 140 .count() 141 > 0 142 { 143 return true; 144 } 145 146 false 147 } 148} 149 150impl BluetoothLESpecifier { 151 pub fn new( 152 names: HashSet<String>, 153 manufacturer_data: Vec<BluetoothLEManufacturerData>, 154 advertised_services: HashSet<Uuid>, 155 services: HashMap<Uuid, HashMap<Endpoint, Uuid>>, 156 ) -> Self { 157 Self { 158 names, 159 manufacturer_data, 160 advertised_services, 161 services, 162 } 163 } 164 165 /// Creates a specifier from a BLE device advertisement. 166 pub fn new_from_device( 167 name: &str, 168 manufacturer_data: &HashMap<u16, Vec<u8>>, 169 advertised_services: &[Uuid], 170 ) -> BluetoothLESpecifier { 171 let mut name_set = HashSet::new(); 172 name_set.insert(name.to_string()); 173 let mut data_vec = vec![]; 174 for (company, data) in manufacturer_data.iter() { 175 data_vec.push(BluetoothLEManufacturerData::new( 176 *company, 177 &Some(data.clone()), 178 )); 179 } 180 let service_set = HashSet::from_iter(advertised_services.iter().copied()); 181 BluetoothLESpecifier { 182 names: name_set, 183 manufacturer_data: data_vec, 184 advertised_services: service_set, 185 services: HashMap::new(), 186 } 187 } 188 189 /// Merge with another BLE specifier, used when loading user configs that extend a protocol 190 /// definition. 191 pub fn merge(&mut self, other: BluetoothLESpecifier) { 192 // Add any new names. 193 self.names = self.names.union(&other.names).cloned().collect(); 194 // Add new services, overwrite matching services. 195 self.advertised_services = self 196 .advertised_services 197 .union(&other.advertised_services) 198 .cloned() 199 .collect(); 200 self.services.extend(other.services); 201 } 202} 203 204/// Specifier for [Lovense Connect 205/// Service](crate::server::device::communication_manager::lovense_connect_service) devices 206/// 207/// Network based services, has no attributes because the [Lovense Connect 208/// Service](crate::server::device::communication_manager::lovense_connect_service) device communication manager 209/// handles all device discovery and identification itself. 210#[derive(Serialize, Deserialize, Debug, Clone)] 211pub struct LovenseConnectServiceSpecifier { 212 // Needed for proper deserialization, but clippy will complain. 213 #[allow(dead_code)] 214 exists: bool, 215} 216 217impl Default for LovenseConnectServiceSpecifier { 218 fn default() -> Self { 219 Self { exists: true } 220 } 221} 222 223impl PartialEq for LovenseConnectServiceSpecifier { 224 fn eq(&self, _other: &Self) -> bool { 225 true 226 } 227} 228 229/// Specifier for [XInput](crate::server::device::communication_manager::xinput) devices 230/// 231/// Network based services, has no attributes because the 232/// [XInput](crate::server::device::communication_manager::xinput) device communication manager handles all device 233/// discovery and identification itself. 234#[derive(Serialize, Deserialize, Debug, Clone, Copy)] 235pub struct XInputSpecifier { 236 // Needed for deserialziation but unused. 237 #[allow(dead_code)] 238 exists: bool, 239} 240 241impl Default for XInputSpecifier { 242 fn default() -> Self { 243 Self { exists: true } 244 } 245} 246 247impl PartialEq for XInputSpecifier { 248 fn eq(&self, _other: &Self) -> bool { 249 true 250 } 251} 252 253#[derive( 254 Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy, Getters, Setters, MutGetters, 255)] 256pub struct VIDPIDPair { 257 vendor_id: u16, 258 product_id: u16, 259} 260 261/// Specifier for HID (USB, Bluetooth) devices 262/// 263/// Handles devices managed by the operating system's HID manager. 264#[derive(Serialize, Deserialize, Debug, Eq, Clone, Getters, Setters, MutGetters)] 265#[getset(get = "pub", set = "pub", get_mut = "pub(crate)")] 266pub struct VIDPIDSpecifier { 267 pairs: Vec<VIDPIDPair>, 268} 269 270impl VIDPIDSpecifier { 271 pub fn new(vendor_id: u16, product_id: u16) -> Self { 272 Self { 273 pairs: vec![VIDPIDPair { 274 vendor_id, 275 product_id, 276 }], 277 } 278 } 279} 280 281impl PartialEq for VIDPIDSpecifier { 282 fn eq(&self, other: &Self) -> bool { 283 for pair in &self.pairs { 284 for other_pair in &other.pairs { 285 if *pair == *other_pair { 286 return true; 287 } 288 } 289 } 290 false 291 } 292} 293 294/// Specifier for Serial devices 295/// 296/// Handles serial port device identification (via port names) and configuration. 297#[derive(Serialize, Deserialize, Debug, Clone, Default, Getters, Setters, MutGetters)] 298#[getset(get = "pub", set = "pub", get_mut = "pub(crate)")] 299pub struct SerialSpecifier { 300 baud_rate: u32, 301 data_bits: u8, 302 stop_bits: u8, 303 parity: char, 304 port: String, 305} 306 307impl SerialSpecifier { 308 pub fn new(port: &str, baud_rate: u32, data_bits: u8, stop_bits: u8, parity: char) -> Self { 309 Self { 310 port: port.to_owned(), 311 baud_rate, 312 data_bits, 313 stop_bits, 314 parity, 315 } 316 } 317 318 /// Given a serial port name (the only identifier we have for this type of device), create a 319 /// specifier instance. 320 pub fn new_from_name(port: &str) -> Self { 321 Self { 322 port: port.to_owned(), 323 ..Default::default() 324 } 325 } 326} 327 328impl PartialEq for SerialSpecifier { 329 fn eq(&self, other: &Self) -> bool { 330 if *self.port == *other.port { 331 return true; 332 } 333 false 334 } 335} 336 337/// Specifier for Websocket Device Manager devices 338/// 339/// The websocket device manager is a network based manager, so we have no info other than possibly 340/// a device name that is provided as part of the connection handshake. 341#[derive(Serialize, Deserialize, Debug, Clone, Default, Getters, Setters, MutGetters)] 342#[getset(get = "pub", set = "pub")] 343pub struct WebsocketSpecifier { 344 name: String, 345} 346 347impl PartialEq for WebsocketSpecifier { 348 fn eq(&self, other: &Self) -> bool { 349 if self.name == other.name { 350 return true; 351 } 352 false 353 } 354} 355 356impl WebsocketSpecifier { 357 pub fn new(name: &str) -> WebsocketSpecifier { 358 Self { 359 name: name.to_owned(), 360 } 361 } 362} 363 364/// Enum that covers all types of communication specifiers. 365/// 366/// Allows generalization of specifiers to handle checking for equality. Used for testing newly discovered 367/// devices against the list of known devices for a protocol. 368#[derive(Serialize, Deserialize, Debug, Clone)] 369pub enum ProtocolCommunicationSpecifier { 370 #[serde(rename = "btle")] 371 BluetoothLE(BluetoothLESpecifier), 372 #[serde(rename = "hid")] 373 HID(VIDPIDSpecifier), 374 #[serde(rename = "usb")] 375 USB(VIDPIDSpecifier), 376 #[serde(rename = "serial")] 377 Serial(SerialSpecifier), 378 #[serde(rename = "xinput")] 379 XInput(XInputSpecifier), 380 #[serde(rename = "lovense_connect_service")] 381 LovenseConnectService(LovenseConnectServiceSpecifier), 382 #[serde(rename = "websocket")] 383 Websocket(WebsocketSpecifier), 384} 385 386impl PartialEq for ProtocolCommunicationSpecifier { 387 fn eq(&self, other: &ProtocolCommunicationSpecifier) -> bool { 388 use ProtocolCommunicationSpecifier::*; 389 match (self, other) { 390 (USB(self_spec), USB(other_spec)) => self_spec == other_spec, 391 (Serial(self_spec), Serial(other_spec)) => self_spec == other_spec, 392 (BluetoothLE(self_spec), BluetoothLE(other_spec)) => self_spec == other_spec, 393 (HID(self_spec), HID(other_spec)) => self_spec == other_spec, 394 (XInput(self_spec), XInput(other_spec)) => self_spec == other_spec, 395 (Websocket(self_spec), Websocket(other_spec)) => self_spec == other_spec, 396 (LovenseConnectService(self_spec), LovenseConnectService(other_spec)) => { 397 self_spec == other_spec 398 } 399 _ => false, 400 } 401 } 402} 403 404impl Eq for ProtocolCommunicationSpecifier { 405}