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}