use crate::{
connector::{
transport::{
ButtplugConnectorTransport,
ButtplugConnectorTransportConnectResult,
ButtplugConnectorTransportSpecificError,
ButtplugTransportMessage,
},
ButtplugConnectorError,
ButtplugConnectorResultFuture,
},
core::messages::serializer::ButtplugSerializedMessage,
util::async_manager,
};
use async_channel::bounded;
use async_tungstenite::{
async_std::connect_async_with_tls_connector,
tungstenite::protocol::Message,
};
use futures::{future, SinkExt, StreamExt};
pub struct ButtplugWebsocketClientTransport {
address: String,
should_use_tls: bool,
bypass_cert_verify: bool,
}
impl ButtplugWebsocketClientTransport {
pub fn new_insecure_connector(address: &str) -> Self {
Self {
should_use_tls: false,
address: address.to_owned(),
bypass_cert_verify: false,
}
}
pub fn new_secure_connector(address: &str, bypass_cert_verify: bool) -> Self {
Self {
should_use_tls: true,
address: address.to_owned(),
bypass_cert_verify,
}
}
}
impl ButtplugConnectorTransport for ButtplugWebsocketClientTransport {
fn connect(&self) -> ButtplugConnectorTransportConnectResult {
let (request_sender, request_receiver) = bounded(256);
let (response_sender, response_receiver) = bounded(256);
let tls_connector = if self.should_use_tls {
use async_tls::TlsConnector;
if self.bypass_cert_verify {
use rustls::ClientConfig;
use std::sync::Arc;
pub struct NoCertificateVerification {}
impl rustls::ServerCertVerifier for NoCertificateVerification {
fn verify_server_cert(
&self,
_roots: &rustls::RootCertStore,
_presented_certs: &[rustls::Certificate],
_dns_name: webpki::DNSNameRef<'_>,
_ocsp: &[u8],
) -> Result<rustls::ServerCertVerified, rustls::TLSError> {
Ok(rustls::ServerCertVerified::assertion())
}
}
let mut config = ClientConfig::new();
config
.dangerous()
.set_certificate_verifier(Arc::new(NoCertificateVerification {}));
Some(TlsConnector::from(Arc::new(config)))
} else {
Some(TlsConnector::new())
}
} else {
None
};
let address = self.address.clone();
Box::pin(async move {
match connect_async_with_tls_connector(&address, tls_connector).await {
Ok((stream, _)) => {
let (mut writer, mut reader) = stream.split();
async_manager::spawn(async move {
while let Ok(msg) = request_receiver.recv().await {
let out_msg = match msg {
ButtplugSerializedMessage::Text(text) => Message::Text(text),
ButtplugSerializedMessage::Binary(bin) => Message::Binary(bin),
};
writer.send(out_msg).await.expect("This should never fail?");
}
})
.unwrap();
async_manager::spawn(async move {
while let Some(response) = reader.next().await {
trace!("Websocket receiving: {:?}", response);
match response.unwrap() {
Message::Text(t) => {
if response_sender
.send(ButtplugTransportMessage::Message(
ButtplugSerializedMessage::Text(t.to_string()),
))
.await
.is_err()
{
error!("Websocket holder has closed, exiting websocket loop.");
return;
}
}
Message::Binary(v) => {
if response_sender
.send(ButtplugTransportMessage::Message(
ButtplugSerializedMessage::Binary(v),
))
.await
.is_err()
{
error!("Websocket holder has closed, exiting websocket loop.");
return;
}
}
Message::Ping(_) => {}
Message::Pong(_) => {}
Message::Close(_) => {
info!("Websocket has requested close.");
return;
}
}
}
})
.unwrap();
Ok((request_sender, response_receiver))
}
Err(websocket_error) => Err(ButtplugConnectorError::TransportSpecificError(
ButtplugConnectorTransportSpecificError::TungsteniteError(websocket_error),
)),
}
})
}
fn disconnect(self) -> ButtplugConnectorResultFuture {
Box::pin(future::ready(Ok(())))
}
}