use crate::{
core::{
errors::ButtplugError,
messages::{
self, ButtplugDeviceCommandMessageUnion, ButtplugOutMessage, MessageAttributesMap,
RawReadCmd, RawReading, RawWriteCmd, SubscribeCmd, UnsubscribeCmd,
},
},
device::{
configuration_manager::{DeviceConfigurationManager, DeviceSpecifier, ProtocolDefinition},
protocol::ButtplugProtocol,
Endpoint,
},
};
use async_trait::async_trait;
use broadcaster::BroadcastChannel;
use futures_channel;
pub type BoundedDeviceEventBroadcaster = BroadcastChannel<
ButtplugDeviceEvent,
futures_channel::mpsc::Sender<ButtplugDeviceEvent>,
futures_channel::mpsc::Receiver<ButtplugDeviceEvent>,
>;
#[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<SubscribeCmd> for DeviceSubscribeCmd {
fn from(msg: SubscribeCmd) -> 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<UnsubscribeCmd> for DeviceUnsubscribeCmd {
fn from(msg: UnsubscribeCmd) -> Self {
Self {
endpoint: msg.endpoint,
}
}
}
#[derive(PartialEq, Debug)]
pub enum DeviceImplCommand {
Write(DeviceWriteCmd),
Read(DeviceReadCmd),
Subscribe(DeviceSubscribeCmd),
Unsubscribe(DeviceUnsubscribeCmd),
}
impl From<RawReadCmd> for DeviceImplCommand {
fn from(msg: RawReadCmd) -> Self {
DeviceImplCommand::Read(msg.into())
}
}
impl From<RawWriteCmd> for DeviceImplCommand {
fn from(msg: RawWriteCmd) -> Self {
DeviceImplCommand::Write(msg.into())
}
}
impl From<SubscribeCmd> for DeviceImplCommand {
fn from(msg: SubscribeCmd) -> Self {
DeviceImplCommand::Subscribe(msg.into())
}
}
impl From<UnsubscribeCmd> for DeviceImplCommand {
fn from(msg: UnsubscribeCmd) -> 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)
}
}
pub struct ButtplugDeviceImplInfo {
pub endpoints: Vec<Endpoint>,
pub manufacturer_name: Option<String>,
pub product_name: Option<String>,
pub serial_number: Option<String>,
}
pub enum ButtplugDeviceCommand {
Connect,
Message(DeviceImplCommand),
Disconnect,
}
pub enum ButtplugDeviceReturn {
Connected(ButtplugDeviceImplInfo),
Ok(messages::Ok),
RawReading(messages::RawReading),
Error(ButtplugError),
}
#[derive(Debug, Clone)]
pub enum ButtplugDeviceEvent {
Notification(Endpoint, Vec<u8>),
Removed,
}
#[async_trait]
pub trait DeviceImpl: Sync + Send {
fn name(&self) -> &str;
fn address(&self) -> &str;
fn connected(&self) -> bool;
fn endpoints(&self) -> Vec<Endpoint>;
async fn disconnect(&self);
fn box_clone(&self) -> Box<dyn DeviceImpl>;
fn get_event_receiver(&self) -> BoundedDeviceEventBroadcaster;
async fn read_value(&self, msg: DeviceReadCmd) -> Result<RawReading, ButtplugError>;
async fn write_value(&self, msg: DeviceWriteCmd) -> Result<(), ButtplugError>;
async fn subscribe(&self, msg: DeviceSubscribeCmd) -> Result<(), ButtplugError>;
async fn unsubscribe(&self, msg: DeviceUnsubscribeCmd) -> Result<(), ButtplugError>;
}
impl Clone for Box<dyn DeviceImpl> {
fn clone(&self) -> Box<dyn DeviceImpl> {
self.box_clone()
}
}
#[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>;
}
#[derive(Clone)]
pub struct ButtplugDevice {
protocol: Box<dyn ButtplugProtocol>,
device: Box<dyn DeviceImpl>,
}
impl ButtplugDevice {
pub fn new(protocol: Box<dyn ButtplugProtocol>, device: Box<dyn DeviceImpl>) -> Self {
Self { protocol, device }
}
pub async fn try_create_device(
mut device_creator: Box<dyn ButtplugDeviceImplCreator>,
) -> Result<Option<ButtplugDevice>, ButtplugError> {
let device_mgr = DeviceConfigurationManager::new();
match device_mgr.find_configuration(&device_creator.get_specifier()) {
Some((config_name, config)) => {
if let Some(proto_creator) = device_mgr.get_protocol_creator(&config_name) {
match device_creator.try_create_device_impl(config).await {
Ok(device_impl) => {
info!("Found Buttplug Device {}", device_impl.name());
match proto_creator.try_create_protocol(&device_impl).await {
Ok(protocol_impl) => {
Ok(Some(ButtplugDevice::new(protocol_impl, device_impl)))
}
Err(e) => Err(e),
}
}
Err(e) => Err(e),
}
} else {
Ok(None)
}
}
None => return Ok(None),
}
}
pub fn name(&self) -> &str {
self.protocol.name()
}
pub fn message_attributes(&self) -> MessageAttributesMap {
self.protocol.message_attributes()
}
pub async fn parse_message(
&mut self,
message: &ButtplugDeviceCommandMessageUnion,
) -> Result<ButtplugOutMessage, ButtplugError> {
self.protocol.parse_message(&self.device, message).await
}
pub fn get_event_receiver(&self) -> BoundedDeviceEventBroadcaster {
self.device.get_event_receiver()
}
}