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//! Buttplug Error Structs/Enums, representing protocol errors.
9
10use super::message::{
11 self,
12 ButtplugMessageSpecVersion,
13 ErrorCode,
14 InputType,
15 OutputType,
16 serializer::ButtplugSerializerError,
17};
18use futures::future::BoxFuture;
19use serde::{Deserialize, Serialize};
20use thiserror::Error;
21
22pub type ButtplugResult<T = ()> = Result<T, ButtplugError>;
23
24/// Handshake errors occur while a client is connecting to a server. This
25/// usually involves protocol handshake errors. For connector errors (i.e. when
26/// a remote network connection cannot be established), see
27/// [crate::connector::ButtplugConnectorError].
28impl<T> From<ButtplugHandshakeError> for BoxFuture<'static, Result<T, ButtplugError>>
29where
30 T: Send + 'static,
31{
32 fn from(err: ButtplugHandshakeError) -> BoxFuture<'static, Result<T, ButtplugError>> {
33 ButtplugError::from(err).into()
34 }
35}
36
37#[derive(Debug, Error, Display, Clone, PartialEq, Eq, Serialize, Deserialize)]
38pub enum ButtplugHandshakeError {
39 /// Expected either a ServerInfo or Error message, received {0}
40 UnexpectedHandshakeMessageReceived(String),
41 /// Expected a RequestServerInfo message to start connection. Message either not received or wrong message received.
42 RequestServerInfoExpected,
43 /// Handshake already happened, cannot run handshake again.
44 HandshakeAlreadyHappened,
45 /// Server has already connected and disconnected, cannot be reused
46 ReconnectDenied,
47 /// Server spec version ({0}) must be equal or greater than client version ({1})
48 MessageSpecVersionMismatch(ButtplugMessageSpecVersion, ButtplugMessageSpecVersion),
49 /// Untyped Deserialized Error: {0}
50 UntypedDeserializedError(String),
51 /// Unhandled spec version requested, may require extra arguments to activate: {0}
52 UnhandledMessageSpecVersionRequested(ButtplugMessageSpecVersion),
53}
54
55/// Message errors occur when a message is somehow malformed on creation, or
56/// received unexpectedly by a client or server.
57impl<T> From<ButtplugMessageError> for BoxFuture<'static, Result<T, ButtplugError>>
58where
59 T: Send + 'static,
60{
61 fn from(err: ButtplugMessageError) -> BoxFuture<'static, Result<T, ButtplugError>> {
62 ButtplugError::from(err).into()
63 }
64}
65
66#[derive(Debug, Error, Display, Clone, PartialEq, Eq, Serialize, Deserialize)]
67pub enum ButtplugMessageError {
68 /// Got unexpected message type: {0}
69 UnexpectedMessageType(String),
70 /// {0} {1} cannot be converted to {2}
71 VersionError(String, String, String),
72 /// Message conversion error: {0}
73 MessageConversionError(String),
74 /// Invalid message contents: {0}
75 InvalidMessageContents(String),
76 /// Unhandled message type: {0}
77 UnhandledMessage(String),
78 /// Message validation error(s): {0}
79 ValidationError(String),
80 /// Message serialization error
81 #[error(transparent)]
82 MessageSerializationError(#[from] ButtplugSerializerError),
83 /// Untyped Deserialized Error: {0}
84 UntypedDeserializedError(String),
85}
86
87/// Ping errors occur when a server requires a ping response (set up during
88/// connection handshake), and the client does not return a response in the
89/// alloted timeframe. This also signifies a server disconnect.
90impl<T> From<ButtplugPingError> for BoxFuture<'static, Result<T, ButtplugError>>
91where
92 T: Send + 'static,
93{
94 fn from(err: ButtplugPingError) -> BoxFuture<'static, Result<T, ButtplugError>> {
95 ButtplugError::from(err).into()
96 }
97}
98
99#[derive(Debug, Error, Display, Clone, PartialEq, Eq, Serialize, Deserialize)]
100pub enum ButtplugPingError {
101 /// Pinged timer exhausted, system has shut down.
102 PingedOut,
103 /// Ping timer not running.
104 PingTimerNotRunning,
105 /// Ping time must be greater than 0.
106 InvalidPingTimeout,
107 /// Untyped Deserialized Error: {0}
108 UntypedDeserializedError(String),
109}
110
111/// Device errors occur during device interactions, including sending
112/// unsupported message commands, addressing the wrong number of device
113/// attributes, etc...
114impl<T> From<ButtplugDeviceError> for BoxFuture<'static, Result<T, ButtplugError>>
115where
116 T: Send + 'static,
117{
118 fn from(err: ButtplugDeviceError) -> BoxFuture<'static, Result<T, ButtplugError>> {
119 ButtplugError::from(err).into()
120 }
121}
122#[derive(Debug, Error, Display, Clone, PartialEq, Eq, Serialize, Deserialize)]
123pub enum ButtplugDeviceError {
124 /// Device {0} not connected
125 DeviceNotConnected(String),
126 /// Device does not support message type {0}.
127 MessageNotSupported(String),
128 /// Device only has {0} features, but {1} commands were sent.
129 DeviceFeatureCountMismatch(u32, u32),
130 /// Device only has {0} features, but was given an index of {1}
131 DeviceFeatureIndexError(u32, u32),
132 /// Device feature mismatch: {0}
133 DeviceFeatureMismatch(String),
134 /// Device only has {0} sensors, but was given an index of {1}
135 DeviceSensorIndexError(u32, u32),
136 /// Device connection error: {0}
137 DeviceConnectionError(String),
138 /// Device communication error: {0}
139 DeviceCommunicationError(String),
140 /// Device feature only has {0} steps for control, but {1} steps specified.
141 DeviceStepRangeError(i32, i32),
142 /// Device got {0} message but has no actuators
143 DeviceNoActuatorError(String),
144 /// Device got {0} message but has no sensors
145 DeviceNoSensorError(String),
146 /// Device does not have endpoint {0}
147 InvalidEndpoint(String),
148 /// Device does not handle command type: {0}
149 UnhandledCommand(String),
150 /// Device type specific error: {0}.
151 DeviceSpecificError(String),
152 /// No device available at index {0}
153 DeviceNotAvailable(u32),
154 /// Device scanning already started.
155 DeviceScanningAlreadyStarted,
156 /// Device scanning already stopped.
157 DeviceScanningAlreadyStopped,
158 /// Device permission error: {0}
159 DevicePermissionError(String),
160 /// Device command does not take negative numbers
161 DeviceCommandSignError,
162 /// {0}
163 ProtocolAttributesNotFound(String),
164 /// Protocol {0} not implemented in library
165 ProtocolNotImplemented(String),
166 /// {0} protocol specific error: {1}
167 ProtocolSpecificError(String, String),
168 /// {0}
169 ProtocolRequirementError(String),
170 /// Protocol already added to system {0},
171 ProtocolAlreadyAdded(String),
172 /// Untyped Deserialized Error: {0}
173 UntypedDeserializedError(String),
174 /// Device Configuration Error: {0}
175 DeviceConfigurationError(String),
176 /// Output Type Mismatch: Index {0} got command for {1}, which is not valid
177 DeviceOutputTypeMismatch(u32, OutputType, OutputType),
178 /// Input Type Mismatch: Index {0} got command for {1}, which is not valid
179 DeviceInputTypeMismatch(u32, InputType),
180 /// Protocol does not have an implementation available for Sensor Type {0}
181 ProtocolInputNotSupported(InputType),
182 /// Device does not support {0}
183 OutputNotSupported(OutputType),
184}
185
186/// Unknown errors occur in exceptional circumstances where no other error type
187/// will suffice. These are rare and usually fatal (disconnecting) errors.
188impl<T> From<ButtplugUnknownError> for BoxFuture<'static, Result<T, ButtplugError>>
189where
190 T: Send + 'static,
191{
192 fn from(err: ButtplugUnknownError) -> BoxFuture<'static, Result<T, ButtplugError>> {
193 ButtplugError::from(err).into()
194 }
195}
196
197#[derive(Debug, Error, Display, Clone, PartialEq, Eq, Serialize, Deserialize)]
198pub enum ButtplugUnknownError {
199 /// Cannot start scanning, no device communication managers available to use for scanning.
200 NoDeviceCommManagers,
201 /// Got unexpected enum type: {0}
202 UnexpectedType(String),
203 /// Untyped Deserialized Error: {0}
204 UntypedDeserializedError(String),
205 /// Device Manager has been shut down by its owning server and is no longer available.
206 DeviceManagerNotRunning,
207}
208
209/// Aggregation enum for protocol error types.
210#[derive(Debug, Error, Clone, PartialEq, Eq, Serialize, Deserialize)]
211pub enum ButtplugError {
212 #[error(transparent)]
213 ButtplugHandshakeError(#[from] ButtplugHandshakeError),
214 #[error(transparent)]
215 ButtplugMessageError(#[from] ButtplugMessageError),
216 #[error(transparent)]
217 ButtplugPingError(#[from] ButtplugPingError),
218 #[error(transparent)]
219 ButtplugDeviceError(#[from] ButtplugDeviceError),
220 #[error(transparent)]
221 ButtplugUnknownError(#[from] ButtplugUnknownError),
222}
223
224impl From<message::ErrorV0> for ButtplugError {
225 /// Turns a Buttplug Protocol Error Message [super::messages::Error] into a [ButtplugError] type.
226 fn from(error: message::ErrorV0) -> Self {
227 match error.error_code() {
228 ErrorCode::ErrorDevice => {
229 ButtplugDeviceError::UntypedDeserializedError(error.error_message().clone()).into()
230 }
231 ErrorCode::ErrorMessage => {
232 ButtplugMessageError::UntypedDeserializedError(error.error_message().clone()).into()
233 }
234 ErrorCode::ErrorHandshake => {
235 ButtplugHandshakeError::UntypedDeserializedError(error.error_message().clone()).into()
236 }
237 ErrorCode::ErrorUnknown => {
238 ButtplugUnknownError::UntypedDeserializedError(error.error_message().clone()).into()
239 }
240 ErrorCode::ErrorPing => {
241 ButtplugPingError::UntypedDeserializedError(error.error_message().clone()).into()
242 }
243 }
244 }
245}