Buttplug sex toy control library
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}