pub mod configuration_manager;
pub mod protocol;
use serde::{
de::{self, Visitor},
Deserialize,
Deserializer,
Serialize,
Serializer,
};
use std::{convert::TryFrom, fmt, str::FromStr, string::ToString, sync::Arc};
use crate::{
core::{
errors::ButtplugError,
messages::{
self,
ButtplugDeviceCommandMessageUnion,
ButtplugServerMessage,
MessageAttributesMap,
RawReadCmd,
RawReading,
RawSubscribeCmd,
RawUnsubscribeCmd,
RawWriteCmd,
},
ButtplugResultFuture,
},
device::{
configuration_manager::{DeviceConfigurationManager, DeviceSpecifier, ProtocolDefinition},
protocol::{ButtplugProtocol, ProtocolTypes},
},
};
use async_trait::async_trait;
use broadcaster::BroadcastChannel;
use configuration_manager::DeviceProtocolConfiguration;
use core::hash::{Hash, Hasher};
use futures::future::BoxFuture;
#[derive(EnumString, Clone, Debug, PartialEq, Eq, Hash, Display, Copy)]
#[strum(serialize_all = "lowercase")]
pub enum Endpoint {
Tx,
Rx,
RxPressure,
RxTouch,
RxAccel,
Command,
Firmware,
TxMode,
TxVibrate,
TxShock,
TxVendorControl,
Whitelist,
}
impl Serialize for Endpoint {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
struct EndpointVisitor;
impl<'de> Visitor<'de> for EndpointVisitor {
type Value = Endpoint;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a string representing an endpoint")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Endpoint::from_str(value).map_err(|e| E::custom(format!("{}", e)))
}
}
impl<'de> Deserialize<'de> for Endpoint {
fn deserialize<D>(deserializer: D) -> Result<Endpoint, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_str(EndpointVisitor)
}
}
pub type BoundedDeviceEventBroadcaster = BroadcastChannel<
ButtplugDeviceEvent,
futures_channel::mpsc::Sender<ButtplugDeviceEvent>,
futures_channel::mpsc::Receiver<ButtplugDeviceEvent>,
>;
pub type ButtplugDeviceResultFuture =
BoxFuture<'static, Result<ButtplugServerMessage, ButtplugError>>;
#[derive(PartialEq, Debug)]
pub struct DeviceReadCmd {
pub endpoint: Endpoint,
pub length: u32,
pub timeout_ms: u32,
}
impl DeviceReadCmd {
pub fn new(endpoint: Endpoint, length: u32, timeout_ms: u32) -> Self {
Self {
endpoint,
length,
timeout_ms,
}
}
}
impl From<RawReadCmd> for DeviceReadCmd {
fn from(msg: RawReadCmd) -> Self {
Self {
endpoint: msg.endpoint,
length: msg.expected_length,
timeout_ms: msg.timeout,
}
}
}
#[derive(PartialEq, Debug)]
pub struct DeviceWriteCmd {
pub endpoint: Endpoint,
pub data: Vec<u8>,
pub write_with_response: bool,
}
impl DeviceWriteCmd {
pub fn new(endpoint: Endpoint, data: Vec<u8>, write_with_response: bool) -> Self {
Self {
endpoint,
data,
write_with_response,
}
}
}
impl From<RawWriteCmd> for DeviceWriteCmd {
fn from(msg: RawWriteCmd) -> Self {
Self {
endpoint: msg.endpoint,
data: msg.data,
write_with_response: msg.write_with_response,
}
}
}
#[derive(PartialEq, Debug)]
pub struct DeviceSubscribeCmd {
pub endpoint: Endpoint,
}
impl DeviceSubscribeCmd {
pub fn new(endpoint: Endpoint) -> Self {
Self { endpoint }
}
}
impl From<RawSubscribeCmd> for DeviceSubscribeCmd {
fn from(msg: RawSubscribeCmd) -> Self {
Self {
endpoint: msg.endpoint,
}
}
}
#[derive(PartialEq, Debug)]
pub struct DeviceUnsubscribeCmd {
pub endpoint: Endpoint,
}
impl DeviceUnsubscribeCmd {
pub fn new(endpoint: Endpoint) -> Self {
Self { endpoint }
}
}
impl From<RawUnsubscribeCmd> for DeviceUnsubscribeCmd {
fn from(msg: RawUnsubscribeCmd) -> Self {
Self {
endpoint: msg.endpoint,
}
}
}
#[derive(PartialEq, Debug)]
pub enum DeviceImplCommand {
Write(DeviceWriteCmd),
Read(DeviceReadCmd),
Subscribe(DeviceSubscribeCmd),
Unsubscribe(DeviceUnsubscribeCmd),
}
impl From<RawWriteCmd> for DeviceImplCommand {
fn from(msg: RawWriteCmd) -> Self {
DeviceImplCommand::Write(msg.into())
}
}
impl From<RawSubscribeCmd> for DeviceImplCommand {
fn from(msg: RawSubscribeCmd) -> Self {
DeviceImplCommand::Subscribe(msg.into())
}
}
impl From<RawUnsubscribeCmd> for DeviceImplCommand {
fn from(msg: RawUnsubscribeCmd) -> Self {
DeviceImplCommand::Unsubscribe(msg.into())
}
}
impl From<DeviceReadCmd> for DeviceImplCommand {
fn from(msg: DeviceReadCmd) -> Self {
DeviceImplCommand::Read(msg)
}
}
impl From<DeviceWriteCmd> for DeviceImplCommand {
fn from(msg: DeviceWriteCmd) -> Self {
DeviceImplCommand::Write(msg)
}
}
impl From<DeviceSubscribeCmd> for DeviceImplCommand {
fn from(msg: DeviceSubscribeCmd) -> Self {
DeviceImplCommand::Subscribe(msg)
}
}
impl From<DeviceUnsubscribeCmd> for DeviceImplCommand {
fn from(msg: DeviceUnsubscribeCmd) -> Self {
DeviceImplCommand::Unsubscribe(msg)
}
}
#[derive(Debug)]
pub struct ButtplugDeviceImplInfo {
pub endpoints: Vec<Endpoint>,
pub manufacturer_name: Option<String>,
pub product_name: Option<String>,
pub serial_number: Option<String>,
}
#[derive(Debug)]
pub enum ButtplugDeviceCommand {
Connect,
Message(DeviceImplCommand),
Disconnect,
}
#[derive(Debug)]
pub enum ButtplugDeviceReturn {
Connected(ButtplugDeviceImplInfo),
Ok(messages::Ok),
RawReading(messages::RawReading),
Error(ButtplugError),
}
#[derive(Debug, Clone)]
pub enum ButtplugDeviceEvent {
Notification(Endpoint, Vec<u8>),
Removed,
}
pub trait DeviceImpl: Sync + Send {
fn name(&self) -> &str;
fn address(&self) -> &str;
fn connected(&self) -> bool;
fn endpoints(&self) -> Vec<Endpoint>;
fn get_event_receiver(&self) -> BoundedDeviceEventBroadcaster;
fn disconnect(&self) -> ButtplugResultFuture;
fn read_value(&self, msg: DeviceReadCmd)
-> BoxFuture<'static, Result<RawReading, ButtplugError>>;
fn write_value(&self, msg: DeviceWriteCmd) -> ButtplugResultFuture;
fn subscribe(&self, msg: DeviceSubscribeCmd) -> ButtplugResultFuture;
fn unsubscribe(&self, msg: DeviceUnsubscribeCmd) -> ButtplugResultFuture;
}
#[async_trait]
pub trait ButtplugDeviceImplCreator: Sync + Send {
fn get_specifier(&self) -> DeviceSpecifier;
async fn try_create_device_impl(
&mut self,
protocol: ProtocolDefinition,
) -> Result<Box<dyn DeviceImpl>, ButtplugError>;
}
pub struct ButtplugDevice {
protocol: Box<dyn ButtplugProtocol>,
device: Arc<Box<dyn DeviceImpl>>,
}
impl Hash for ButtplugDevice {
fn hash<H: Hasher>(&self, state: &mut H) {
self.device.address().hash(state);
}
}
impl Eq for ButtplugDevice {
}
impl PartialEq for ButtplugDevice {
fn eq(&self, other: &Self) -> bool {
self.device.address() == other.device.address()
}
}
impl ButtplugDevice {
pub fn new(protocol: Box<dyn ButtplugProtocol>, device: Box<dyn DeviceImpl>) -> Self {
Self {
protocol,
device: Arc::new(device),
}
}
pub async fn try_create_device(
mut device_creator: Box<dyn ButtplugDeviceImplCreator>,
) -> Result<Option<ButtplugDevice>, ButtplugError> {
let device_cfg_mgr = DeviceConfigurationManager::default();
match device_cfg_mgr.find_configuration(&device_creator.get_specifier()) {
Some((config_name, config)) => {
let device_protocol_config =
DeviceProtocolConfiguration::new(config.defaults.clone(), config.configurations.clone());
if let Ok(proto_type) = ProtocolTypes::try_from(&*config_name) {
match device_creator.try_create_device_impl(config).await {
Ok(device_impl) => {
info!("Found Buttplug Device {}", device_impl.name());
match protocol::try_create_protocol(
&proto_type,
&*device_impl,
device_protocol_config,
)
.await
{
Ok(protocol_impl) => Ok(Some(ButtplugDevice::new(protocol_impl, device_impl))),
Err(e) => Err(e),
}
}
Err(e) => Err(e),
}
} else {
Ok(None)
}
}
None => Ok(None),
}
}
pub fn name(&self) -> &str {
self.protocol.name()
}
pub fn message_attributes(&self) -> MessageAttributesMap {
self.protocol.message_attributes()
}
pub fn parse_message(
&self,
message: ButtplugDeviceCommandMessageUnion,
) -> ButtplugDeviceResultFuture {
self.protocol.handle_command(self.device.clone(), message)
}
pub fn get_event_receiver(&self) -> BoundedDeviceEventBroadcaster {
self.device.get_event_receiver()
}
}