···1+2+use buttplug_core::errors::ButtplugDeviceError;
3+use dashmap::DashMap;
4+use getset::Getters;
5+use std::{
6+ collections::HashMap,
7+ fmt::{self, Debug},
8+};
9+10+use crate::{BaseDeviceIdentifier, ProtocolCommunicationSpecifier, ServerDeviceDefinition, UserDeviceIdentifier};
11+12+#[derive(Default, Clone)]
13+pub struct DeviceConfigurationManagerBuilder {
14+ communication_specifiers: HashMap<String, Vec<ProtocolCommunicationSpecifier>>,
15+ user_communication_specifiers: DashMap<String, Vec<ProtocolCommunicationSpecifier>>,
16+ base_device_definitions: HashMap<BaseDeviceIdentifier, ServerDeviceDefinition>,
17+ user_device_definitions: DashMap<UserDeviceIdentifier, ServerDeviceDefinition>,
18+}
19+20+impl DeviceConfigurationManagerBuilder {
21+ pub fn communication_specifier(
22+ &mut self,
23+ protocol_name: &str,
24+ specifier: &[ProtocolCommunicationSpecifier],
25+ ) -> &mut Self {
26+ self
27+ .communication_specifiers
28+ .entry(protocol_name.to_owned())
29+ .or_default()
30+ .extend(specifier.iter().cloned());
31+ self
32+ }
33+34+ pub fn protocol_features(
35+ &mut self,
36+ identifier: &BaseDeviceIdentifier,
37+ features: &ServerDeviceDefinition,
38+ ) -> &mut Self {
39+ self
40+ .base_device_definitions
41+ .insert(identifier.clone(), features.clone());
42+ self
43+ }
44+45+ pub fn user_communication_specifier(
46+ &mut self,
47+ protocol_name: &str,
48+ specifier: &[ProtocolCommunicationSpecifier],
49+ ) -> &mut Self {
50+ self
51+ .user_communication_specifiers
52+ .entry(protocol_name.to_owned())
53+ .or_default()
54+ .extend(specifier.iter().cloned());
55+ self
56+ }
57+58+ pub fn user_protocol_features(
59+ &mut self,
60+ identifier: &UserDeviceIdentifier,
61+ features: &ServerDeviceDefinition,
62+ ) -> &mut Self {
63+ if let Some((_, base_definition)) = self
64+ .base_device_definitions
65+ .iter()
66+ .find(|(_, x)| x.id() == features.base_id())
67+ {
68+ self.user_device_definitions.insert(
69+ identifier.clone(),
70+ ServerDeviceDefinition::new(base_definition, features),
71+ );
72+ } else {
73+ error!(
74+ "Cannot find protocol with base id {} for user id {}",
75+ features.base_id(),
76+ features.id()
77+ )
78+ }
79+ self
80+ }
81+82+ pub fn finish(&mut self) -> Result<DeviceConfigurationManager, ButtplugDeviceError> {
83+ // Build and validate the protocol attributes tree.
84+ let mut attribute_tree_map = HashMap::new();
85+86+ // Add all the defaults first, they won't have parent attributes.
87+ for (ident, attr) in &self.base_device_definitions {
88+ /*
89+ for feature in attr.features() {
90+ if let Err(e) = feature.is_valid() {
91+ error!("Feature {attr:?} for ident {ident:?} is not valid, skipping addition: {e:?}");
92+ continue;
93+ }
94+ }
95+ */
96+ attribute_tree_map.insert(ident.clone(), attr.clone());
97+ }
98+99+ let user_attribute_tree_map = DashMap::new();
100+ // Finally, add in user configurations, which will have an address.
101+ for kv in &self.user_device_definitions {
102+ let (ident, attr) = (kv.key(), kv.value());
103+ for feature in attr.features() {
104+ if let Err(e) = feature.is_valid() {
105+ error!("Feature {attr:?} for ident {ident:?} is not valid, skipping addition: {e:?}");
106+ continue;
107+ }
108+ }
109+ user_attribute_tree_map.insert(kv.key().clone(), kv.value().clone());
110+ }
111+112+ Ok(DeviceConfigurationManager {
113+ base_communication_specifiers: self.communication_specifiers.clone(),
114+ user_communication_specifiers: self.user_communication_specifiers.clone(),
115+ base_device_definitions: attribute_tree_map,
116+ user_device_definitions: user_attribute_tree_map,
117+ //protocol_map,
118+ })
119+ }
120+}
121+122+/// Correlates information about protocols and which devices they support.
123+///
124+/// The [DeviceConfigurationManager] handles stores information about which device protocols the
125+/// library supports, as well as which devices can use those protocols. When a
126+/// [DeviceCommunicationManager](crate::server::device::communication_manager) finds a device during scanning,
127+/// device information is given to the [DeviceConfigurationManager] to decide whether Buttplug
128+/// should try to connect to and communicate with the device.
129+///
130+/// Assuming the device is supported by the library, the [DeviceConfigurationManager] also stores
131+/// information about what commands can be sent to the device (Vibrate, Rotate, etc...), and the
132+/// parameters for those commands (number of power levels, stroke distances, etc...).
133+#[derive(Getters)]
134+#[getset(get = "pub")]
135+pub struct DeviceConfigurationManager {
136+ /// Communication specifiers from the base device config, mapped from protocol name to vector of
137+ /// specifiers. Should not change/update during a session.
138+ base_communication_specifiers: HashMap<String, Vec<ProtocolCommunicationSpecifier>>,
139+ /// Device definitions from the base device config. Should not change/update during a session.
140+ base_device_definitions: HashMap<BaseDeviceIdentifier, ServerDeviceDefinition>,
141+ /// Communication specifiers provided by the user, mapped from protocol name to vector of
142+ /// specifiers. Loaded at session start, may change over life of session.
143+ user_communication_specifiers: DashMap<String, Vec<ProtocolCommunicationSpecifier>>,
144+ /// Device definitions from the user device config. Loaded at session start, may change over life
145+ /// of session.
146+ user_device_definitions: DashMap<UserDeviceIdentifier, ServerDeviceDefinition>,
147+}
148+149+impl Debug for DeviceConfigurationManager {
150+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151+ f.debug_struct("DeviceConfigurationManager").finish()
152+ }
153+}
154+155+impl Default for DeviceConfigurationManager {
156+ fn default() -> Self {
157+ // Unwrap allowed here because we assume our built in device config will
158+ // always work. System won't pass tests or possibly even build otherwise.
159+ DeviceConfigurationManagerBuilder::default()
160+ .finish()
161+ .expect("Default creation of a DCM should always work.")
162+ }
163+}
164+165+impl DeviceConfigurationManager {
166+ pub fn add_user_communication_specifier(
167+ &self,
168+ protocol: &str,
169+ specifier: &ProtocolCommunicationSpecifier,
170+ ) -> Result<(), ButtplugDeviceError> {
171+ //self.protocol_map.contains_key(protocol);
172+ self
173+ .user_communication_specifiers
174+ .entry(protocol.to_owned())
175+ .or_default()
176+ .push(specifier.clone());
177+ Ok(())
178+ }
179+180+ pub fn remove_user_communication_specifier(
181+ &self,
182+ protocol: &str,
183+ specifier: &ProtocolCommunicationSpecifier,
184+ ) {
185+ if let Some(mut specifiers) = self.user_communication_specifiers.get_mut(protocol) {
186+ let specifier_vec = specifiers.value_mut();
187+ *specifier_vec = specifier_vec
188+ .iter()
189+ .filter(|s| *specifier != **s)
190+ .cloned()
191+ .collect();
192+ }
193+ }
194+195+ pub fn add_user_device_definition(
196+ &self,
197+ identifier: &UserDeviceIdentifier,
198+ definition: &ServerDeviceDefinition,
199+ ) -> Result<(), ButtplugDeviceError> {
200+ //self.protocol_map.contains_key(identifier.protocol());
201+ // Check validity of device
202+ let mut index = definition.user_config().index();
203+ let indexes: Vec<u32> = self.user_device_definitions().iter().map(|x| x.value().user_config().index()).collect();
204+ // If we just added 1 to the maximum value of the current indexes, someone decides to set an
205+ // index to u32::MAX-1, then we'd have a problem. This is kind of a shit solution but it'll work
206+ // quickly for anyone that's not actively fucking with us by manually playing with user config files.
207+ while indexes.contains(&index) {
208+ index = index.wrapping_add(1);
209+ }
210+ let mut def = definition.clone();
211+ *def.user_device_mut().user_config_mut().index_mut() = index;
212+ self
213+ .user_device_definitions
214+ .entry(identifier.clone())
215+ .insert(def);
216+ Ok(())
217+ }
218+219+ pub fn remove_user_device_definition(&self, identifier: &UserDeviceIdentifier) {
220+ self.user_device_definitions.remove(identifier);
221+ }
222+223+ pub fn address_allowed(&self, address: &str) -> bool {
224+ // Make sure the device isn't on the deny list
225+ if self
226+ .user_device_definitions
227+ .iter()
228+ .any(|kv| kv.key().address() == address && kv.value().user_config().deny())
229+ {
230+ // If device is outright denied, deny
231+ info!(
232+ "Device {} denied by configuration, not connecting.",
233+ address
234+ );
235+ false
236+ } else if self
237+ .user_device_definitions
238+ .iter()
239+ .any(|kv| kv.value().user_config().allow())
240+ && !self
241+ .user_device_definitions
242+ .iter()
243+ .any(|kv| kv.key().address() == address && kv.value().user_config().allow())
244+ {
245+ // If device is not on allow list and allow list isn't empty, deny
246+ info!(
247+ "Device {} not on allow list and allow list not empty, not connecting.",
248+ address
249+ );
250+ false
251+ } else {
252+ true
253+ }
254+ }
255+256+ fn device_index(&self, identifier: &UserDeviceIdentifier) -> u32 {
257+ // See if we have a reserved or reusable device index here.
258+ if let Some(config) = self.user_device_definitions.get(identifier) {
259+ let index = config.user_config().index();
260+ debug!("Found index {index} for device {identifier:?}");
261+ return index;
262+ }
263+264+ let current_indexes: Vec<u32> = self
265+ .user_device_definitions
266+ .iter()
267+ .map(|x| x.user_config().index())
268+ .collect();
269+270+ // Someone is gonna make a max device index in their config file just to fuck with me, therefore
271+ // we don't do "max + 1", we fill in holes (lol) in sequences. To whomever has 4 billion sex toys:
272+ // sorry your index finding for new devices is slow and takes 16GB of allocation every time we
273+ // want to search the index space.
274+275+ let mut index = 0;
276+ while current_indexes.contains(&index) {
277+ index += 1;
278+ }
279+ debug!("Generating and assigning index {index:?} for device {identifier:?}");
280+ index
281+ }
282+283+ /// Provides read-only access to the internal protocol/identifier map. Mainly
284+ /// used for WebBluetooth filter construction, but could also be handy for
285+ /// listing capabilities in UI, etc.
286+ pub fn protocol_device_configurations(
287+ &self,
288+ ) -> HashMap<String, Vec<ProtocolCommunicationSpecifier>> {
289+ self.base_communication_specifiers.clone()
290+ }
291+292+ pub fn device_definition(&self, identifier: &UserDeviceIdentifier) -> Option<DeviceDefinition> {
293+ let features = if let Some(attrs) = self.user_device_definitions.get(identifier) {
294+ debug!("User device config found for {:?}", identifier);
295+ attrs.clone()
296+ } else if let Some(attrs) = self.base_device_definitions.get(&BaseDeviceIdentifier::new(
297+ identifier.protocol(),
298+ identifier.identifier(),
299+ )) {
300+ debug!(
301+ "Protocol + Identifier device config found for {:?}",
302+ identifier
303+ );
304+ DeviceDefinition::new_from_base_definition(attrs, self.device_index(identifier))
305+ } else if let Some(attrs) = self
306+ .base_device_definitions
307+ .get(&BaseDeviceIdentifier::new(identifier.protocol(), &None))
308+ {
309+ debug!("Protocol device config found for {:?}", identifier);
310+ DeviceDefinition::new_from_base_definition(attrs, self.device_index(identifier))
311+ } else {
312+ return None;
313+ };
314+315+ // If this is a new device, it needs to be added to the user device definition map.
316+ //
317+ // Device definitions are looked up before we fully initialize a device, mostly for algorithm
318+ // preparation. There is a very small chance we may save the device config then error out when
319+ // we connect to the device, but we'll assume we may connect successfully later.
320+ if self.user_device_definitions.get(identifier).is_none() {
321+ self
322+ .user_device_definitions
323+ .insert(identifier.clone(), features.clone());
324+ }
325+326+ Some(features)
327+ }
328+}
···1314use core::hash::Hash;
1516-// We need this array to be exposed in our WASM FFI, but the only way to do that
17-// is to expose it at the declaration level. Therefore, we use the WASM feature
18-// to assume we're building for WASM and attach our bindgen. The serde
19-// de/serialization is taken care of at the FFI level.
20-21/// Endpoint names for device communication.
22///
23/// Endpoints denote different contextual communication targets on a device. For instance, for a
···1314use core::hash::Hash;
150000016/// Endpoint names for device communication.
17///
18/// Endpoints denote different contextual communication targets on a device. For instance, for a
···137#[macro_use]
138extern crate strum_macros;
1390000000140mod specifier;
141pub use specifier::*;
142mod identifiers;
···145pub use device_definitions::*;
146mod device_feature;
147pub use device_feature::*;
148-mod device_configuration;
149-pub use device_configuration::*;
150mod endpoint;
151pub use endpoint::*;
152153-use buttplug_core::errors::ButtplugDeviceError;
154-use dashmap::DashMap;
155-use getset::Getters;
156-use std::{
157- collections::HashMap,
158- fmt::{self, Debug},
159-};
160161-#[macro_use]
162-extern crate log;
163-164-#[derive(Default, Clone)]
165-pub struct DeviceConfigurationManagerBuilder {
166- communication_specifiers: HashMap<String, Vec<ProtocolCommunicationSpecifier>>,
167- user_communication_specifiers: DashMap<String, Vec<ProtocolCommunicationSpecifier>>,
168- base_device_definitions: HashMap<BaseDeviceIdentifier, BaseDeviceDefinition>,
169- user_device_definitions: DashMap<UserDeviceIdentifier, DeviceDefinition>,
170-}
171-172-impl DeviceConfigurationManagerBuilder {
173- pub fn communication_specifier(
174- &mut self,
175- protocol_name: &str,
176- specifier: &[ProtocolCommunicationSpecifier],
177- ) -> &mut Self {
178- self
179- .communication_specifiers
180- .entry(protocol_name.to_owned())
181- .or_default()
182- .extend(specifier.iter().cloned());
183- self
184- }
185-186- pub fn protocol_features(
187- &mut self,
188- identifier: &BaseDeviceIdentifier,
189- features: &BaseDeviceDefinition,
190- ) -> &mut Self {
191- self
192- .base_device_definitions
193- .insert(identifier.clone(), features.clone());
194- self
195- }
196-197- pub fn user_communication_specifier(
198- &mut self,
199- protocol_name: &str,
200- specifier: &[ProtocolCommunicationSpecifier],
201- ) -> &mut Self {
202- self
203- .user_communication_specifiers
204- .entry(protocol_name.to_owned())
205- .or_default()
206- .extend(specifier.iter().cloned());
207- self
208- }
209-210- pub fn user_protocol_features(
211- &mut self,
212- identifier: &UserDeviceIdentifier,
213- features: &UserDeviceDefinition,
214- ) -> &mut Self {
215- if let Some((_, base_definition)) = self
216- .base_device_definitions
217- .iter()
218- .find(|(_, x)| x.id() == features.base_id())
219- {
220- self.user_device_definitions.insert(
221- identifier.clone(),
222- DeviceDefinition::new(base_definition, features),
223- );
224- } else {
225- error!(
226- "Cannot find protocol with base id {} for user id {}",
227- features.base_id(),
228- features.id()
229- )
230- }
231- self
232- }
233-234- pub fn finish(&mut self) -> Result<DeviceConfigurationManager, ButtplugDeviceError> {
235- // Build and validate the protocol attributes tree.
236- let mut attribute_tree_map = HashMap::new();
237-238- // Add all the defaults first, they won't have parent attributes.
239- for (ident, attr) in &self.base_device_definitions {
240- /*
241- for feature in attr.features() {
242- if let Err(e) = feature.is_valid() {
243- error!("Feature {attr:?} for ident {ident:?} is not valid, skipping addition: {e:?}");
244- continue;
245- }
246- }
247- */
248- attribute_tree_map.insert(ident.clone(), attr.clone());
249- }
250-251- let user_attribute_tree_map = DashMap::new();
252- // Finally, add in user configurations, which will have an address.
253- for kv in &self.user_device_definitions {
254- let (ident, attr) = (kv.key(), kv.value());
255- for feature in attr.features() {
256- if let Err(e) = feature.is_valid() {
257- error!("Feature {attr:?} for ident {ident:?} is not valid, skipping addition: {e:?}");
258- continue;
259- }
260- }
261- user_attribute_tree_map.insert(kv.key().clone(), kv.value().clone());
262- }
263-264- Ok(DeviceConfigurationManager {
265- base_communication_specifiers: self.communication_specifiers.clone(),
266- user_communication_specifiers: self.user_communication_specifiers.clone(),
267- base_device_definitions: attribute_tree_map,
268- user_device_definitions: user_attribute_tree_map,
269- //protocol_map,
270- })
271- }
272-}
273-274-/// Correlates information about protocols and which devices they support.
275-///
276-/// The [DeviceConfigurationManager] handles stores information about which device protocols the
277-/// library supports, as well as which devices can use those protocols. When a
278-/// [DeviceCommunicationManager](crate::server::device::communication_manager) finds a device during scanning,
279-/// device information is given to the [DeviceConfigurationManager] to decide whether Buttplug
280-/// should try to connect to and communicate with the device.
281-///
282-/// Assuming the device is supported by the library, the [DeviceConfigurationManager] also stores
283-/// information about what commands can be sent to the device (Vibrate, Rotate, etc...), and the
284-/// parameters for those commands (number of power levels, stroke distances, etc...).
285-#[derive(Getters)]
286-#[getset(get = "pub")]
287-pub struct DeviceConfigurationManager {
288- /// Communication specifiers from the base device config, mapped from protocol name to vector of
289- /// specifiers. Should not change/update during a session.
290- base_communication_specifiers: HashMap<String, Vec<ProtocolCommunicationSpecifier>>,
291- /// Device definitions from the base device config. Should not change/update during a session.
292- base_device_definitions: HashMap<BaseDeviceIdentifier, BaseDeviceDefinition>,
293- /// Communication specifiers provided by the user, mapped from protocol name to vector of
294- /// specifiers. Loaded at session start, may change over life of session.
295- user_communication_specifiers: DashMap<String, Vec<ProtocolCommunicationSpecifier>>,
296- /// Device definitions from the user device config. Loaded at session start, may change over life
297- /// of session.
298- user_device_definitions: DashMap<UserDeviceIdentifier, DeviceDefinition>,
299-}
300-301-impl Debug for DeviceConfigurationManager {
302- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303- f.debug_struct("DeviceConfigurationManager").finish()
304- }
305-}
306-307-impl Default for DeviceConfigurationManager {
308- fn default() -> Self {
309- // Unwrap allowed here because we assume our built in device config will
310- // always work. System won't pass tests or possibly even build otherwise.
311- DeviceConfigurationManagerBuilder::default()
312- .finish()
313- .expect("Default creation of a DCM should always work.")
314- }
315-}
316-317-impl DeviceConfigurationManager {
318- pub fn add_user_communication_specifier(
319- &self,
320- protocol: &str,
321- specifier: &ProtocolCommunicationSpecifier,
322- ) -> Result<(), ButtplugDeviceError> {
323- //self.protocol_map.contains_key(protocol);
324- self
325- .user_communication_specifiers
326- .entry(protocol.to_owned())
327- .or_default()
328- .push(specifier.clone());
329- Ok(())
330- }
331-332- pub fn remove_user_communication_specifier(
333- &self,
334- protocol: &str,
335- specifier: &ProtocolCommunicationSpecifier,
336- ) {
337- if let Some(mut specifiers) = self.user_communication_specifiers.get_mut(protocol) {
338- let specifier_vec = specifiers.value_mut();
339- *specifier_vec = specifier_vec
340- .iter()
341- .filter(|s| *specifier != **s)
342- .cloned()
343- .collect();
344- }
345- }
346-347- pub fn add_user_device_definition(
348- &self,
349- identifier: &UserDeviceIdentifier,
350- definition: &DeviceDefinition,
351- ) -> Result<(), ButtplugDeviceError> {
352- //self.protocol_map.contains_key(identifier.protocol());
353- // Check validity of device
354- let mut index = definition.user_config().index();
355- let indexes: Vec<u32> = self.user_device_definitions().iter().map(|x| x.value().user_config().index()).collect();
356- // If we just added 1 to the maximum value of the current indexes, someone decides to set an
357- // index to u32::MAX-1, then we'd have a problem. This is kind of a shit solution but it'll work
358- // quickly for anyone that's not actively fucking with us by manually playing with user config files.
359- while indexes.contains(&index) {
360- index = index.wrapping_add(1);
361- }
362- let mut def = definition.clone();
363- *def.user_device_mut().user_config_mut().index_mut() = index;
364- self
365- .user_device_definitions
366- .entry(identifier.clone())
367- .insert(def);
368- Ok(())
369- }
370-371- pub fn remove_user_device_definition(&self, identifier: &UserDeviceIdentifier) {
372- self.user_device_definitions.remove(identifier);
373- }
374-375- pub fn address_allowed(&self, address: &str) -> bool {
376- // Make sure the device isn't on the deny list
377- if self
378- .user_device_definitions
379- .iter()
380- .any(|kv| kv.key().address() == address && kv.value().user_config().deny())
381- {
382- // If device is outright denied, deny
383- info!(
384- "Device {} denied by configuration, not connecting.",
385- address
386- );
387- false
388- } else if self
389- .user_device_definitions
390- .iter()
391- .any(|kv| kv.value().user_config().allow())
392- && !self
393- .user_device_definitions
394- .iter()
395- .any(|kv| kv.key().address() == address && kv.value().user_config().allow())
396- {
397- // If device is not on allow list and allow list isn't empty, deny
398- info!(
399- "Device {} not on allow list and allow list not empty, not connecting.",
400- address
401- );
402- false
403- } else {
404- true
405- }
406- }
407-408- fn device_index(&self, identifier: &UserDeviceIdentifier) -> u32 {
409- // See if we have a reserved or reusable device index here.
410- if let Some(config) = self.user_device_definitions.get(identifier) {
411- let index = config.user_config().index();
412- debug!("Found index {index} for device {identifier:?}");
413- return index;
414- }
415-416- let current_indexes: Vec<u32> = self
417- .user_device_definitions
418- .iter()
419- .map(|x| x.user_config().index())
420- .collect();
421-422- // Someone is gonna make a max device index in their config file just to fuck with me, therefore
423- // we don't do "max + 1", we fill in holes (lol) in sequences. To whomever has 4 billion sex toys:
424- // sorry your index finding for new devices is slow and takes 16GB of allocation every time we
425- // want to search the index space.
426-427- let mut index = 0;
428- while current_indexes.contains(&index) {
429- index += 1;
430- }
431- debug!("Generating and assigning index {index:?} for device {identifier:?}");
432- index
433- }
434435- /// Provides read-only access to the internal protocol/identifier map. Mainly
436- /// used for WebBluetooth filter construction, but could also be handy for
437- /// listing capabilities in UI, etc.
438- pub fn protocol_device_configurations(
439- &self,
440- ) -> HashMap<String, Vec<ProtocolCommunicationSpecifier>> {
441- self.base_communication_specifiers.clone()
442- }
443-444- pub fn device_definition(&self, identifier: &UserDeviceIdentifier) -> Option<DeviceDefinition> {
445- let features = if let Some(attrs) = self.user_device_definitions.get(identifier) {
446- debug!("User device config found for {:?}", identifier);
447- attrs.clone()
448- } else if let Some(attrs) = self.base_device_definitions.get(&BaseDeviceIdentifier::new(
449- identifier.protocol(),
450- identifier.identifier(),
451- )) {
452- debug!(
453- "Protocol + Identifier device config found for {:?}",
454- identifier
455- );
456- DeviceDefinition::new_from_base_definition(attrs, self.device_index(identifier))
457- } else if let Some(attrs) = self
458- .base_device_definitions
459- .get(&BaseDeviceIdentifier::new(identifier.protocol(), &None))
460- {
461- debug!("Protocol device config found for {:?}", identifier);
462- DeviceDefinition::new_from_base_definition(attrs, self.device_index(identifier))
463- } else {
464- return None;
465- };
466-467- // If this is a new device, it needs to be added to the user device definition map.
468- //
469- // Device definitions are looked up before we fully initialize a device, mostly for algorithm
470- // preparation. There is a very small chance we may save the device config then error out when
471- // we connect to the device, but we'll assume we may connect successfully later.
472- if self.user_device_definitions.get(identifier).is_none() {
473- self
474- .user_device_definitions
475- .insert(identifier.clone(), features.clone());
476- }
477-478- Some(features)
479- }
480}
···137#[macro_use]
138extern crate strum_macros;
139140+#[macro_use]
141+extern crate log;
142+143+mod device_config_file;
144+pub use device_config_file::{load_protocol_configs, save_user_config};
145+mod device_config_manager;
146+pub use device_config_manager::*;
147mod specifier;
148pub use specifier::*;
149mod identifiers;
···152pub use device_definitions::*;
153mod device_feature;
154pub use device_feature::*;
00155mod endpoint;
156pub use endpoint::*;
1570000000158159+use std::ops::RangeInclusive;
160+use serde::Serializer;
161+use thiserror::Error;
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000162163+#[derive(Error, Debug)]
164+pub enum ButtplugDeviceConfigError<T> {
165+ /// Conversion to client type not possible with requested property type
166+ #[error("Conversion of {0} to client type not possible with requested property type")]
167+ InvalidOutputTypeConversion(String),
168+ /// User set range exceeds bounds of possible configuration range
169+ #[error("User set range {0} exceeds bounds of possible configuration range {1}")]
170+ InvalidUserRange(RangeInclusive<T>, RangeInclusive<T>),
171+ /// Base range required
172+ #[error("Base range required for all feature outputs")]
173+ BaseRangeRequired,
0000000000000000000000000000000000174}
···11use std::collections::{HashMap, HashSet};
12use uuid::Uuid;
1314-// Note: There's a ton of extra structs in here just to deserialize the json
15-// file. Just leave them and build extras (for instance,
16-// DeviceProtocolConfiguration) if needed elsewhere in the codebase. It's not
17-// gonna hurt anything and making a ton of serde attributes is just going to get
18-// confusing (see the messages impl).
19-20#[derive(Serialize, Deserialize, Debug, Clone, Getters, MutGetters, Setters, Eq)]
21#[getset(get = "pub", set = "pub", get_mut = "pub(crate)")]
22pub struct BluetoothLEManufacturerData {