Buttplug sex toy control library
at dev 8.7 kB view raw
1// Buttplug Rust Source Code File - See https://buttplug.io for more info. 2// 3// Copyright 2016-2024 Nonpolynomial Labs LLC. All rights reserved. 4// 5// Licensed under the BSD 3-Clause license. See LICENSE file in the project root 6// for full license information. 7 8//! Buttplug Message Spec Conversion 9//! 10//! This module contains code to convert any message from an older spec version up to the current 11//! message spec, and then convert any response from the current message spec back down the sending 12//! spec. This is handled within the server, as the server is the only portion of Buttplug that 13//! needs to handle up/downgrading (the client should never have to care and should only ever talk 14//! one version of the spec, preferably the latest). Having this done within the server also allows 15//! us to access required state for converting between messages that requires knowledge of ephemeral 16//! device structures (i.e. converting from v4 device features to <= v3 message attributes for 17//! messages like DeviceAdded). 18 19use buttplug_core::{ 20 errors::{ButtplugError, ButtplugMessageError}, 21 message::{ 22 ButtplugDeviceMessage, 23 ButtplugMessage, 24 ButtplugMessageSpecVersion, 25 ButtplugServerMessageV4, 26 DeviceListV4, 27 DeviceMessageInfoV4, 28 DeviceRemovedV0, 29 InputTypeData, 30 }, 31}; 32 33use dashmap::DashSet; 34 35use crate::message::{DeviceAddedV0, DeviceAddedV1, DeviceAddedV2, DeviceAddedV3}; 36 37use super::message::{ 38 BatteryLevelReadingV2, 39 ButtplugClientMessageV2, 40 ButtplugClientMessageV3, 41 ButtplugClientMessageVariant, 42 ButtplugServerMessageV0, 43 ButtplugServerMessageV1, 44 ButtplugServerMessageV2, 45 ButtplugServerMessageV3, 46 ButtplugServerMessageVariant, 47 SensorReadingV3, 48}; 49 50pub struct ButtplugServerDeviceEventMessageConverter { 51 device_indexes: DashSet<u32>, 52} 53 54impl ButtplugServerDeviceEventMessageConverter { 55 pub fn new(indexes: Vec<u32>) -> Self { 56 let device_indexes = DashSet::new(); 57 indexes.iter().for_each(|x| { 58 device_indexes.insert(*x); 59 }); 60 Self { device_indexes } 61 } 62 63 // Due to the way we generate device events, we expect every new DeviceList to only have one 64 // change currently. 65 pub fn convert_device_list( 66 &self, 67 version: &ButtplugMessageSpecVersion, 68 list: &DeviceListV4, 69 ) -> ButtplugServerMessageVariant { 70 let new_indexes: Vec<u32> = list.devices().iter().map(|x| *x.0).collect(); 71 if new_indexes.len() > self.device_indexes.len() { 72 // Device Added 73 let connected_devices: Vec<&DeviceMessageInfoV4> = list 74 .devices() 75 .values() 76 .filter(|x| !self.device_indexes.contains(&x.device_index())) 77 .collect(); 78 self 79 .device_indexes 80 .insert(connected_devices[0].device_index()); 81 if *version == ButtplugMessageSpecVersion::Version4 { 82 return ButtplugServerMessageVariant::V4(list.clone().into()); 83 } 84 let da3 = DeviceAddedV3::from(connected_devices[0].clone()); 85 if *version == ButtplugMessageSpecVersion::Version3 { 86 return ButtplugServerMessageVariant::V3(da3.into()); 87 } 88 let da2 = DeviceAddedV2::from(da3); 89 if *version == ButtplugMessageSpecVersion::Version2 { 90 return ButtplugServerMessageVariant::V2(da2.into()); 91 } 92 let da1 = DeviceAddedV1::from(da2); 93 if *version == ButtplugMessageSpecVersion::Version1 { 94 return ButtplugServerMessageVariant::V1(da1.into()); 95 } 96 let da0 = DeviceAddedV0::from(da1); 97 ButtplugServerMessageVariant::V0(ButtplugServerMessageV0::DeviceAdded(da0)) 98 } else { 99 // Device Removed 100 let disconnected_indexes: Vec<u32> = self 101 .device_indexes 102 .iter() 103 .filter(|x| !new_indexes.contains(x)) 104 .map(|x| *x) 105 .collect(); 106 self.device_indexes.remove(&disconnected_indexes[0]); 107 match version { 108 ButtplugMessageSpecVersion::Version0 => ButtplugServerMessageVariant::V0( 109 ButtplugServerMessageV0::DeviceRemoved(DeviceRemovedV0::new(disconnected_indexes[0])), 110 ), 111 ButtplugMessageSpecVersion::Version1 => { 112 ButtplugServerMessageVariant::V1(DeviceRemovedV0::new(disconnected_indexes[0]).into()) 113 } 114 ButtplugMessageSpecVersion::Version2 => { 115 ButtplugServerMessageVariant::V2(DeviceRemovedV0::new(disconnected_indexes[0]).into()) 116 } 117 ButtplugMessageSpecVersion::Version3 => { 118 ButtplugServerMessageVariant::V3(DeviceRemovedV0::new(disconnected_indexes[0]).into()) 119 } 120 ButtplugMessageSpecVersion::Version4 => { 121 ButtplugServerMessageVariant::V4(list.clone().into()) 122 } 123 } 124 } 125 // There is no == here because the only way DeviceList would be returned is via a 126 // RequestDeviceList call. Events will only ever be additions or deletions. 127 } 128} 129 130pub struct ButtplugServerMessageConverter { 131 original_message: Option<ButtplugClientMessageVariant>, 132} 133 134impl ButtplugServerMessageConverter { 135 pub fn new(msg: Option<ButtplugClientMessageVariant>) -> Self { 136 Self { 137 original_message: msg, 138 } 139 } 140 141 // 142 // Outgoing Conversion 143 // 144 145 pub fn convert_outgoing( 146 &self, 147 msg: &ButtplugServerMessageV4, 148 version: &ButtplugMessageSpecVersion, 149 ) -> Result<ButtplugServerMessageVariant, ButtplugError> { 150 let mut outgoing_msg = match version { 151 ButtplugMessageSpecVersion::Version0 => { 152 ButtplugServerMessageVariant::V0(self.convert_servermessagev4_to_servermessagev0(msg)?) 153 } 154 ButtplugMessageSpecVersion::Version1 => { 155 ButtplugServerMessageVariant::V1(self.convert_servermessagev4_to_servermessagev1(msg)?) 156 } 157 ButtplugMessageSpecVersion::Version2 => { 158 ButtplugServerMessageVariant::V2(self.convert_servermessagev4_to_servermessagev2(msg)?) 159 } 160 ButtplugMessageSpecVersion::Version3 => { 161 ButtplugServerMessageVariant::V3(self.convert_servermessagev4_to_servermessagev3(msg)?) 162 } 163 ButtplugMessageSpecVersion::Version4 => ButtplugServerMessageVariant::V4(msg.clone()), 164 }; 165 // Always make sure the ID is set after conversion 166 outgoing_msg.set_id(msg.id()); 167 Ok(outgoing_msg) 168 } 169 170 fn convert_servermessagev4_to_servermessagev3( 171 &self, 172 msg: &ButtplugServerMessageV4, 173 ) -> Result<ButtplugServerMessageV3, ButtplugError> { 174 match msg { 175 ButtplugServerMessageV4::InputReading(m) => { 176 let original_msg = self.original_message.as_ref().unwrap(); 177 if let ButtplugClientMessageVariant::V3(ButtplugClientMessageV3::SensorReadCmd(msg)) = 178 &original_msg 179 { 180 // We only ever implemented battery in v3, so only accept that. 181 if let InputTypeData::Battery(value) = m.data() { 182 let msg_out = SensorReadingV3::new( 183 msg.device_index(), 184 *msg.sensor_index(), 185 *msg.sensor_type(), 186 vec![value.data() as i32], 187 ); 188 Ok(msg_out.into()) 189 } else { 190 Err(ButtplugMessageError::UnexpectedMessageType("SensorReading".to_owned()).into()) 191 } 192 } else { 193 Err(ButtplugMessageError::UnexpectedMessageType("SensorReading".to_owned()).into()) 194 } 195 } 196 _ => Ok(msg.clone().try_into()?), 197 } 198 } 199 200 fn convert_servermessagev4_to_servermessagev2( 201 &self, 202 msg: &ButtplugServerMessageV4, 203 ) -> Result<ButtplugServerMessageV2, ButtplugError> { 204 let msg_v3 = self.convert_servermessagev4_to_servermessagev3(msg)?; 205 match msg_v3 { 206 ButtplugServerMessageV3::SensorReading(m) => { 207 let original_msg = self.original_message.as_ref().unwrap(); 208 // Sensor Reading didn't exist in v2, we only had Battery or RSSI. Therefore we need to 209 // context of the original message to make sure this conversion happens correctly. 210 if let ButtplugClientMessageVariant::V2(ButtplugClientMessageV2::BatteryLevelCmd(msg)) = 211 &original_msg 212 { 213 Ok(BatteryLevelReadingV2::new(msg.device_index(), m.data()[0] as f64 / 100f64).into()) 214 } else { 215 Err(ButtplugMessageError::UnexpectedMessageType("SensorReading".to_owned()).into()) 216 } 217 } 218 _ => Ok(msg_v3.into()), 219 } 220 } 221 222 fn convert_servermessagev4_to_servermessagev1( 223 &self, 224 msg: &ButtplugServerMessageV4, 225 ) -> Result<ButtplugServerMessageV1, ButtplugError> { 226 Ok(self.convert_servermessagev4_to_servermessagev2(msg)?.into()) 227 } 228 229 fn convert_servermessagev4_to_servermessagev0( 230 &self, 231 msg: &ButtplugServerMessageV4, 232 ) -> Result<ButtplugServerMessageV0, ButtplugError> { 233 Ok(self.convert_servermessagev4_to_servermessagev1(msg)?.into()) 234 } 235 236 // Outgoing Conversion Utility Methods 237}