Buttplug sex toy control library

chore: Create ProtocolManager to handle config/protocol divide

+193 -232
+180 -3
crates/buttplug_server/src/device/protocol.rs
··· 16 16 ProtocolCommunicationSpecifier, 17 17 UserDeviceIdentifier, 18 18 }; 19 + use dashmap::DashMap; 19 20 20 21 use crate::{ 21 - device::hardware::{Hardware, HardwareCommand, HardwareReadCmd}, 22 + device::{hardware::{Hardware, HardwareCommand, HardwareReadCmd}, protocol_impl::get_default_protocol_map}, 22 23 message::{ 23 24 checked_output_cmd::CheckedOutputCmdV4, 24 25 spec_enums::ButtplugDeviceCommandMessageUnionV4, ··· 30 31 future::{self, BoxFuture, FutureExt}, 31 32 StreamExt, 32 33 }; 33 - use std::sync::Arc; 34 + use std::{collections::HashMap, sync::Arc}; 34 35 use std::{pin::Pin, time::Duration}; 35 36 use uuid::Uuid; 37 + use super::hardware::HardwareWriteCmd; 36 38 37 39 /// Strategy for situations where hardware needs to get updates every so often in order to keep 38 40 /// things alive. Currently this applies to iOS backgrounding with bluetooth devices, as well as ··· 521 523 pub use generic_protocol_initializer_setup; 522 524 pub use generic_protocol_setup; 523 525 524 - use super::hardware::HardwareWriteCmd; 526 + pub struct ProtocolManager { 527 + // Map of protocol names to their respective protocol instance factories 528 + protocol_map: HashMap<String, Arc<dyn ProtocolIdentifierFactory>>, 529 + } 530 + 531 + impl Default for ProtocolManager { 532 + fn default() -> Self { 533 + Self { 534 + protocol_map: get_default_protocol_map() 535 + } 536 + } 537 + } 538 + 539 + impl ProtocolManager { 540 + pub fn protocol_specializers( 541 + &self, 542 + specifier: &ProtocolCommunicationSpecifier, 543 + base_communication_specifiers: &HashMap<String, Vec<ProtocolCommunicationSpecifier>>, 544 + user_communication_specifiers: &DashMap<String, Vec<ProtocolCommunicationSpecifier>>, 545 + ) -> Vec<ProtocolSpecializer> { 546 + debug!( 547 + "Looking for protocol that matches specifier: {:?}", 548 + specifier 549 + ); 550 + let mut specializers = vec![]; 551 + let mut update_specializer_map = 552 + |name: &str, specifiers: &Vec<ProtocolCommunicationSpecifier>| { 553 + if specifiers.contains(specifier) { 554 + info!( 555 + "Found protocol {:?} for user specifier {:?}.", 556 + name, specifier 557 + ); 558 + if self.protocol_map.contains_key(name) { 559 + specializers.push(ProtocolSpecializer::new( 560 + specifiers.clone(), 561 + self 562 + .protocol_map 563 + .get(name) 564 + .expect("already checked existence") 565 + .create(), 566 + )); 567 + } else { 568 + warn!( 569 + "No protocol implementation for {:?} found for specifier {:?}.", 570 + name, specifier 571 + ); 572 + } 573 + } 574 + }; 575 + // Loop through both maps, as chaining between DashMap and HashMap gets kinda gross. 576 + for spec in user_communication_specifiers.iter() { 577 + update_specializer_map(spec.key(), spec.value()); 578 + } 579 + for (name, specifiers) in base_communication_specifiers.iter() { 580 + update_specializer_map(name, specifiers); 581 + } 582 + specializers 583 + } 584 + } 585 + 586 + 587 + /* 588 + #[cfg(test)] 589 + mod test { 590 + use super::*; 591 + use crate::{ 592 + core::message::{OutputType, FeatureType}, 593 + server::message::server_device_feature::{ServerDeviceFeature, ServerDeviceFeatureOutput}, 594 + }; 595 + use std::{ 596 + collections::{HashMap, HashSet}, 597 + ops::RangeInclusive, 598 + }; 599 + 600 + fn create_unit_test_dcm() -> DeviceConfigurationManager { 601 + let mut builder = DeviceConfigurationManagerBuilder::default(); 602 + let specifiers = ProtocolCommunicationSpecifier::BluetoothLE(BluetoothLESpecifier::new( 603 + HashSet::from(["LVS-*".to_owned(), "LovenseDummyTestName".to_owned()]), 604 + vec![], 605 + HashSet::new(), 606 + HashMap::new(), 607 + )); 608 + let mut feature_actuator = HashMap::new(); 609 + feature_actuator.insert( 610 + OutputType::Vibrate, 611 + ServerDeviceFeatureOutput::new(&RangeInclusive::new(0, 20), &RangeInclusive::new(0, 20)), 612 + ); 613 + builder 614 + .communication_specifier("lovense", &[specifiers]) 615 + .protocol_features( 616 + &BaseDeviceIdentifier::new("lovense", &Some("P".to_owned())), 617 + &BaseDeviceDefinition::new( 618 + "Lovense Edge", 619 + &uuid::Uuid::new_v4(), 620 + &None, 621 + &vec![ 622 + ServerDeviceFeature::new( 623 + "Edge Vibration 1", 624 + &uuid::Uuid::new_v4(), 625 + &None, 626 + FeatureType::Vibrate, 627 + &Some(feature_actuator.clone()), 628 + &None, 629 + ), 630 + ServerDeviceFeature::new( 631 + "Edge Vibration 2", 632 + &uuid::Uuid::new_v4(), 633 + &None, 634 + FeatureType::Vibrate, 635 + &Some(feature_actuator.clone()), 636 + &None, 637 + ), 638 + ], 639 + &None 640 + ), 641 + ) 642 + .finish() 643 + .unwrap() 644 + } 645 + 646 + #[test] 647 + fn test_config_equals() { 648 + let config = create_unit_test_dcm(); 649 + let spec = ProtocolCommunicationSpecifier::BluetoothLE(BluetoothLESpecifier::new_from_device( 650 + "LVS-Something", 651 + &HashMap::new(), 652 + &[], 653 + )); 654 + assert!(!config.protocol_specializers(&spec).is_empty()); 655 + } 656 + 657 + #[test] 658 + fn test_config_wildcard_equals() { 659 + let config = create_unit_test_dcm(); 660 + let spec = ProtocolCommunicationSpecifier::BluetoothLE(BluetoothLESpecifier::new_from_device( 661 + "LVS-Whatever", 662 + &HashMap::new(), 663 + &[], 664 + )); 665 + assert!(!config.protocol_specializers(&spec).is_empty()); 666 + } 667 + /* 668 + #[test] 669 + fn test_specific_device_config_creation() { 670 + let dcm = create_unit_test_dcm(false); 671 + let spec = ProtocolCommunicationSpecifier::BluetoothLE(BluetoothLESpecifier::new_from_device( 672 + "LVS-Whatever", 673 + &HashMap::new(), 674 + &[], 675 + )); 676 + assert!(!dcm.protocol_specializers(&spec).is_empty()); 677 + let config: ProtocolDeviceAttributes = dcm 678 + .device_definition( 679 + &UserDeviceIdentifier::new("Whatever", "lovense", &Some("P".to_owned())), 680 + &[], 681 + ) 682 + .expect("Should be found") 683 + .into(); 684 + // Make sure we got the right name 685 + assert_eq!(config.name(), "Lovense Edge"); 686 + // Make sure we overwrote the default of 1 687 + assert_eq!( 688 + config 689 + .message_attributes() 690 + .scalar_cmd() 691 + .as_ref() 692 + .expect("Test, assuming infallible") 693 + .get(0) 694 + .expect("Test, assuming infallible") 695 + .step_count(), 696 + 20 697 + ); 698 + } 699 + */ 700 + } 701 + */
+11 -6
crates/buttplug_server/src/device/server_device_manager_event_loop.rs
··· 16 16 hardware::communication::{HardwareCommunicationManager, HardwareCommunicationManagerEvent}, 17 17 ServerDevice, 18 18 ServerDeviceEvent, 19 + protocol::ProtocolManager 19 20 }; 20 21 use dashmap::{DashMap, DashSet}; 21 22 use futures::{future, pin_mut, FutureExt, StreamExt}; ··· 53 54 loop_cancellation_token: CancellationToken, 54 55 /// True if stop scanning message was sent, means we won't send scanning finished. 55 56 stop_scanning_received: AtomicBool, 57 + /// Protocol map, for mapping user definitions to protocols 58 + protocol_manager: ProtocolManager 56 59 } 57 60 58 61 impl ServerDeviceManagerEventLoop { ··· 80 83 connecting_devices: Arc::new(DashSet::new()), 81 84 loop_cancellation_token, 82 85 stop_scanning_received: AtomicBool::new(false), 86 + protocol_manager: ProtocolManager::default() 83 87 } 84 88 } 85 89 ··· 190 194 // 191 195 // We used to do this in build_server_device, but we shouldn't mark devices as actually 192 196 // connecting until after this happens, so we're moving it back here. 193 - // TODO FIX THIS ASAP 194 - /* 195 197 let protocol_specializers = self 196 - .device_config_manager 197 - .protocol_specializers(&creator.specifier()); 198 - */ 199 - let protocol_specializers = vec![]; 198 + .protocol_manager 199 + .protocol_specializers( 200 + &creator.specifier(), 201 + self.device_config_manager.base_communication_specifiers(), 202 + self.device_config_manager.user_communication_specifiers() 203 + ); 204 + 200 205 // If we have no identifiers, then there's nothing to do here. Throw an error. 201 206 if protocol_specializers.is_empty() { 202 207 debug!(
+2 -223
crates/buttplug_server_device_config/src/lib.rs
··· 158 158 159 159 #[derive(Default, Clone)] 160 160 pub struct DeviceConfigurationManagerBuilder { 161 - skip_default_protocols: bool, 162 161 communication_specifiers: HashMap<String, Vec<ProtocolCommunicationSpecifier>>, 163 162 user_communication_specifiers: DashMap<String, Vec<ProtocolCommunicationSpecifier>>, 164 163 base_device_definitions: HashMap<BaseDeviceIdentifier, BaseDeviceDefinition>, 165 164 user_device_definitions: DashMap<UserDeviceIdentifier, DeviceDefinition>, 166 - // Map of protocol names to their respective protocol instance factories 167 - // protocols: Vec<(String, Arc<dyn ProtocolIdentifierFactory>)>, 168 165 } 169 166 170 167 impl DeviceConfigurationManagerBuilder { ··· 228 225 } 229 226 self 230 227 } 231 - /* 232 - /// Add a protocol instance factory for a [ButtplugProtocol] 233 - pub fn protocol_factory<T>(&mut self, factory: T) -> &mut Self 234 - where 235 - T: ProtocolIdentifierFactory + 'static, 236 - { 237 - self 238 - .protocols 239 - .push((factory.identifier().to_owned(), Arc::new(factory))); 240 - self 241 - } 242 - */ 243 - pub fn skip_default_protocols(&mut self) -> &mut Self { 244 - self.skip_default_protocols = true; 245 - self 246 - } 247 228 248 229 pub fn finish(&mut self) -> Result<DeviceConfigurationManager, ButtplugDeviceError> { 249 - // Map of protocol names to their respective protocol instance factories 250 - /* 251 - let mut protocol_map = if !self.skip_default_protocols { 252 - get_default_protocol_map() 253 - } else { 254 - HashMap::new() 255 - }; 256 - 257 - for (name, protocol) in &self.protocols { 258 - if protocol_map.contains_key(name) { 259 - // TODO Fill in error 260 - } 261 - protocol_map.insert(name.clone(), protocol.clone()); 262 - } 263 - */ 264 230 // Build and validate the protocol attributes tree. 265 231 let mut attribute_tree_map = HashMap::new(); 266 232 267 233 // Add all the defaults first, they won't have parent attributes. 268 234 for (ident, attr) in &self.base_device_definitions { 269 - // If we don't have a protocol loaded for this configuration block, just drop it. We can't do 270 - // anything with it anyways. 271 - /* 272 - if !protocol_map.contains_key(ident.protocol()) { 273 - debug!( 274 - "Protocol {:?} in base configurations does not exist in system, discarding definition.", 275 - ident.protocol() 276 - ); 277 - continue; 278 - } 279 - */ 280 235 /* 281 236 for feature in attr.features() { 282 237 if let Err(e) = feature.is_valid() { ··· 292 247 // Finally, add in user configurations, which will have an address. 293 248 for kv in &self.user_device_definitions { 294 249 let (ident, attr) = (kv.key(), kv.value()); 295 - // If we don't have a protocol loaded for this configuration block, just drop it. We can't do 296 - // anything with it anyways. 297 - /* 298 - if !protocol_map.contains_key(ident.protocol()) { 299 - warn!( 300 - "Protocol {:?} in user configurations does not exist in system, discarding definition.", 301 - ident.protocol() 302 - ); 303 - continue; 304 - } 305 - */ 306 250 for feature in attr.features() { 307 251 if let Err(e) = feature.is_valid() { 308 252 error!("Feature {attr:?} for ident {ident:?} is not valid, skipping addition: {e:?}"); ··· 334 278 /// information about what commands can be sent to the device (Vibrate, Rotate, etc...), and the 335 279 /// parameters for those commands (number of power levels, stroke distances, etc...). 336 280 #[derive(Getters)] 281 + #[getset(get = "pub")] 337 282 pub struct DeviceConfigurationManager { 338 - // Map of protocol names to their respective protocol instance factories 339 - // protocol_map: HashMap<String, Arc<dyn ProtocolIdentifierFactory>>, 340 283 /// Communication specifiers from the base device config, mapped from protocol name to vector of 341 284 /// specifiers. Should not change/update during a session. 342 285 base_communication_specifiers: HashMap<String, Vec<ProtocolCommunicationSpecifier>>, ··· 344 287 base_device_definitions: HashMap<BaseDeviceIdentifier, BaseDeviceDefinition>, 345 288 /// Communication specifiers provided by the user, mapped from protocol name to vector of 346 289 /// specifiers. Loaded at session start, may change over life of session. 347 - #[getset(get = "pub")] 348 290 user_communication_specifiers: DashMap<String, Vec<ProtocolCommunicationSpecifier>>, 349 - /// Device definitions from the base device config. Loaded at session start, may change over life 291 + /// Device definitions from the user device config. Loaded at session start, may change over life 350 292 /// of session. 351 - #[getset(get = "pub")] 352 293 user_device_definitions: DashMap<UserDeviceIdentifier, DeviceDefinition>, 353 294 } 354 295 ··· 483 424 ) -> HashMap<String, Vec<ProtocolCommunicationSpecifier>> { 484 425 self.base_communication_specifiers.clone() 485 426 } 486 - /* 487 - pub fn protocol_specializers( 488 - &self, 489 - specifier: &ProtocolCommunicationSpecifier, 490 - ) -> Vec<ProtocolSpecializer> { 491 - debug!( 492 - "Looking for protocol that matches specifier: {:?}", 493 - specifier 494 - ); 495 - let mut specializers = vec![]; 496 427 497 - let mut update_specializer_map = 498 - |name: &str, specifiers: &Vec<ProtocolCommunicationSpecifier>| { 499 - if specifiers.contains(specifier) { 500 - info!( 501 - "Found protocol {:?} for user specifier {:?}.", 502 - name, specifier 503 - ); 504 - 505 - if self.protocol_map.contains_key(name) { 506 - specializers.push(ProtocolSpecializer::new( 507 - specifiers.clone(), 508 - self 509 - .protocol_map 510 - .get(name) 511 - .expect("already checked existence") 512 - .create(), 513 - )); 514 - } else { 515 - warn!( 516 - "No protocol implementation for {:?} found for specifier {:?}.", 517 - name, specifier 518 - ); 519 - } 520 - } 521 - }; 522 - 523 - // Loop through both maps, as chaining between DashMap and HashMap gets kinda gross. 524 - for spec in self.user_communication_specifiers.iter() { 525 - update_specializer_map(spec.key(), spec.value()); 526 - } 527 - for (name, specifiers) in self.base_communication_specifiers.iter() { 528 - update_specializer_map(name, specifiers); 529 - } 530 - specializers 531 - } 532 - */ 533 428 pub fn device_definition(&self, identifier: &UserDeviceIdentifier) -> Option<DeviceDefinition> { 534 429 let features = if let Some(attrs) = self.user_device_definitions.get(identifier) { 535 430 debug!("User device config found for {:?}", identifier); ··· 567 462 Some(features) 568 463 } 569 464 } 570 - 571 - /* 572 - #[cfg(test)] 573 - mod test { 574 - use super::*; 575 - use crate::{ 576 - core::message::{OutputType, FeatureType}, 577 - server::message::server_device_feature::{ServerDeviceFeature, ServerDeviceFeatureOutput}, 578 - }; 579 - use std::{ 580 - collections::{HashMap, HashSet}, 581 - ops::RangeInclusive, 582 - }; 583 - 584 - fn create_unit_test_dcm() -> DeviceConfigurationManager { 585 - let mut builder = DeviceConfigurationManagerBuilder::default(); 586 - let specifiers = ProtocolCommunicationSpecifier::BluetoothLE(BluetoothLESpecifier::new( 587 - HashSet::from(["LVS-*".to_owned(), "LovenseDummyTestName".to_owned()]), 588 - vec![], 589 - HashSet::new(), 590 - HashMap::new(), 591 - )); 592 - let mut feature_actuator = HashMap::new(); 593 - feature_actuator.insert( 594 - OutputType::Vibrate, 595 - ServerDeviceFeatureOutput::new(&RangeInclusive::new(0, 20), &RangeInclusive::new(0, 20)), 596 - ); 597 - builder 598 - .communication_specifier("lovense", &[specifiers]) 599 - .protocol_features( 600 - &BaseDeviceIdentifier::new("lovense", &Some("P".to_owned())), 601 - &BaseDeviceDefinition::new( 602 - "Lovense Edge", 603 - &uuid::Uuid::new_v4(), 604 - &None, 605 - &vec![ 606 - ServerDeviceFeature::new( 607 - "Edge Vibration 1", 608 - &uuid::Uuid::new_v4(), 609 - &None, 610 - FeatureType::Vibrate, 611 - &Some(feature_actuator.clone()), 612 - &None, 613 - ), 614 - ServerDeviceFeature::new( 615 - "Edge Vibration 2", 616 - &uuid::Uuid::new_v4(), 617 - &None, 618 - FeatureType::Vibrate, 619 - &Some(feature_actuator.clone()), 620 - &None, 621 - ), 622 - ], 623 - &None 624 - ), 625 - ) 626 - .finish() 627 - .unwrap() 628 - } 629 - 630 - #[test] 631 - fn test_config_equals() { 632 - let config = create_unit_test_dcm(); 633 - let spec = ProtocolCommunicationSpecifier::BluetoothLE(BluetoothLESpecifier::new_from_device( 634 - "LVS-Something", 635 - &HashMap::new(), 636 - &[], 637 - )); 638 - assert!(!config.protocol_specializers(&spec).is_empty()); 639 - } 640 - 641 - #[test] 642 - fn test_config_wildcard_equals() { 643 - let config = create_unit_test_dcm(); 644 - let spec = ProtocolCommunicationSpecifier::BluetoothLE(BluetoothLESpecifier::new_from_device( 645 - "LVS-Whatever", 646 - &HashMap::new(), 647 - &[], 648 - )); 649 - assert!(!config.protocol_specializers(&spec).is_empty()); 650 - } 651 - /* 652 - #[test] 653 - fn test_specific_device_config_creation() { 654 - let dcm = create_unit_test_dcm(false); 655 - let spec = ProtocolCommunicationSpecifier::BluetoothLE(BluetoothLESpecifier::new_from_device( 656 - "LVS-Whatever", 657 - &HashMap::new(), 658 - &[], 659 - )); 660 - assert!(!dcm.protocol_specializers(&spec).is_empty()); 661 - let config: ProtocolDeviceAttributes = dcm 662 - .device_definition( 663 - &UserDeviceIdentifier::new("Whatever", "lovense", &Some("P".to_owned())), 664 - &[], 665 - ) 666 - .expect("Should be found") 667 - .into(); 668 - // Make sure we got the right name 669 - assert_eq!(config.name(), "Lovense Edge"); 670 - // Make sure we overwrote the default of 1 671 - assert_eq!( 672 - config 673 - .message_attributes() 674 - .scalar_cmd() 675 - .as_ref() 676 - .expect("Test, assuming infallible") 677 - .get(0) 678 - .expect("Test, assuming infallible") 679 - .step_count(), 680 - 20 681 - ); 682 - } 683 - */ 684 - } 685 - */