Buttplug sex toy control library

chore: Finish separation of serialized config and DCM

+292 -138
+1 -1
crates/buttplug_server_device_config/src/device_config_file/base.rs
··· 32 32 } 33 33 34 34 impl BaseConfigFile { 35 - pub fn new(major_version: u32, minor_version: u32) -> Self { 35 + pub(crate) fn new(major_version: u32, minor_version: u32) -> Self { 36 36 Self { 37 37 version: ConfigVersion { 38 38 major: major_version,
+27 -1
crates/buttplug_server_device_config/src/device_config_file/device.rs
··· 2 2 use serde::{Deserialize, Serialize}; 3 3 use uuid::Uuid; 4 4 5 - use crate::{ServerDeviceDefinition, ServerDeviceDefinitionBuilder}; 5 + use crate::{ButtplugDeviceConfigError, ServerDeviceDefinition, ServerDeviceDefinitionBuilder}; 6 6 7 7 use super::feature::{ConfigBaseDeviceFeature, ConfigUserDeviceFeature}; 8 8 ··· 96 96 /// Per-user configurations specific to this device instance. 97 97 user_config: ConfigUserDeviceCustomization, 98 98 } 99 + 100 + impl ConfigUserDeviceDefinition { 101 + pub fn build_from_base_definition(&self, base: &ServerDeviceDefinition) -> Result<ServerDeviceDefinition, ButtplugDeviceConfigError> { 102 + let mut builder = ServerDeviceDefinitionBuilder::from_base(&base, self.id); 103 + if let Some(display_name) = &self.user_config.display_name { 104 + builder.display_name(display_name); 105 + } 106 + if let Some(message_gap_ms) = self.user_config.message_gap_ms { 107 + builder.message_gap_ms(message_gap_ms); 108 + } 109 + self.user_config.allow.then(|| builder.allow()); 110 + self.user_config.deny.then(|| builder.deny()); 111 + builder.index(self.user_config.index); 112 + if self.features().len() != base.features().len() { 113 + return Err(ButtplugDeviceConfigError::UserFeatureMismatch); 114 + } 115 + for feature in self.features() { 116 + if let Some(base_feature) = base.features().iter().find(|x| x.id() == feature.base_id()) { 117 + builder.add_feature(&feature.with_base_feature(base_feature)?); 118 + } else { 119 + return Err(ButtplugDeviceConfigError::UserFeatureMismatch); 120 + } 121 + } 122 + Ok(builder.finish()) 123 + } 124 + }
+118 -4
crates/buttplug_server_device_config/src/device_config_file/feature.rs
··· 4 4 use getset::{CopyGetters, Getters, MutGetters, Setters}; 5 5 use serde::{Deserialize, Serialize}; 6 6 use uuid::Uuid; 7 - use crate::{ServerDeviceFeature, ServerDeviceFeatureInput, ServerDeviceFeatureInputProperties, ServerDeviceFeatureOutput, ServerDeviceFeatureOutputPositionWithDurationProperties, ServerDeviceFeatureOutputValueProperties}; 7 + use crate::{ButtplugDeviceConfigError, RangeWithLimit, ServerDeviceFeature, ServerDeviceFeatureInput, ServerDeviceFeatureInputProperties, ServerDeviceFeatureOutput, ServerDeviceFeatureOutputPositionProperties, ServerDeviceFeatureOutputPositionWithDurationProperties, ServerDeviceFeatureOutputValueProperties}; 8 8 9 9 use super::range_sequence_serialize; 10 10 ··· 20 20 } 21 21 22 22 #[derive(Serialize, Deserialize, Clone, Debug)] 23 + struct BaseDeviceFeatureOutputPositionProperties { 24 + value: RangeInclusive<u32> 25 + } 26 + 27 + impl Into<ServerDeviceFeatureOutputPositionProperties> for BaseDeviceFeatureOutputPositionProperties { 28 + fn into(self) -> ServerDeviceFeatureOutputPositionProperties { 29 + ServerDeviceFeatureOutputPositionProperties::new(&self.value.into(), false, false) 30 + } 31 + } 32 + 33 + #[derive(Serialize, Deserialize, Clone, Debug)] 23 34 struct BaseDeviceFeatureOutputPositionWithDurationProperties { 24 35 position: RangeInclusive<u32>, 25 36 duration: RangeInclusive<u32>, ··· 48 59 #[serde(skip_serializing_if="Option::is_none")] 49 60 led: Option<BaseDeviceFeatureOutputValueProperties>, 50 61 #[serde(skip_serializing_if="Option::is_none")] 51 - position: Option<BaseDeviceFeatureOutputValueProperties>, 62 + position: Option<BaseDeviceFeatureOutputPositionProperties>, 52 63 #[serde(skip_serializing_if="Option::is_none")] 53 64 position_with_duration: Option<BaseDeviceFeatureOutputPositionWithDurationProperties>, 54 65 #[serde(skip_serializing_if="Option::is_none")] ··· 99 110 value: Option<RangeInclusive<i32>>, 100 111 #[serde(default)] 101 112 disabled: bool, 102 - #[serde(default)] 103 - reverse: bool 104 113 } 105 114 115 + impl UserDeviceFeatureOutputValueProperties { 116 + pub fn with_base_properties(&self, base: &ServerDeviceFeatureOutputValueProperties) -> Result<ServerDeviceFeatureOutputValueProperties, ButtplugDeviceConfigError> { 117 + let range = RangeWithLimit::try_new(base.value().base(), &self.value)?; 118 + Ok(ServerDeviceFeatureOutputValueProperties::new(&range, self.disabled)) 119 + } 120 + } 106 121 107 122 #[derive(Serialize, Deserialize, Clone, Debug)] 108 123 struct UserDeviceFeatureOutputPositionProperties { ··· 114 129 reverse: bool 115 130 } 116 131 132 + impl UserDeviceFeatureOutputPositionProperties { 133 + pub fn with_base_properties(&self, base: &ServerDeviceFeatureOutputPositionProperties) -> Result<ServerDeviceFeatureOutputPositionProperties, ButtplugDeviceConfigError> { 134 + let value = RangeWithLimit::try_new(base.position().base(), &self.value)?; 135 + Ok(ServerDeviceFeatureOutputPositionProperties::new(&value, self.disabled, self.reverse)) 136 + } 137 + } 138 + 117 139 #[derive(Serialize, Deserialize, Clone, Debug)] 118 140 struct UserDeviceFeatureOutputPositionWithDurationProperties { 119 141 #[serde(skip_serializing_if="Option::is_none")] ··· 126 148 reverse: bool 127 149 } 128 150 151 + impl UserDeviceFeatureOutputPositionWithDurationProperties { 152 + pub fn with_base_properties(&self, base: &ServerDeviceFeatureOutputPositionWithDurationProperties) -> Result<ServerDeviceFeatureOutputPositionWithDurationProperties, ButtplugDeviceConfigError> { 153 + let position = RangeWithLimit::try_new(base.position().base(), &self.position)?; 154 + let duration = RangeWithLimit::try_new(base.duration().base(), &self.duration)?; 155 + Ok(ServerDeviceFeatureOutputPositionWithDurationProperties::new(&position, &duration, self.disabled, self.reverse)) 156 + } 157 + } 129 158 #[derive(Serialize, Deserialize, Clone, Debug)] 130 159 struct UserDeviceFeatureOutput { 131 160 #[serde(skip_serializing_if="Option::is_none")] ··· 150 179 spray: Option<UserDeviceFeatureOutputValueProperties>, 151 180 } 152 181 182 + impl UserDeviceFeatureOutput { 183 + pub fn with_base_output(&self, base_output: &ServerDeviceFeatureOutput) -> Result<ServerDeviceFeatureOutput, ButtplugDeviceConfigError> { 184 + let mut output = ServerDeviceFeatureOutput::default(); 185 + if let Some(base_vibrate) = base_output.vibrate() { 186 + if let Some(user_vibrate) = &self.vibrate { 187 + output.set_vibrate(Some(user_vibrate.with_base_properties(base_vibrate)?)); 188 + } else { 189 + output.set_vibrate(base_output.vibrate().clone()); 190 + } 191 + } 192 + if let Some(user_rotate) = &self.rotate { 193 + if let Some(base_rotate) = base_output.rotate() { 194 + output.set_rotate(Some(user_rotate.with_base_properties(base_rotate)?)); 195 + } else { 196 + output.set_rotate(base_output.rotate().clone()); 197 + } 198 + } 199 + if let Some(user_oscillate) = &self.oscillate { 200 + if let Some(base_oscillate) = base_output.oscillate() { 201 + output.set_oscillate(Some(user_oscillate.with_base_properties(base_oscillate)?)); 202 + } else { 203 + output.set_oscillate(base_output.oscillate().clone()); 204 + } 205 + } 206 + if let Some(user_constrict) = &self.constrict { 207 + if let Some(base_constrict) = base_output.constrict() { 208 + output.set_constrict(Some(user_constrict.with_base_properties(base_constrict)?)); 209 + } else { 210 + output.set_constrict(base_output.constrict().clone()); 211 + } 212 + } 213 + if let Some(user_heater) = &self.heater { 214 + if let Some(base_heater) = base_output.heater() { 215 + output.set_heater(Some(user_heater.with_base_properties(base_heater)?)); 216 + } else { 217 + output.set_heater(base_output.heater().clone()); 218 + } 219 + } 220 + if let Some(user_led) = &self.led { 221 + if let Some(base_led) = base_output.led() { 222 + output.set_led(Some(user_led.with_base_properties(base_led)?)); 223 + } else { 224 + output.set_led(base_output.led().clone()); 225 + } 226 + } 227 + if let Some(user_spray) = &self.spray { 228 + if let Some(base_spray) = base_output.spray() { 229 + output.set_spray(Some(user_spray.with_base_properties(base_spray)?)); 230 + } else { 231 + output.set_spray(base_output.spray().clone()); 232 + } 233 + } 234 + if let Some(user) = &self.position { 235 + if let Some(base) = base_output.position() { 236 + output.set_position(Some(user.with_base_properties(base)?)); 237 + } else { 238 + output.set_position(base_output.position().clone()); 239 + } 240 + } 241 + if let Some(user) = &self.position_with_duration { 242 + if let Some(base) = base_output.position_with_duration() { 243 + output.set_position_with_duration(Some(user.with_base_properties(base)?)); 244 + } else { 245 + output.set_position_with_duration(base_output.position_with_duration().clone()); 246 + } 247 + } 248 + Ok(output) 249 + } 250 + } 251 + 153 252 #[derive( 154 253 Clone, Debug, Default, PartialEq, Eq, Getters, MutGetters, Setters, Serialize, Deserialize, 155 254 )] ··· 267 366 #[getset(get = "pub")] 268 367 #[serde(rename = "output", skip_serializing_if = "Option::is_none")] 269 368 output: Option<UserDeviceFeatureOutput> 369 + } 370 + 371 + impl ConfigUserDeviceFeature { 372 + pub fn with_base_feature(&self, base_feature: &ServerDeviceFeature) -> Result<ServerDeviceFeature, ButtplugDeviceConfigError> { 373 + let output = if let Some(o) = &self.output { 374 + if let Some(base) = base_feature.output() { 375 + Some(o.with_base_output(&base)?) 376 + } else { 377 + None 378 + } 379 + } else { 380 + None 381 + }; 382 + Ok(ServerDeviceFeature::new(&base_feature.description(), self.id, Some(self.base_id), base_feature.alt_protocol_index(), &output, base_feature.input())) 383 + } 270 384 } 271 385 272 386 #[derive(Serialize, Deserialize, Debug, Clone, Default, CopyGetters)]
+51 -30
crates/buttplug_server_device_config/src/device_config_file/mod.rs
··· 13 13 14 14 use base::BaseConfigFile; 15 15 16 - use crate::device_config_file::{protocol::ProtocolDefinition, user::{UserConfigDefinition, UserConfigFile, UserDeviceConfigPair}}; 16 + use crate::device_config_file::{ 17 + protocol::ProtocolDefinition, 18 + user::{UserConfigDefinition, UserConfigFile, UserDeviceConfigPair}, 19 + }; 17 20 18 - use super::{ 19 - BaseDeviceIdentifier, 20 - DeviceConfigurationManager, 21 - DeviceConfigurationManagerBuilder, 22 - }; 21 + use super::{BaseDeviceIdentifier, DeviceConfigurationManager, DeviceConfigurationManagerBuilder}; 23 22 use buttplug_core::{ 24 23 errors::{ButtplugDeviceError, ButtplugError}, 25 24 util::json::JSONValidator, 26 25 }; 27 26 use dashmap::DashMap; 28 27 use getset::CopyGetters; 29 - use serde::{Deserialize, Serialize, Serializer, ser::{self, SerializeSeq}}; 28 + use serde::{ 29 + Deserialize, 30 + Serialize, 31 + Serializer, 32 + ser::{self, SerializeSeq}, 33 + }; 30 34 use std::{collections::HashMap, fmt::Display, ops::RangeInclusive}; 31 35 32 36 pub static DEVICE_CONFIGURATION_JSON: &str = 33 37 include_str!("../../build-config/buttplug-device-config-v4.json"); 34 - static DEVICE_CONFIGURATION_JSON_SCHEMA: &str = include_str!( 35 - "../../device-config-v4/buttplug-device-config-schema-v4.json" 36 - ); 38 + static DEVICE_CONFIGURATION_JSON_SCHEMA: &str = 39 + include_str!("../../device-config-v4/buttplug-device-config-schema-v4.json"); 37 40 38 41 fn range_serialize<S>(range: &Option<RangeInclusive<u32>>, serializer: S) -> Result<S::Ok, S::Error> 39 42 where ··· 81 84 trait ConfigVersionGetter { 82 85 fn version(&self) -> ConfigVersion; 83 86 } 84 - 85 87 86 88 fn get_internal_config_version() -> ConfigVersion { 87 89 let config: BaseConfigFile = serde_json::from_str(DEVICE_CONFIGURATION_JSON) ··· 150 152 let mut default = None; 151 153 if let Some(features) = protocol_def.defaults() { 152 154 default = Some(features.clone()); 153 - dcm_builder.protocol_features(&BaseDeviceIdentifier::new_default(&protocol_name), &features.clone().into()); 155 + dcm_builder.base_device_definition( 156 + &BaseDeviceIdentifier::new_default(&protocol_name), 157 + &features.clone().into(), 158 + ); 154 159 } 155 160 156 161 for config in protocol_def.configurations() { 157 162 if let Some(idents) = config.identifier() { 158 163 for config_ident in idents { 159 - let ident = BaseDeviceIdentifier::new(&protocol_name, config_ident); 164 + let ident = BaseDeviceIdentifier::new_with_identifier(&protocol_name, config_ident); 160 165 if let Some(d) = &default { 161 - dcm_builder.protocol_features(&ident, &d.update_with_configuration(config.clone()).into()); 166 + dcm_builder 167 + .base_device_definition(&ident, &d.update_with_configuration(config.clone()).into()); 162 168 } else { 163 - dcm_builder.protocol_features(&ident, &config.clone().into()); 169 + dcm_builder.base_device_definition(&ident, &config.clone().into()); 164 170 } 165 171 } 166 172 } ··· 175 181 skip_version_check: bool, 176 182 dcm_builder: &mut DeviceConfigurationManagerBuilder, 177 183 ) -> Result<(), ButtplugDeviceError> { 184 + let base_dcm = dcm_builder.clone().finish().unwrap(); 185 + 178 186 info!("Loading user configuration from string."); 179 187 let user_config_file = 180 188 load_protocol_config_from_json::<UserConfigFile>(user_config_str, skip_version_check)?; ··· 194 202 dcm_builder.user_communication_specifier(&protocol_name, &specifiers); 195 203 } 196 204 197 - if let Some(features) = protocol_def.defaults() { 198 - dcm_builder.protocol_features(&BaseDeviceIdentifier::new_default(&protocol_name), features); 199 - } 205 + // Defaults aren't valid in user config files. All we can do is create new configurations with 206 + // valid identifiers. 200 207 201 208 for config in protocol_def.configurations() { 202 209 if let Some(idents) = config.identifier() { 203 210 for config_ident in idents { 204 - let ident = BaseDeviceIdentifier::new(&protocol_name, config_ident); 205 - dcm_builder.protocol_features(ident, config.clone()); 211 + let ident = BaseDeviceIdentifier::new_with_identifier(&protocol_name, config_ident); 212 + dcm_builder.base_device_definition(&ident, &config.clone().into()); 206 213 } 207 214 } 208 215 } 209 216 } 210 217 211 - for user_device_config_pair in user_config.user_device_configs().clone().unwrap_or_default() { 212 - dcm_builder.user_protocol_features( 213 - user_device_config_pair.identifier(), 214 - user_device_config_pair.config(), 215 - ); 218 + for user_device_config_pair in user_config 219 + .user_device_configs() 220 + .clone() 221 + .unwrap_or_default() 222 + { 223 + if let Some(base_config) = base_dcm 224 + .base_device_definitions() 225 + .get(&user_device_config_pair.identifier().into()) 226 + { 227 + if let Ok(user_config) = user_device_config_pair 228 + .config() 229 + .build_from_base_definition(base_config) 230 + { 231 + dcm_builder.user_device_definition(user_device_config_pair.identifier(), &user_config); 232 + } 233 + } else { 234 + error!( 235 + "Device identifier {:?} does not have a match base identifier that matches anything in the base config, removing from database.", 236 + user_device_config_pair.identifier() 237 + ); 238 + } 216 239 } 217 240 218 241 Ok(()) ··· 274 297 mod test { 275 298 use crate::device_config_file::load_main_config; 276 299 277 - use super::{load_protocol_config_from_json, DEVICE_CONFIGURATION_JSON, base::BaseConfigFile}; 300 + use super::{DEVICE_CONFIGURATION_JSON, base::BaseConfigFile, load_protocol_config_from_json}; 278 301 279 302 #[test] 280 303 fn test_config_file_parsing() { 281 - load_protocol_config_from_json::<BaseConfigFile>( 282 - &DEVICE_CONFIGURATION_JSON.to_owned(), 283 - true 284 - ).unwrap(); 304 + load_protocol_config_from_json::<BaseConfigFile>(&DEVICE_CONFIGURATION_JSON.to_owned(), true) 305 + .unwrap(); 285 306 } 286 307 287 308 #[test]
+35 -76
crates/buttplug_server_device_config/src/device_config_manager.rs
··· 2 2 use buttplug_core::errors::ButtplugDeviceError; 3 3 use dashmap::DashMap; 4 4 use getset::Getters; 5 + use uuid::Uuid; 5 6 use std::{ 6 7 collections::HashMap, 7 8 fmt::{self, Debug}, 8 9 }; 9 10 10 - use crate::{BaseDeviceIdentifier, ProtocolCommunicationSpecifier, ServerDeviceDefinition, UserDeviceIdentifier}; 11 + use crate::{BaseDeviceIdentifier, ButtplugDeviceConfigError, ProtocolCommunicationSpecifier, ServerDeviceDefinition, ServerDeviceDefinitionBuilder, UserDeviceIdentifier}; 11 12 12 13 #[derive(Default, Clone)] 13 14 pub struct DeviceConfigurationManagerBuilder { ··· 31 32 self 32 33 } 33 34 34 - pub fn protocol_features( 35 + pub fn base_device_definition( 35 36 &mut self, 36 37 identifier: &BaseDeviceIdentifier, 37 38 features: &ServerDeviceDefinition, ··· 55 56 self 56 57 } 57 58 58 - pub fn user_protocol_features( 59 + pub fn user_device_definition( 59 60 &mut self, 60 61 identifier: &UserDeviceIdentifier, 61 - features: &ServerDeviceDefinition, 62 - ) -> &mut Self { 63 - if let Some((_, base_definition)) = self 62 + device_definition: &ServerDeviceDefinition, 63 + ) -> Result<&mut Self, ButtplugDeviceConfigError> { 64 + if self 64 65 .base_device_definitions 65 66 .iter() 66 - .find(|(_, x)| x.id() == features.base_id()) 67 + .find(|(_, x)| x.id() == device_definition.base_id().unwrap_or_default()) 68 + .is_some() 67 69 { 68 70 self.user_device_definitions.insert( 69 71 identifier.clone(), 70 - ServerDeviceDefinition::new(base_definition, features), 72 + device_definition.clone() 71 73 ); 74 + Ok(self) 72 75 } else { 73 76 error!( 74 - "Cannot find protocol with base id {} for user id {}", 75 - features.base_id(), 76 - features.id() 77 - ) 77 + "Cannot find protocol with base id {:?} for user id {}", 78 + device_definition.base_id(), 79 + device_definition.id() 80 + ); 81 + Err(ButtplugDeviceConfigError::BaseIdNotFound(device_definition.id())) 78 82 } 79 - self 83 + 80 84 } 81 85 82 86 pub fn finish(&mut self) -> Result<DeviceConfigurationManager, ButtplugDeviceError> { ··· 85 89 86 90 // Add all the defaults first, they won't have parent attributes. 87 91 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 92 attribute_tree_map.insert(ident.clone(), attr.clone()); 97 93 } 98 94 99 95 let user_attribute_tree_map = DashMap::new(); 100 96 // Finally, add in user configurations, which will have an address. 101 97 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 98 user_attribute_tree_map.insert(kv.key().clone(), kv.value().clone()); 110 99 } 111 100 ··· 131 120 /// information about what commands can be sent to the device (Vibrate, Rotate, etc...), and the 132 121 /// parameters for those commands (number of power levels, stroke distances, etc...). 133 122 #[derive(Getters)] 134 - #[getset(get = "pub")] 123 + #[getset(get = "pub(crate)")] 135 124 pub struct DeviceConfigurationManager { 136 125 /// Communication specifiers from the base device config, mapped from protocol name to vector of 137 126 /// specifiers. Should not change/update during a session. ··· 192 181 } 193 182 } 194 183 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 184 pub fn remove_user_device_definition(&self, identifier: &UserDeviceIdentifier) { 220 185 self.user_device_definitions.remove(identifier); 221 186 } ··· 225 190 if self 226 191 .user_device_definitions 227 192 .iter() 228 - .any(|kv| kv.key().address() == address && kv.value().user_config().deny()) 193 + .any(|kv| kv.key().address() == address && kv.value().deny()) 229 194 { 230 195 // If device is outright denied, deny 231 196 info!( ··· 236 201 } else if self 237 202 .user_device_definitions 238 203 .iter() 239 - .any(|kv| kv.value().user_config().allow()) 204 + .any(|kv| kv.value().allow()) 240 205 && !self 241 206 .user_device_definitions 242 207 .iter() 243 - .any(|kv| kv.key().address() == address && kv.value().user_config().allow()) 208 + .any(|kv| kv.key().address() == address && kv.value().allow()) 244 209 { 245 210 // If device is not on allow list and allow list isn't empty, deny 246 211 info!( ··· 256 221 fn device_index(&self, identifier: &UserDeviceIdentifier) -> u32 { 257 222 // See if we have a reserved or reusable device index here. 258 223 if let Some(config) = self.user_device_definitions.get(identifier) { 259 - let index = config.user_config().index(); 224 + let index = config.index(); 260 225 debug!("Found index {index} for device {identifier:?}"); 261 226 return index; 262 227 } ··· 264 229 let current_indexes: Vec<u32> = self 265 230 .user_device_definitions 266 231 .iter() 267 - .map(|x| x.user_config().index()) 232 + .map(|x| x.index()) 268 233 .collect(); 269 234 270 235 // Someone is gonna make a max device index in their config file just to fuck with me, therefore ··· 280 245 index 281 246 } 282 247 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) { 248 + pub fn device_definition(&self, identifier: &UserDeviceIdentifier) -> Option<ServerDeviceDefinition> { 249 + let features = if let Some(definition) = self.user_device_definitions.get(identifier) { 294 250 debug!("User device config found for {:?}", identifier); 295 - attrs.clone() 296 - } else if let Some(attrs) = self.base_device_definitions.get(&BaseDeviceIdentifier::new( 251 + definition.clone() 252 + } else if let Some(definition) = self.base_device_definitions.get(&BaseDeviceIdentifier::new( 297 253 identifier.protocol(), 298 254 identifier.identifier(), 299 255 )) { 300 256 debug!( 301 - "Protocol + Identifier device config found for {:?}", 257 + "Protocol + Identifier device config found for {:?}, creating new user device from configuration", 302 258 identifier 303 259 ); 304 - DeviceDefinition::new_from_base_definition(attrs, self.device_index(identifier)) 305 - } else if let Some(attrs) = self 260 + let mut builder = ServerDeviceDefinitionBuilder::from_base(definition, Uuid::new_v4()); 261 + builder.index(self.device_index(identifier)).finish() 262 + } else if let Some(definition) = self 306 263 .base_device_definitions 307 264 .get(&BaseDeviceIdentifier::new(identifier.protocol(), &None)) 308 265 { 309 - debug!("Protocol device config found for {:?}", identifier); 310 - DeviceDefinition::new_from_base_definition(attrs, self.device_index(identifier)) 266 + debug!("Protocol device config found for {:?}, creating new user device from protocol defaults", identifier); 267 + let mut builder = ServerDeviceDefinitionBuilder::from_base(definition, Uuid::new_v4()); 268 + builder.index(self.device_index(identifier)).finish() 311 269 } else { 312 270 return None; 313 271 }; ··· 325 283 326 284 Some(features) 327 285 } 286 + 328 287 }
+17 -4
crates/buttplug_server_device_config/src/device_definitions.rs
··· 51 51 } 52 52 } 53 53 54 - pub fn base_id(&mut self, id: &Uuid) -> &mut Self { 55 - self.def.base_id = Some(id.clone()); 54 + pub fn from_base(value: &ServerDeviceDefinition, id: Uuid) -> Self { 55 + let mut value = value.clone(); 56 + value.base_id = Some(value.id); 57 + value.id = id; 58 + value.features = vec!(); 59 + ServerDeviceDefinitionBuilder { def: value } 60 + } 61 + 62 + pub fn id(&mut self, id: Uuid) -> &mut Self { 63 + self.def.id = id; 64 + self 65 + } 66 + 67 + pub fn base_id(&mut self, id: Uuid) -> &mut Self { 68 + self.def.base_id = Some(id); 56 69 self 57 70 } 58 71 ··· 91 104 self 92 105 } 93 106 94 - pub fn finish(self) -> ServerDeviceDefinition { 95 - self.def 107 + pub fn finish(&self) -> ServerDeviceDefinition { 108 + self.def.clone() 96 109 } 97 110 }
+26 -11
crates/buttplug_server_device_config/src/device_feature.rs
··· 57 57 seq.end() 58 58 } 59 59 60 - #[derive(Debug, Clone)] 60 + #[derive(Debug, Clone, Getters)] 61 + #[getset(get = "pub")] 61 62 pub struct RangeWithLimit<T: PartialOrd + Clone> { 62 63 base: RangeInclusive<T>, 63 64 user: Option<RangeInclusive<T>>, ··· 80 81 pub fn try_new( 81 82 base: &RangeInclusive<T>, 82 83 user: &Option<RangeInclusive<T>>, 83 - ) -> Result<Self, ButtplugDeviceConfigError<T>> { 84 + ) -> Result<Self, ButtplugDeviceConfigError> { 84 85 if let Some(user) = user { 85 86 if user.is_empty() { 86 - Err(ButtplugDeviceConfigError::InvalidUserRange( 87 - (*user).clone(), 88 - (*base).clone(), 89 - )) 87 + Err(ButtplugDeviceConfigError::InvalidUserRange) 90 88 } else { 91 89 if *user.start() < *base.start() 92 90 || *user.end() > *base.end() 93 91 || *user.start() > *base.end() 94 92 || *user.end() < *base.start() 95 93 { 96 - Err(ButtplugDeviceConfigError::InvalidUserRange( 97 - (*user).clone(), 98 - (*base).clone(), 99 - )) 94 + Err(ButtplugDeviceConfigError::InvalidUserRange) 100 95 } else { 101 96 Ok(Self { 102 97 base: (*base).clone(), ··· 135 130 } 136 131 137 132 #[derive(Debug, Clone, Getters, CopyGetters)] 133 + pub struct ServerDeviceFeatureOutputPositionProperties { 134 + #[getset(get = "pub")] 135 + position: RangeWithLimit<u32>, 136 + #[getset(get_copy = "pub")] 137 + disabled: bool, 138 + #[getset(get_copy = "pub")] 139 + reverse_position: bool, 140 + } 141 + 142 + impl ServerDeviceFeatureOutputPositionProperties { 143 + pub fn new(position: &RangeWithLimit<u32>, disabled: bool, reverse_position: bool) -> Self { 144 + Self { 145 + position: position.clone(), 146 + disabled, 147 + reverse_position 148 + } 149 + } 150 + } 151 + 152 + #[derive(Debug, Clone, Getters, CopyGetters)] 138 153 pub struct ServerDeviceFeatureOutputPositionWithDurationProperties { 139 154 #[getset(get = "pub")] 140 155 position: RangeWithLimit<u32>, ··· 167 182 constrict: Option<ServerDeviceFeatureOutputValueProperties>, 168 183 heater: Option<ServerDeviceFeatureOutputValueProperties>, 169 184 led: Option<ServerDeviceFeatureOutputValueProperties>, 170 - position: Option<ServerDeviceFeatureOutputValueProperties>, 185 + position: Option<ServerDeviceFeatureOutputPositionProperties>, 171 186 position_with_duration: Option<ServerDeviceFeatureOutputPositionWithDurationProperties>, 172 187 spray: Option<ServerDeviceFeatureOutputValueProperties>, 173 188 }
+7 -6
crates/buttplug_server_device_config/src/identifiers.rs
··· 45 45 46 46 impl BaseDeviceIdentifier { 47 47 pub fn new_default(protocol: &str) -> Self { 48 - Self { 49 - protocol: protocol.to_owned(), 50 - identifier: None, 51 - } 48 + Self::new(protocol, &None) 49 + } 50 + 51 + pub fn new_with_identifier(protocol: &str, attributes_identifier: &str) -> Self { 52 + Self::new(protocol, &Some(attributes_identifier.to_owned())) 52 53 } 53 54 54 - pub fn new(protocol: &str, attributes_identifier: &str) -> Self { 55 + pub fn new(protocol: &str, attributes_identifier: &Option<String>) -> Self { 55 56 Self { 56 57 protocol: protocol.to_owned(), 57 - identifier: Some(attributes_identifier.to_owned()), 58 + identifier: attributes_identifier.clone(), 58 59 } 59 60 } 60 61 }
+10 -5
crates/buttplug_server_device_config/src/lib.rs
··· 141 141 extern crate log; 142 142 143 143 mod device_config_file; 144 - pub use device_config_file::{load_protocol_configs, save_user_config}; 144 + pub use device_config_file::{load_protocol_configs}; //, save_user_config}; 145 145 mod device_config_manager; 146 146 pub use device_config_manager::*; 147 147 mod specifier; ··· 154 154 pub use device_feature::*; 155 155 mod endpoint; 156 156 pub use endpoint::*; 157 + use uuid::Uuid; 157 158 158 159 159 - use std::ops::RangeInclusive; 160 160 use thiserror::Error; 161 161 162 162 #[derive(Error, Debug)] 163 - pub enum ButtplugDeviceConfigError<T> { 163 + pub enum ButtplugDeviceConfigError { 164 164 /// Conversion to client type not possible with requested property type 165 165 #[error("Conversion of {0} to client type not possible with requested property type")] 166 166 InvalidOutputTypeConversion(String), 167 167 /// User set range exceeds bounds of possible configuration range 168 - #[error("User set range {0} exceeds bounds of possible configuration range {1}")] 169 - InvalidUserRange(RangeInclusive<T>, RangeInclusive<T>), 168 + #[error("User set range exceeds bounds of possible configuration range")] 169 + InvalidUserRange, 170 170 /// Base range required 171 171 #[error("Base range required for all feature outputs")] 172 172 BaseRangeRequired, 173 + /// Base ID not found, cannot match user device/feature to a base device/feature 174 + #[error("Device definition with base id {0} not found")] 175 + BaseIdNotFound(Uuid), 176 + #[error("Feature vectors between base and user device definitions do not match")] 177 + UserFeatureMismatch 173 178 }