use super::{
connectors::{
ButtplugClientConnectionStateShared, ButtplugClientConnector, ButtplugClientConnectorError,
},
device::ButtplugClientDevice,
ButtplugClientEvent, ButtplugClientResult,
};
use crate::{
core::messages::{ButtplugClientOutMessage, DeviceList, DeviceMessageInfo},
util::future::{ButtplugFutureStateShared, ButtplugMessageFuturePair},
};
use async_std::{
prelude::{FutureExt, StreamExt},
sync::{channel, Receiver, Sender},
};
use std::collections::HashMap;
pub enum ButtplugClientMessage {
Connect(
Box<dyn ButtplugClientConnector>,
ButtplugClientConnectionStateShared,
),
Disconnect(ButtplugClientConnectionStateShared),
HandleDeviceList(DeviceList),
RequestDeviceList(ButtplugFutureStateShared<Vec<ButtplugClientDevice>>),
Message(ButtplugMessageFuturePair),
}
pub enum ButtplugClientDeviceEvent {
DeviceDisconnect,
ClientDisconnect,
Message(ButtplugClientOutMessage),
}
enum StreamReturn {
ConnectorMessage(ButtplugClientOutMessage),
ClientMessage(ButtplugClientMessage),
DeviceMessage(ButtplugMessageFuturePair),
Disconnect,
}
struct ButtplugClientEventLoop {
devices: HashMap<u32, DeviceMessageInfo>,
device_message_sender: Sender<ButtplugMessageFuturePair>,
device_message_receiver: Receiver<ButtplugMessageFuturePair>,
device_event_senders: HashMap<u32, Vec<Sender<ButtplugClientDeviceEvent>>>,
event_sender: Sender<ButtplugClientEvent>,
client_receiver: Receiver<ButtplugClientMessage>,
connector: Box<dyn ButtplugClientConnector>,
connector_receiver: Receiver<ButtplugClientOutMessage>,
}
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::<ButtplugMessageFuturePair>(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: ButtplugClientOutMessage) {
info!("Sending message to clients.");
match &msg {
ButtplugClientOutMessage::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;
}
ButtplugClientOutMessage::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;
}
}
ButtplugClientOutMessage::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(())
}