use super::{
connectors::{
ButtplugClientConnectionStateShared, ButtplugClientConnector, ButtplugClientConnectorError,
},
device::ButtplugClientDevice,
ButtplugClientEvent, ButtplugClientResult,
};
use crate::core::messages::{ButtplugMessageUnion, DeviceList, DeviceMessageInfo};
use async_std::{
future::Future,
prelude::{FutureExt, StreamExt},
sync::{channel, Receiver, Sender},
task::{Context, Poll, Waker},
};
use core::pin::Pin;
use std::{
collections::HashMap,
sync::{Arc, Mutex},
};
#[derive(Debug, Clone)]
pub struct ButtplugClientFutureState<T> {
reply_msg: Option<T>,
waker: Option<Waker>,
}
impl<T> Default for ButtplugClientFutureState<T> {
fn default() -> Self {
ButtplugClientFutureState::<T> {
reply_msg: None,
waker: None,
}
}
}
impl<T> ButtplugClientFutureState<T> {
pub fn set_reply(&mut self, reply: T) {
if self.reply_msg.is_some() {
panic!("set_reply_msg called multiple times on the same future.");
}
self.reply_msg = Some(reply);
if self.waker.is_some() {
self.waker.take().unwrap().wake();
}
}
}
pub type ButtplugClientFutureStateShared<T> = Arc<Mutex<ButtplugClientFutureState<T>>>;
#[derive(Debug)]
pub struct ButtplugClientFuture<T> {
waker_state: ButtplugClientFutureStateShared<T>,
}
impl<T> Default for ButtplugClientFuture<T> {
fn default() -> Self {
ButtplugClientFuture::<T> {
waker_state: ButtplugClientFutureStateShared::<T>::default(),
}
}
}
impl<T> ButtplugClientFuture<T> {
pub fn get_state_clone(&self) -> ButtplugClientFutureStateShared<T> {
self.waker_state.clone()
}
}
impl<T> Future for ButtplugClientFuture<T> {
type Output = T;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let mut waker_state = self.waker_state.lock().unwrap();
if waker_state.reply_msg.is_some() {
let msg = waker_state.reply_msg.take().unwrap();
Poll::Ready(msg)
} else {
debug!("Waker set.");
waker_state.waker = Some(cx.waker().clone());
Poll::Pending
}
}
}
pub type ButtplugClientMessageState = ButtplugClientFutureState<ButtplugMessageUnion>;
pub type ButtplugClientMessageStateShared = ButtplugClientFutureStateShared<ButtplugMessageUnion>;
pub type ButtplugClientMessageFuture = ButtplugClientFuture<ButtplugMessageUnion>;
pub type ButtplugClientMessageFuturePair = (ButtplugMessageUnion, ButtplugClientMessageStateShared);
pub enum ButtplugClientMessage {
Connect(
Box<dyn ButtplugClientConnector>,
ButtplugClientConnectionStateShared,
),
Disconnect(ButtplugClientConnectionStateShared),
HandleDeviceList(DeviceList),
RequestDeviceList(ButtplugClientFutureStateShared<Vec<ButtplugClientDevice>>),
Message(ButtplugClientMessageFuturePair),
}
pub enum ButtplugClientDeviceEvent {
DeviceDisconnect,
ClientDisconnect,
Message(ButtplugMessageUnion),
}
enum StreamReturn {
ConnectorMessage(ButtplugMessageUnion),
ClientMessage(ButtplugClientMessage),
DeviceMessage(ButtplugClientMessageFuturePair),
Disconnect,
}
struct ButtplugClientEventLoop {
devices: HashMap<u32, DeviceMessageInfo>,
device_message_sender: Sender<ButtplugClientMessageFuturePair>,
device_message_receiver: Receiver<ButtplugClientMessageFuturePair>,
device_event_senders: HashMap<u32, Vec<Sender<ButtplugClientDeviceEvent>>>,
event_sender: Sender<ButtplugClientEvent>,
client_receiver: Receiver<ButtplugClientMessage>,
connector: Box<dyn ButtplugClientConnector>,
connector_receiver: Receiver<ButtplugMessageUnion>,
}
impl ButtplugClientEventLoop {
pub async fn wait_for_connector(
event_sender: Sender<ButtplugClientEvent>,
mut client_receiver: Receiver<ButtplugClientMessage>,
) -> Result<Self, ButtplugClientConnectorError> {
match client_receiver.next().await {
None => {
debug!("Client disconnected.");
Err(ButtplugClientConnectorError::new(
"Client was dropped during connect.",
))
}
Some(msg) => match msg {
ButtplugClientMessage::Connect(mut connector, state) => {
match connector.connect().await {
Err(err) => {
error!("Cannot connect to server: {}", err.message);
let mut waker_state = state.lock().unwrap();
let reply = Err(ButtplugClientConnectorError::new(&format!(
"Cannot connect to server: {}",
err.message
)));
waker_state.set_reply(reply);
Err(ButtplugClientConnectorError::new(
"Client couldn't connect to server.",
))
}
Ok(_) => {
info!("Connected!");
let mut waker_state = state.lock().unwrap();
waker_state.set_reply(Ok(()));
let (device_message_sender, device_message_receiver) = channel(256);
Ok(ButtplugClientEventLoop {
devices: HashMap::new(),
device_event_senders: HashMap::new(),
device_message_sender,
device_message_receiver,
event_sender,
client_receiver,
connector_receiver: connector.get_event_receiver(),
connector,
})
}
}
}
_ => {
error!("Received non-connector message before connector message.");
Err(ButtplugClientConnectorError::new(
"Event Loop did not receive Connect message first.",
))
}
},
}
}
fn create_client_device(&mut self, info: &DeviceMessageInfo) -> ButtplugClientDevice {
let (event_sender, event_receiver) = channel(256);
self.device_event_senders
.entry(info.device_index)
.or_insert_with(|| vec![])
.push(event_sender);
ButtplugClientDevice::from((info, self.device_message_sender.clone(), event_receiver))
}
async fn parse_connector_message(&mut self, msg: ButtplugMessageUnion) {
info!("Sending message to clients.");
match &msg {
ButtplugMessageUnion::DeviceAdded(dev) => {
let info = DeviceMessageInfo::from(dev);
let device = self.create_client_device(&info);
self.devices.insert(dev.device_index, info);
self.event_sender
.send(ButtplugClientEvent::DeviceAdded(device))
.await;
}
ButtplugMessageUnion::DeviceList(dev) => {
for d in &dev.devices {
let device = self.create_client_device(&d);
self.devices.insert(d.device_index, d.clone());
self.event_sender
.send(ButtplugClientEvent::DeviceAdded(device))
.await;
}
}
ButtplugMessageUnion::DeviceRemoved(dev) => {
let info = self.devices.remove(&dev.device_index);
self.device_event_senders.remove(&dev.device_index);
self.event_sender
.send(ButtplugClientEvent::DeviceRemoved(info.unwrap()))
.await;
}
_ => panic!("Got connector message type we don't know how to handle!"),
}
}
async fn parse_client_message(&mut self, msg: ButtplugClientMessage) -> bool {
debug!("Parsing a client message.");
match msg {
ButtplugClientMessage::Message(msg_fut) => {
debug!("Sending message through connector.");
self.connector.send(&msg_fut.0, &msg_fut.1).await;
true
}
ButtplugClientMessage::Disconnect(state) => {
info!("Client requested disconnect");
let mut waker_state = state.lock().unwrap();
waker_state.set_reply(self.connector.disconnect().await);
false
}
ButtplugClientMessage::RequestDeviceList(fut) => {
info!("Building device list!");
let mut r = vec![];
let devices = self.devices.clone();
for d in devices.values() {
let dev = self.create_client_device(d);
r.push(dev);
}
info!("Returning device list of {} items!", r.len());
let mut waker_state = fut.lock().unwrap();
waker_state.set_reply(r);
info!("Finised setting waker!");
true
}
ButtplugClientMessage::HandleDeviceList(device_list) => {
info!("Handling device list!");
for d in &device_list.devices {
let device = self.create_client_device(&d);
self.devices.insert(d.device_index, d.clone());
self.event_sender
.send(ButtplugClientEvent::DeviceAdded(device))
.await;
}
true
}
_ => panic!("Client message not handled!"),
}
}
pub async fn run(&mut self) {
let mut client_receiver = self.client_receiver.clone();
let mut connector_receiver = self.connector_receiver.clone();
let mut device_receiver = self.device_message_receiver.clone();
loop {
let client_future = async {
match client_receiver.next().await {
None => {
debug!("Client disconnected.");
StreamReturn::Disconnect
}
Some(msg) => StreamReturn::ClientMessage(msg),
}
};
let event_future = async {
match connector_receiver.next().await {
None => {
debug!("Connector disconnected.");
StreamReturn::Disconnect
}
Some(msg) => StreamReturn::ConnectorMessage(msg),
}
};
let device_future = async {
match device_receiver.next().await {
None => {
panic!("We should never get here.");
}
Some(msg) => StreamReturn::DeviceMessage(msg),
}
};
let stream_fut = event_future.race(client_future).race(device_future);
match stream_fut.await {
StreamReturn::ConnectorMessage(msg) => self.parse_connector_message(msg).await,
StreamReturn::ClientMessage(msg) => {
if !self.parse_client_message(msg).await {
break;
}
}
StreamReturn::DeviceMessage(msg_fut) => {
self.connector.send(&msg_fut.0, &msg_fut.1).await;
}
StreamReturn::Disconnect => {
info!("Disconnected!");
break;
}
}
}
}
}
pub async fn client_event_loop(
event_sender: Sender<ButtplugClientEvent>,
client_receiver: Receiver<ButtplugClientMessage>,
) -> ButtplugClientResult {
info!("Starting client event loop.");
ButtplugClientEventLoop::wait_for_connector(event_sender, client_receiver)
.await?
.run()
.await;
info!("Exiting client event loop");
Ok(())
}