Buttplug sex toy control library
at dev 7.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//! Methods for establishing connections between Buttplug Clients and Servers 9//! 10//! Buttplug is made to work in many different circumstances. The [crate::client::ButtplugClient] 11//! and [crate::server::ButtplugServer] may be in the same process, in different process 12//! communicating over some sort of IPC, or on different machines using a network connection. 13//! Connectors are what make these setups possible. 14//! 15//! # How Buttplug Clients and Servers Use Connectors 16//! 17//! A Buttplug Client uses a connector to communicate with a server, be it in the same process or on 18//! another machine. The client's connector handles establishing the connection to the server, as 19//! well as sending ([possibly serialized][crate::messages::serializer]) messages to the 20//! server and matching replies from the server to waiting futures. 21//! 22//! Buttplug servers use connectors to receive info from clients. They usually have less to do than 23//! client connectors, because they don't have to keep track of messages waiting for replies (since 24//! Buttplug messages that require responses are only client -> server, the server will never send 25//! anything to a client that expects a response.) 26//! 27//! # In-Process and Remote Connectors 28//! 29//! There are two types of connectors: In-Process and Remote. All connectors have the same API 30//! (since they all follow the [crate::connector::ButtplugConnector] trait), but will varying in 31//! latency, message passing techniques, etc... 32//! 33//! There is only 1 in-process connector, the [ButtplugInProcessClientConnector]. This is used when 34//! the client and server live in the same process, which is useful for multiple reasons (see 35//! [ButtplugInProcessClientConnector] documentation for more info). As in-process connectors can 36//! just send message objects back and forth, there is no need for message serialization. 37//! 38//! Remote connectors refer to any connector that connects to something outside of the current 39//! process, be it still on the same machine (IPC) or somewhere else (network). 40//! 41//! # Remote Transports 42//! 43//! Remote Transports 44//! 45//! # Buttplug Client/Server Does Not Necessarily Mean Transport Client/Server 46//! 47//! Here's an odd but valid situation: *You can have a Buttplug Client that uses a Websocket Server 48//! connector!* 49//! 50//! There are times where this is actually useful. For instance, let's say a user of Buttplug wants 51//! to use a Windows 7 desktop machine to control a Bluetooth LE toy. This normally wouldn't work 52//! because Windows 7 doesn't have a Bluetooth LE API we can easily access. However, they also have 53//! an android phone. They could run a Buttplug Server in Chrome on their Android phone, have the 54//! Client on the desktop run a websocket server, then have (and stick with me here) the Buttplug 55//! Server in the Android Chrome instance use a Websocket Client to connect to the Websocket Server 56//! on the desktop. This allows the desktop machine to proxy Bluetooth to the WebBluetooth API built 57//! into Android Chrome. 58//! 59//! Is this ridiculous? *Absolutely*. 60//! 61//! Will people do it? Remember, this is a library about sex, so the answer is also *Absolutely*. 62//! 63//! There are slightly more useful situations like device forwarders where this work comes in also, 64//! but that Windows 7/Android example is where the idea originally came from. 65 66pub mod remote_connector; 67pub mod transport; 68 69use crate::{ 70 message::{ButtplugMessage, serializer::ButtplugSerializedMessage}, 71 util::future::{ButtplugFuture, ButtplugFutureStateShared}, 72}; 73use displaydoc::Display; 74use futures::future::{self, BoxFuture, FutureExt}; 75pub use remote_connector::ButtplugRemoteConnector; 76use thiserror::Error; 77use tokio::sync::mpsc::Sender; 78 79pub type ButtplugConnectorResult = Result<(), ButtplugConnectorError>; 80pub type ButtplugConnectorStateShared = 81 ButtplugFutureStateShared<Result<(), ButtplugConnectorError>>; 82pub type ButtplugConnectorFuture = ButtplugFuture<Result<(), ButtplugConnectorError>>; 83pub type ButtplugConnectorResultFuture = BoxFuture<'static, ButtplugConnectorResult>; 84 85/// Errors specific to client connector structs. 86/// 87/// Errors that relate to the communication method of the client connector. Can 88/// include network/IPC protocol specific errors. 89#[derive(Debug, Error, Display)] 90pub enum ButtplugConnectorError { 91 /// Connector is not currently connected to a remote. 92 ConnectorNotConnected, 93 /// Connector channel has closed, meaning disconnection is likely. 94 ConnectorChannelClosed, 95 /// Connector already connected, cannot be connected twice. 96 ConnectorAlreadyConnected, 97 /// Connector error: {0} 98 ConnectorGenericError(String), 99 /// Specific error for connector type: {0}. 100 TransportSpecificError(transport::ButtplugConnectorTransportSpecificError), 101} 102 103impl<T> From<ButtplugConnectorError> for BoxFuture<'static, Result<T, ButtplugConnectorError>> 104where 105 T: Send + 'static, 106{ 107 fn from(err: ButtplugConnectorError) -> BoxFuture<'static, Result<T, ButtplugConnectorError>> { 108 future::ready(Err(err)).boxed() 109 } 110} 111 112/// Trait for client connectors. 113/// 114/// Connectors are how Buttplug Clients and servers talk to each other. Whether 115/// embedded, meaning the client and server exist in the same process space, or 116/// remote, where the client and server are separated by some boundary, the 117/// connector trait makes it so that these components always look local. 118/// 119/// The `O` type specifies the outbound message type. This will usually be a 120/// message enum. For instance, in a client connector, this would usually be 121/// [ButtplugClientMessage][crate::messages::ButtplugClientMessage]. 122/// 123/// The `I` type specifies the inbound message type. This will usually be a 124/// message enum. For instance, in a client connector, this would usually be 125/// [ButtplugServerMessage][crate::messages::ButtplugServerMessage]. 126pub trait ButtplugConnector<OutboundMessageType, InboundMessageType>: Send + Sync 127where 128 OutboundMessageType: ButtplugMessage + 'static, 129 InboundMessageType: ButtplugMessage + 'static, 130{ 131 /// Connects the client to the server. 132 /// 133 /// Tries to connect to another connector, returning an event stream of 134 /// incoming messages (of type `I`) on successful connect. 135 /// 136 /// # Errors 137 /// 138 /// Returns a [ButtplugConnectorError] if there is a problem with the 139 /// connection process. It is assumed that all information needed to create 140 /// the connection will be passed as part of the Trait implementors creation 141 /// methods. 142 /// 143 /// # Async 144 /// 145 /// As connection may involve blocking operations like establishing network 146 /// connections, this trait method is marked async. 147 fn connect( 148 &mut self, 149 message_receiver: Sender<InboundMessageType>, 150 ) -> BoxFuture<'static, Result<(), ButtplugConnectorError>>; 151 /// Disconnects the client from the server. 152 /// 153 /// Returns a [ButtplugConnectorError] if there is a problem with the 154 /// disconnection process. 155 /// 156 /// # Async 157 /// 158 /// As disconnection may involve blocking operations like network closing and 159 /// cleanup, this trait method is marked async. 160 fn disconnect(&self) -> ButtplugConnectorResultFuture; 161 /// Sends a message of outbound message type `O` to the other connector. 162 /// 163 /// # Errors 164 /// 165 /// If the connector is not currently connected, or an error happens during 166 /// the send operation, this will return a [ButtplugConnectorError] 167 fn send(&self, msg: OutboundMessageType) -> ButtplugConnectorResultFuture; 168}