Buttplug sex toy control library

chore: Swap out Inflate w/ Spray

Fixes #749, #752

+53 -50
+7 -7
buttplug-schema/schema/buttplug-schema.json
··· 377 "Command": { 378 "type": "object", 379 "patternProperties": { 380 - "^(Vibrate|Rotate|Oscillate|Constrict|Inflate|Position|Heater|Led)$": { 381 "type": "object", 382 "properties": { 383 "Value": { ··· 584 "description": "Name of the client software.", 585 "type": "string" 586 }, 587 - "ApiVersionMajor": { 588 "description": "Message template version of the server software.", 589 "type": "integer", 590 "minimum": 0 591 }, 592 - "ApiVersionMinor": { 593 "description": "Message template version of the server software.", 594 "type": "integer", 595 "minimum": 0 ··· 599 "required": [ 600 "Id", 601 "ClientName", 602 - "ApiVersionMajor", 603 - "ApiVersionMinor" 604 ] 605 }, 606 "ServerInfo": { ··· 612 "description": "Name of the server. Can be 0-length.", 613 "type": "string" 614 }, 615 - "ApiVersionMajor": { 616 "description": "Message template version of the server software.", 617 "type": "integer", 618 "minimum": 0 619 }, 620 - "ApiVersionMinor": { 621 "description": "Message template version of the server software.", 622 "type": "integer", 623 "minimum": 0
··· 377 "Command": { 378 "type": "object", 379 "patternProperties": { 380 + "^(Vibrate|Rotate|Oscillate|Constrict|Spray|Position|Heater|Led)$": { 381 "type": "object", 382 "properties": { 383 "Value": { ··· 584 "description": "Name of the client software.", 585 "type": "string" 586 }, 587 + "ProtocolVersionMajor": { 588 "description": "Message template version of the server software.", 589 "type": "integer", 590 "minimum": 0 591 }, 592 + "ProtocolVersionMinor": { 593 "description": "Message template version of the server software.", 594 "type": "integer", 595 "minimum": 0 ··· 599 "required": [ 600 "Id", 601 "ClientName", 602 + "ProtocolVersionMajor", 603 + "ProtocolVersionMinor" 604 ] 605 }, 606 "ServerInfo": { ··· 612 "description": "Name of the server. Can be 0-length.", 613 "type": "string" 614 }, 615 + "ProtocolVersionMajor": { 616 "description": "Message template version of the server software.", 617 "type": "integer", 618 "minimum": 0 619 }, 620 + "ProtocolVersionMinor": { 621 "description": "Message template version of the server software.", 622 "type": "integer", 623 "minimum": 0
+2 -2
crates/buttplug_client/src/client_device_feature.rs
··· 143 self.check_and_set_actuator(OutputCommand::Rotate(OutputValue::new(level))) 144 } 145 146 - pub fn inflate(&self, level: u32) -> ButtplugClientResultFuture { 147 - self.check_and_set_actuator(OutputCommand::Inflate(OutputValue::new(level))) 148 } 149 150 pub fn constrict(&self, level: u32) -> ButtplugClientResultFuture {
··· 143 self.check_and_set_actuator(OutputCommand::Rotate(OutputValue::new(level))) 144 } 145 146 + pub fn spray(&self, level: u32) -> ButtplugClientResultFuture { 147 + self.check_and_set_actuator(OutputCommand::Spray(OutputValue::new(level))) 148 } 149 150 pub fn constrict(&self, level: u32) -> ButtplugClientResultFuture {
+7 -4
crates/buttplug_core/src/message/device_feature.rs
··· 24 Rotate, 25 Oscillate, 26 Constrict, 27 - Inflate, 28 Heater, 29 Led, 30 // For instances where we specify a position to move to ASAP. Usually servos, probably for the ··· 58 RotateWithDirection, 59 Oscillate, 60 Constrict, 61 - Inflate, 62 Heater, 63 Led, 64 // For instances where we specify a position to move to ASAP. Usually servos, probably for the 65 // OSR-2/SR-6. 66 Position, 67 PositionWithDuration, 68 } 69 70 impl TryFrom<FeatureType> for OutputType { ··· 80 FeatureType::PositionWithDuration => Ok(OutputType::PositionWithDuration), 81 FeatureType::Oscillate => Ok(OutputType::Oscillate), 82 FeatureType::Constrict => Ok(OutputType::Constrict), 83 - FeatureType::Inflate => Ok(OutputType::Inflate), 84 FeatureType::Position => Ok(OutputType::Position), 85 _ => Err(format!( 86 "Feature type {value} not valid for OutputType conversion" ··· 129 OutputType::PositionWithDuration => FeatureType::PositionWithDuration, 130 OutputType::Oscillate => FeatureType::Oscillate, 131 OutputType::Constrict => FeatureType::Constrict, 132 - OutputType::Inflate => FeatureType::Inflate, 133 OutputType::Position => FeatureType::Position, 134 } 135 }
··· 24 Rotate, 25 Oscillate, 26 Constrict, 27 + Spray, 28 Heater, 29 Led, 30 // For instances where we specify a position to move to ASAP. Usually servos, probably for the ··· 58 RotateWithDirection, 59 Oscillate, 60 Constrict, 61 Heater, 62 Led, 63 // For instances where we specify a position to move to ASAP. Usually servos, probably for the 64 // OSR-2/SR-6. 65 Position, 66 PositionWithDuration, 67 + // Lube shooters 68 + Spray, 69 + // Things we might add in the future 70 + // Inflate, 71 } 72 73 impl TryFrom<FeatureType> for OutputType { ··· 83 FeatureType::PositionWithDuration => Ok(OutputType::PositionWithDuration), 84 FeatureType::Oscillate => Ok(OutputType::Oscillate), 85 FeatureType::Constrict => Ok(OutputType::Constrict), 86 + FeatureType::Spray => Ok(OutputType::Spray), 87 FeatureType::Position => Ok(OutputType::Position), 88 _ => Err(format!( 89 "Feature type {value} not valid for OutputType conversion" ··· 132 OutputType::PositionWithDuration => FeatureType::PositionWithDuration, 133 OutputType::Oscillate => FeatureType::Oscillate, 134 OutputType::Constrict => FeatureType::Constrict, 135 + OutputType::Spray => FeatureType::Spray, 136 OutputType::Position => FeatureType::Position, 137 } 138 }
+5 -5
crates/buttplug_core/src/message/v4/output_cmd.rs
··· 71 RotateWithDirection(OutputRotateWithDirection), 72 Oscillate(OutputValue), 73 Constrict(OutputValue), 74 - Inflate(OutputValue), 75 Heater(OutputValue), 76 Led(OutputValue), 77 // For instances where we specify a position to move to ASAP. Usually servos, probably for the ··· 84 pub fn value(&self) -> u32 { 85 match self { 86 OutputCommand::Constrict(x) 87 - | OutputCommand::Inflate(x) 88 | OutputCommand::Heater(x) 89 | OutputCommand::Led(x) 90 | OutputCommand::Oscillate(x) ··· 99 pub fn set_value(&mut self, value: u32) { 100 match self { 101 OutputCommand::Constrict(x) 102 - | OutputCommand::Inflate(x) 103 | OutputCommand::Heater(x) 104 | OutputCommand::Led(x) 105 | OutputCommand::Oscillate(x) ··· 118 Self::RotateWithDirection(_) => OutputType::RotateWithDirection, 119 Self::Oscillate(_) => OutputType::Oscillate, 120 Self::Constrict(_) => OutputType::Constrict, 121 - Self::Inflate(_) => OutputType::Inflate, 122 Self::Led(_) => OutputType::Led, 123 Self::Position(_) => OutputType::Position, 124 Self::PositionWithDuration(_) => OutputType::PositionWithDuration, ··· 130 match output_type { 131 OutputType::Constrict => Ok(Self::Constrict(OutputValue::new(value))), 132 OutputType::Heater => Ok(Self::Heater(OutputValue::new(value))), 133 - OutputType::Inflate => Ok(Self::Inflate(OutputValue::new(value))), 134 OutputType::Led => Ok(Self::Led(OutputValue::new(value))), 135 OutputType::Oscillate => Ok(Self::Oscillate(OutputValue::new(value))), 136 OutputType::Position => Ok(Self::Position(OutputValue::new(value))),
··· 71 RotateWithDirection(OutputRotateWithDirection), 72 Oscillate(OutputValue), 73 Constrict(OutputValue), 74 + Spray(OutputValue), 75 Heater(OutputValue), 76 Led(OutputValue), 77 // For instances where we specify a position to move to ASAP. Usually servos, probably for the ··· 84 pub fn value(&self) -> u32 { 85 match self { 86 OutputCommand::Constrict(x) 87 + | OutputCommand::Spray(x) 88 | OutputCommand::Heater(x) 89 | OutputCommand::Led(x) 90 | OutputCommand::Oscillate(x) ··· 99 pub fn set_value(&mut self, value: u32) { 100 match self { 101 OutputCommand::Constrict(x) 102 + | OutputCommand::Spray(x) 103 | OutputCommand::Heater(x) 104 | OutputCommand::Led(x) 105 | OutputCommand::Oscillate(x) ··· 118 Self::RotateWithDirection(_) => OutputType::RotateWithDirection, 119 Self::Oscillate(_) => OutputType::Oscillate, 120 Self::Constrict(_) => OutputType::Constrict, 121 + Self::Spray(_) => OutputType::Spray, 122 Self::Led(_) => OutputType::Led, 123 Self::Position(_) => OutputType::Position, 124 Self::PositionWithDuration(_) => OutputType::PositionWithDuration, ··· 130 match output_type { 131 OutputType::Constrict => Ok(Self::Constrict(OutputValue::new(value))), 132 OutputType::Heater => Ok(Self::Heater(OutputValue::new(value))), 133 + OutputType::Spray => Ok(Self::Spray(OutputValue::new(value))), 134 OutputType::Led => Ok(Self::Led(OutputValue::new(value))), 135 OutputType::Oscillate => Ok(Self::Oscillate(OutputValue::new(value))), 136 OutputType::Position => Ok(Self::Position(OutputValue::new(value))),
+8 -8
crates/buttplug_core/src/message/v4/request_server_info.rs
··· 36 #[serde(rename = "ClientName")] 37 #[getset(get = "pub")] 38 client_name: String, 39 - #[serde(rename = "ApiVersionMajor")] 40 #[getset(get_copy = "pub")] 41 - api_version_major: ButtplugMessageSpecVersion, 42 - #[serde(rename = "ApiVersionMinor")] 43 #[getset(get_copy = "pub")] 44 - api_version_minor: u32, 45 } 46 47 impl RequestServerInfoV4 { 48 pub fn new( 49 client_name: &str, 50 - api_version_major: ButtplugMessageSpecVersion, 51 - api_version_minor: u32, 52 ) -> Self { 53 Self { 54 id: 1, 55 client_name: client_name.to_string(), 56 - api_version_major, 57 - api_version_minor, 58 } 59 } 60 }
··· 36 #[serde(rename = "ClientName")] 37 #[getset(get = "pub")] 38 client_name: String, 39 + #[serde(rename = "ProtocolVersionMajor")] 40 #[getset(get_copy = "pub")] 41 + protocol_version_major: ButtplugMessageSpecVersion, 42 + #[serde(rename = "ProtocolVersionMinor")] 43 #[getset(get_copy = "pub")] 44 + protocol_version_minor: u32, 45 } 46 47 impl RequestServerInfoV4 { 48 pub fn new( 49 client_name: &str, 50 + protocol_version_major: ButtplugMessageSpecVersion, 51 + protocol_version_minor: u32, 52 ) -> Self { 53 Self { 54 id: 1, 55 client_name: client_name.to_string(), 56 + protocol_version_major, 57 + protocol_version_minor, 58 } 59 } 60 }
+8 -8
crates/buttplug_core/src/message/v4/server_info.rs
··· 30 pub struct ServerInfoV4 { 31 #[serde(rename = "Id")] 32 id: u32, 33 - #[serde(rename = "ApiVersionMajor")] 34 #[getset(get_copy = "pub")] 35 - api_version_major: ButtplugMessageSpecVersion, 36 - #[serde(rename = "ApiVersionMinor")] 37 #[getset(get_copy = "pub")] 38 - api_version_minor: u32, 39 #[serde(rename = "MaxPingTime")] 40 #[getset(get_copy = "pub")] 41 max_ping_time: u32, ··· 47 impl ServerInfoV4 { 48 pub fn new( 49 server_name: &str, 50 - api_version_major: ButtplugMessageSpecVersion, 51 - api_version_minor: u32, 52 max_ping_time: u32, 53 ) -> Self { 54 Self { 55 id: 1, 56 - api_version_major, 57 - api_version_minor, 58 max_ping_time, 59 server_name: server_name.to_string(), 60 }
··· 30 pub struct ServerInfoV4 { 31 #[serde(rename = "Id")] 32 id: u32, 33 + #[serde(rename = "ProtocolVersionMajor")] 34 #[getset(get_copy = "pub")] 35 + protocol_version_major: ButtplugMessageSpecVersion, 36 + #[serde(rename = "ProtocolVersionMinor")] 37 #[getset(get_copy = "pub")] 38 + protocol_version_minor: u32, 39 #[serde(rename = "MaxPingTime")] 40 #[getset(get_copy = "pub")] 41 max_ping_time: u32, ··· 47 impl ServerInfoV4 { 48 pub fn new( 49 server_name: &str, 50 + protocol_version_major: ButtplugMessageSpecVersion, 51 + protocol_version_minor: u32, 52 max_ping_time: u32, 53 ) -> Self { 54 Self { 55 id: 1, 56 + protocol_version_major, 57 + protocol_version_minor, 58 max_ping_time, 59 server_name: server_name.to_string(), 60 }
+4 -4
crates/buttplug_server/src/device/protocol.rs
··· 226 OutputCommand::Constrict(x) => { 227 self.handle_output_constrict_cmd(cmd.feature_index(), cmd.feature_id(), x.value()) 228 } 229 - OutputCommand::Inflate(x) => { 230 - self.handle_output_inflate_cmd(cmd.feature_index(), cmd.feature_id(), x.value()) 231 } 232 OutputCommand::Oscillate(x) => { 233 self.handle_output_oscillate_cmd(cmd.feature_index(), cmd.feature_id(), x.value()) ··· 289 self.command_unimplemented("OutputCmd (Oscillate Actuator)") 290 } 291 292 - fn handle_output_inflate_cmd( 293 &self, 294 _feature_index: u32, 295 _feature_id: Uuid, 296 _level: u32, 297 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 298 - self.command_unimplemented("OutputCmd (Inflate Actuator)") 299 } 300 301 fn handle_output_constrict_cmd(
··· 226 OutputCommand::Constrict(x) => { 227 self.handle_output_constrict_cmd(cmd.feature_index(), cmd.feature_id(), x.value()) 228 } 229 + OutputCommand::Spray(x) => { 230 + self.handle_output_spray_cmd(cmd.feature_index(), cmd.feature_id(), x.value()) 231 } 232 OutputCommand::Oscillate(x) => { 233 self.handle_output_oscillate_cmd(cmd.feature_index(), cmd.feature_id(), x.value()) ··· 289 self.command_unimplemented("OutputCmd (Oscillate Actuator)") 290 } 291 292 + fn handle_output_spray_cmd( 293 &self, 294 _feature_index: u32, 295 _feature_id: Uuid, 296 _level: u32, 297 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 298 + self.command_unimplemented("OutputCmd (Spray Actuator)") 299 } 300 301 fn handle_output_constrict_cmd(
+2 -2
crates/buttplug_server/src/device/server_device.rs
··· 410 stop_cmd(message::OutputCommand::Heater(OutputValue::new(0))); 411 break; 412 } 413 - OutputType::Inflate => { 414 - stop_cmd(message::OutputCommand::Inflate(OutputValue::new(0))); 415 break; 416 } 417 OutputType::Led => {
··· 410 stop_cmd(message::OutputCommand::Heater(OutputValue::new(0))); 411 break; 412 } 413 + OutputType::Spray => { 414 + stop_cmd(message::OutputCommand::Spray(OutputValue::new(0))); 415 break; 416 } 417 OutputType::Led => {
+1 -1
crates/buttplug_server/src/message/v2/server_info.rs
··· 70 Self { 71 id: value.id(), 72 server_name: value.server_name().clone(), 73 - message_version: value.api_version_major(), 74 max_ping_time: value.max_ping_time(), 75 } 76 }
··· 70 Self { 71 id: value.id(), 72 server_name: value.server_name().clone(), 73 + message_version: value.protocol_version_major(), 74 max_ping_time: value.max_ping_time(), 75 } 76 }
+6 -6
crates/buttplug_server/src/server.rs
··· 357 info!( 358 "Performing server handshake check with client {} at message version {}.{}", 359 msg.client_name(), 360 - msg.api_version_major(), 361 - msg.api_version_minor() 362 ); 363 364 - if BUTTPLUG_CURRENT_API_MAJOR_VERSION < msg.api_version_major() { 365 return ButtplugHandshakeError::MessageSpecVersionMismatch( 366 BUTTPLUG_CURRENT_API_MAJOR_VERSION, 367 - msg.api_version_major(), 368 ) 369 .into(); 370 } ··· 374 375 // Due to programming/spec errors in prior versions of the protocol, anything before v4 expected 376 // that it would be back a matching api version of the server. The correct response is to send back whatever the 377 - let output_version = if (msg.api_version_major() as u32) < 4 { 378 - msg.api_version_major() 379 } else { 380 BUTTPLUG_CURRENT_API_MAJOR_VERSION 381 };
··· 357 info!( 358 "Performing server handshake check with client {} at message version {}.{}", 359 msg.client_name(), 360 + msg.protocol_version_major(), 361 + msg.protocol_version_minor() 362 ); 363 364 + if BUTTPLUG_CURRENT_API_MAJOR_VERSION < msg.protocol_version_major() { 365 return ButtplugHandshakeError::MessageSpecVersionMismatch( 366 BUTTPLUG_CURRENT_API_MAJOR_VERSION, 367 + msg.protocol_version_major(), 368 ) 369 .into(); 370 } ··· 374 375 // Due to programming/spec errors in prior versions of the protocol, anything before v4 expected 376 // that it would be back a matching api version of the server. The correct response is to send back whatever the 377 + let output_version = if (msg.protocol_version_major() as u32) < 4 { 378 + msg.protocol_version_major() 379 } else { 380 BUTTPLUG_CURRENT_API_MAJOR_VERSION 381 };
+3 -3
crates/buttplug_server_device_config/device-config-v4/buttplug-device-config-schema-v4.json
··· 185 }, 186 "feature-type": { 187 "type": "string", 188 - "pattern": "^(Vibrate|Rotate|Oscillate|Constrict|Inflate|Position|Battery|RSSI|Pressure|RotateWithDirection|PositionWithDuration|Heater|Led)$" 189 }, 190 "output": { 191 "type": "object", 192 "patternProperties": { 193 - "^(Vibrate|Rotate|Oscillate|Constrict|Inflate|Position|RotateWithDirection|PositionWithDuration|Heater|Led)$": { 194 "type": "object", 195 "properties": { 196 "step-range": { ··· 269 "output": { 270 "type": "object", 271 "patternProperties": { 272 - "^(Vibrate|Rotate|Oscillate|Constrict|Inflate|Position|RotateWithDirection|PositionWithDuration|Heater|Led)$": { 273 "type": "object", 274 "properties": { 275 "step-limit": {
··· 185 }, 186 "feature-type": { 187 "type": "string", 188 + "pattern": "^(Vibrate|Rotate|Oscillate|Constrict|Spray|Position|Battery|RSSI|Pressure|RotateWithDirection|PositionWithDuration|Heater|Led)$" 189 }, 190 "output": { 191 "type": "object", 192 "patternProperties": { 193 + "^(Vibrate|Rotate|Oscillate|Constrict|Spray|Position|RotateWithDirection|PositionWithDuration|Heater|Led)$": { 194 "type": "object", 195 "properties": { 196 "step-range": { ··· 269 "output": { 270 "type": "object", 271 "patternProperties": { 272 + "^(Vibrate|Rotate|Oscillate|Constrict|Spray|Position|RotateWithDirection|PositionWithDuration|Heater|Led)$": { 273 "type": "object", 274 "properties": { 275 "step-limit": {