···8//! Representation and management of devices connected to the server.
910use super::{
11- ButtplugClientError,
12- ButtplugClientMessageFuturePair,
13- ButtplugClientRequest,
14- ButtplugClientResultFuture,
15- ButtplugServerMessageFuture,
16};
17use crate::{
18 core::{
19 connector::ButtplugConnectorError,
20 errors::{ButtplugDeviceError, ButtplugError, ButtplugMessageError},
21 messages::{
22- ActuatorType,
23- ButtplugCurrentSpecClientMessage,
24- ButtplugCurrentSpecDeviceMessageType,
25- ButtplugCurrentSpecServerMessage,
26- ButtplugDeviceMessageType,
27- ButtplugMessage,
28- DeviceMessageAttributes,
29- DeviceMessageInfo,
30- Endpoint,
31- LinearCmd,
32- RawReadCmd,
33- RawSubscribeCmd,
34- RawUnsubscribeCmd,
35- RawWriteCmd,
36- RotateCmd,
37- RotationSubcommand,
38- ScalarCmd,
39- ScalarSubcommand,
40- SensorReadCmd,
41- SensorSubscribeCmd,
42- SensorType,
43- SensorUnsubscribeCmd,
44- StopDeviceCmd,
45 VectorSubcommand,
46 },
47 },
48 util::stream::convert_broadcast_receiver_to_stream,
49};
50use futures::{future, FutureExt, Stream};
051use std::{
52 collections::HashMap,
53 fmt,
···56 Arc,
57 },
58};
59-use getset::{Getters, CopyGetters};
60use tokio::sync::broadcast;
61use tracing_futures::Instrument;
62···152/// to a device connected to the server.
153pub struct ButtplugClientDevice {
154 /// Name of the device
155- #[getset(get="pub")]
156 name: String,
157 /// Index of the device, matching the index in the
158 /// [ButtplugServer][crate::server::ButtplugServer]'s
159 /// [DeviceManager][crate::server::device_manager::DeviceManager].
160- #[getset(get_copy="pub")]
161 index: u32,
162 /// Map of messages the device can take, along with the attributes of those
163 /// messages.
164- #[getset(get="pub")]
165 message_attributes: DeviceMessageAttributes,
166 /// Sends commands from the [ButtplugClientDevice] instance to the
167 /// [ButtplugClient][super::ButtplugClient]'s event loop, which will then send
···310 .into(),
311 ),
312 }
313- }.boxed()
0314 }
315316 /// Commands device to vibrate, assuming it has the features to do so.
···372 self.send_message_expect_ok(msg)
373 }
374375-pub fn scalar(&self, scalar_cmd: &ScalarCommand) -> ButtplugClientResultFuture {
376- if self.message_attributes.scalar_cmd().is_none() {
377- return self.create_boxed_future_client_error(
378- ButtplugDeviceError::MessageNotSupported(ButtplugDeviceMessageType::VibrateCmd).into(),
379- );
380- }
381382- let scalar_count: u32 = self
383- .message_attributes
384- .scalar_cmd()
385- .as_ref()
386- .expect("Already checked existence")
387- .len() as u32;
388389- let mut scalar_vec: Vec<ScalarSubcommand>;
390- match scalar_cmd {
391- ScalarCommand::Scalar((scalar, actuator)) => {
392- scalar_vec = Vec::with_capacity(scalar_count as usize);
393- for i in 0..scalar_count {
394- scalar_vec.push(ScalarSubcommand::new(i, *scalar, *actuator));
395- }
396- }
397- ScalarCommand::ScalarMap(map) => {
398- if map.len() as u32 > scalar_count {
399- return self.create_boxed_future_client_error(
400- ButtplugDeviceError::DeviceFeatureCountMismatch(scalar_count, map.len() as u32)
401- .into(),
402- );
403 }
404- scalar_vec = Vec::with_capacity(map.len() as usize);
405- for (idx, (scalar, actuator)) in map {
406- if *idx >= scalar_count {
407 return self.create_boxed_future_client_error(
408- ButtplugDeviceError::DeviceFeatureIndexError(scalar_count, *idx).into(),
409 );
410 }
411- scalar_vec.push(ScalarSubcommand::new(*idx, *scalar, *actuator));
00000000412 }
413- }
414- ScalarCommand::ScalarVec(vec) => {
415- if vec.len() as u32 > scalar_count {
416- return self.create_boxed_future_client_error(
417- ButtplugDeviceError::DeviceFeatureCountMismatch(scalar_count, vec.len() as u32)
418- .into(),
419- );
420- }
421- scalar_vec = Vec::with_capacity(vec.len() as usize);
422- for (i, (scalar, actuator)) in vec.iter().enumerate() {
423- scalar_vec.push(ScalarSubcommand::new(i as u32, *scalar, *actuator));
424 }
425 }
00426 }
427- let msg = ScalarCmd::new(self.index, scalar_vec).into();
428- self.send_message_expect_ok(msg)
429-}
430431 /// Commands device to move linearly, assuming it has the features to do so.
432 pub fn linear(&self, linear_cmd: &LinearCommand) -> ButtplugClientResultFuture {
···570 return self.create_boxed_future_client_error(
571 ButtplugDeviceError::ProtocolSensorNotSupported(*sensor_type).into(),
572 );
573- }
574 let msg = SensorReadCmd::new(self.index, sensor_indexes[0], *sensor_type).into();
575 let reply = self.send_message(msg);
576- async move {
577 if let ButtplugCurrentSpecServerMessage::SensorReading(data) = reply.await? {
578 Ok(data.data().clone())
579 } else {
580- Err(ButtplugError::ButtplugMessageError(ButtplugMessageError::UnexpectedMessageType("SensorReading".to_owned())).into())
00000581 }
582- }.boxed()
0583 }
584585 pub fn battery_level(&self) -> ButtplugClientResultFuture<f64> {
···602 pub fn raw_write(
603 &self,
604 endpoint: Endpoint,
605- data: Vec<u8>,
606 write_with_response: bool,
607 ) -> ButtplugClientResultFuture {
608 if self.message_attributes.raw_write_cmd().is_none() {
···613 let msg = ButtplugCurrentSpecClientMessage::RawWriteCmd(RawWriteCmd::new(
614 self.index,
615 endpoint,
616- data,
617 write_with_response,
618 ));
619 self.send_message_expect_ok(msg)
···649 .into(),
650 ),
651 }
652- }.boxed()
0653 }
654655 pub fn raw_subscribe(&self, endpoint: Endpoint) -> ButtplugClientResultFuture {
···703 }
704}
705706-impl Eq for ButtplugClientDevice {
707-}
708709impl PartialEq for ButtplugClientDevice {
710 fn eq(&self, other: &Self) -> bool {
···8//! Representation and management of devices connected to the server.
910use super::{
11+ ButtplugClientError, ButtplugClientMessageFuturePair, ButtplugClientRequest,
12+ ButtplugClientResultFuture, ButtplugServerMessageFuture,
00013};
14use crate::{
15 core::{
16 connector::ButtplugConnectorError,
17 errors::{ButtplugDeviceError, ButtplugError, ButtplugMessageError},
18 messages::{
19+ ActuatorType, ButtplugCurrentSpecClientMessage, ButtplugCurrentSpecDeviceMessageType,
20+ ButtplugCurrentSpecServerMessage, ButtplugDeviceMessageType, ButtplugMessage,
21+ DeviceMessageAttributes, DeviceMessageInfo, Endpoint, LinearCmd, RawReadCmd, RawSubscribeCmd,
22+ RawUnsubscribeCmd, RawWriteCmd, RotateCmd, RotationSubcommand, ScalarCmd, ScalarSubcommand,
23+ SensorReadCmd, SensorSubscribeCmd, SensorType, SensorUnsubscribeCmd, StopDeviceCmd,
00000000000000000024 VectorSubcommand,
25 },
26 },
27 util::stream::convert_broadcast_receiver_to_stream,
28};
29use futures::{future, FutureExt, Stream};
30+use getset::{CopyGetters, Getters};
31use std::{
32 collections::HashMap,
33 fmt,
···36 Arc,
37 },
38};
039use tokio::sync::broadcast;
40use tracing_futures::Instrument;
41···131/// to a device connected to the server.
132pub struct ButtplugClientDevice {
133 /// Name of the device
134+ #[getset(get = "pub")]
135 name: String,
136 /// Index of the device, matching the index in the
137 /// [ButtplugServer][crate::server::ButtplugServer]'s
138 /// [DeviceManager][crate::server::device_manager::DeviceManager].
139+ #[getset(get_copy = "pub")]
140 index: u32,
141 /// Map of messages the device can take, along with the attributes of those
142 /// messages.
143+ #[getset(get = "pub")]
144 message_attributes: DeviceMessageAttributes,
145 /// Sends commands from the [ButtplugClientDevice] instance to the
146 /// [ButtplugClient][super::ButtplugClient]'s event loop, which will then send
···289 .into(),
290 ),
291 }
292+ }
293+ .boxed()
294 }
295296 /// Commands device to vibrate, assuming it has the features to do so.
···352 self.send_message_expect_ok(msg)
353 }
354355+ pub fn scalar(&self, scalar_cmd: &ScalarCommand) -> ButtplugClientResultFuture {
356+ if self.message_attributes.scalar_cmd().is_none() {
357+ return self.create_boxed_future_client_error(
358+ ButtplugDeviceError::MessageNotSupported(ButtplugDeviceMessageType::VibrateCmd).into(),
359+ );
360+ }
361362+ let scalar_count: u32 = self
363+ .message_attributes
364+ .scalar_cmd()
365+ .as_ref()
366+ .expect("Already checked existence")
367+ .len() as u32;
368369+ let mut scalar_vec: Vec<ScalarSubcommand>;
370+ match scalar_cmd {
371+ ScalarCommand::Scalar((scalar, actuator)) => {
372+ scalar_vec = Vec::with_capacity(scalar_count as usize);
373+ for i in 0..scalar_count {
374+ scalar_vec.push(ScalarSubcommand::new(i, *scalar, *actuator));
375+ }
0000000376 }
377+ ScalarCommand::ScalarMap(map) => {
378+ if map.len() as u32 > scalar_count {
0379 return self.create_boxed_future_client_error(
380+ ButtplugDeviceError::DeviceFeatureCountMismatch(scalar_count, map.len() as u32).into(),
381 );
382 }
383+ scalar_vec = Vec::with_capacity(map.len() as usize);
384+ for (idx, (scalar, actuator)) in map {
385+ if *idx >= scalar_count {
386+ return self.create_boxed_future_client_error(
387+ ButtplugDeviceError::DeviceFeatureIndexError(scalar_count, *idx).into(),
388+ );
389+ }
390+ scalar_vec.push(ScalarSubcommand::new(*idx, *scalar, *actuator));
391+ }
392 }
393+ ScalarCommand::ScalarVec(vec) => {
394+ if vec.len() as u32 > scalar_count {
395+ return self.create_boxed_future_client_error(
396+ ButtplugDeviceError::DeviceFeatureCountMismatch(scalar_count, vec.len() as u32).into(),
397+ );
398+ }
399+ scalar_vec = Vec::with_capacity(vec.len() as usize);
400+ for (i, (scalar, actuator)) in vec.iter().enumerate() {
401+ scalar_vec.push(ScalarSubcommand::new(i as u32, *scalar, *actuator));
402+ }
0403 }
404 }
405+ let msg = ScalarCmd::new(self.index, scalar_vec).into();
406+ self.send_message_expect_ok(msg)
407 }
000408409 /// Commands device to move linearly, assuming it has the features to do so.
410 pub fn linear(&self, linear_cmd: &LinearCommand) -> ButtplugClientResultFuture {
···548 return self.create_boxed_future_client_error(
549 ButtplugDeviceError::ProtocolSensorNotSupported(*sensor_type).into(),
550 );
551+ }
552 let msg = SensorReadCmd::new(self.index, sensor_indexes[0], *sensor_type).into();
553 let reply = self.send_message(msg);
554+ async move {
555 if let ButtplugCurrentSpecServerMessage::SensorReading(data) = reply.await? {
556 Ok(data.data().clone())
557 } else {
558+ Err(
559+ ButtplugError::ButtplugMessageError(ButtplugMessageError::UnexpectedMessageType(
560+ "SensorReading".to_owned(),
561+ ))
562+ .into(),
563+ )
564 }
565+ }
566+ .boxed()
567 }
568569 pub fn battery_level(&self) -> ButtplugClientResultFuture<f64> {
···586 pub fn raw_write(
587 &self,
588 endpoint: Endpoint,
589+ data: &Vec<u8>,
590 write_with_response: bool,
591 ) -> ButtplugClientResultFuture {
592 if self.message_attributes.raw_write_cmd().is_none() {
···597 let msg = ButtplugCurrentSpecClientMessage::RawWriteCmd(RawWriteCmd::new(
598 self.index,
599 endpoint,
600+ data.clone(),
601 write_with_response,
602 ));
603 self.send_message_expect_ok(msg)
···633 .into(),
634 ),
635 }
636+ }
637+ .boxed()
638 }
639640 pub fn raw_subscribe(&self, endpoint: Endpoint) -> ButtplugClientResultFuture {
···688 }
689}
690691+impl Eq for ButtplugClientDevice {}
0692693impl PartialEq for ButtplugClientDevice {
694 fn eq(&self, other: &Self) -> bool {
+3-1
buttplug/src/server/device/configuration/mod.rs
···324 }
325326 /// Check to make sure the message attributes of an instance are valid.
327- // TODO Can we do this in new() instead and return a result there?
328 fn is_valid(&self) -> Result<(), ButtplugDeviceError> {
329 if let Some(attrs) = self.message_attributes.scalar_cmd() {
330 for attr in attrs {
···679 raw_endpoints: &[Endpoint],
680 ) -> Option<ProtocolDeviceAttributes> {
681 let mut flat_attrs = if let Some(attrs) = self.protocol_attributes.get(&identifier.into()) {
0682 attrs.flatten()
683 } else if let Some(attrs) = self.protocol_attributes.get(&ProtocolAttributesIdentifier {
684 address: None,
685 attributes_identifier: identifier.attributes_identifier().clone(),
686 protocol: identifier.protocol().clone(),
687 }) {
0688 attrs.flatten()
689 } else if let Some(attrs) = self.protocol_attributes.get(&ProtocolAttributesIdentifier {
690 address: None,
691 attributes_identifier: ProtocolAttributesType::Default,
692 protocol: identifier.protocol().clone(),
693 }) {
0694 attrs.flatten()
695 } else {
696 return None;
···324 }
325326 /// Check to make sure the message attributes of an instance are valid.
0327 fn is_valid(&self) -> Result<(), ButtplugDeviceError> {
328 if let Some(attrs) = self.message_attributes.scalar_cmd() {
329 for attr in attrs {
···678 raw_endpoints: &[Endpoint],
679 ) -> Option<ProtocolDeviceAttributes> {
680 let mut flat_attrs = if let Some(attrs) = self.protocol_attributes.get(&identifier.into()) {
681+ debug!("User device config found for {:?}", identifier);
682 attrs.flatten()
683 } else if let Some(attrs) = self.protocol_attributes.get(&ProtocolAttributesIdentifier {
684 address: None,
685 attributes_identifier: identifier.attributes_identifier().clone(),
686 protocol: identifier.protocol().clone(),
687 }) {
688+ debug!("Protocol + Identifier device config found for {:?}", identifier);
689 attrs.flatten()
690 } else if let Some(attrs) = self.protocol_attributes.get(&ProtocolAttributesIdentifier {
691 address: None,
692 attributes_identifier: ProtocolAttributesType::Default,
693 protocol: identifier.protocol().clone(),
694 }) {
695+ debug!("Protocol device config found for {:?}", identifier);
696 attrs.flatten()
697 } else {
698 return None;
+6
buttplug/src/server/mod.rs
···303 .protocol_attributes(ident.clone(), attributes.clone());
304 }
305000000306 let device_manager = Arc::new(self.device_manager_builder.finish(output_sender.clone())?);
307308 // Spawn the ping timer task, assuming the ping time is > 0.
···303 .protocol_attributes(ident.clone(), attributes.clone());
304 }
305306+ for (ident, attributes) in protocol_map.user_configs() {
307+ self
308+ .device_manager_builder
309+ .protocol_attributes(ident.into(), attributes.clone());
310+ }
311+312 let device_manager = Arc::new(self.device_manager_builder.finish(output_sender.clone())?);
313314 // Spawn the ping timer task, assuming the ping time is > 0.