|
|
@ -1,25 +1,11 @@ |
|
|
use crossbeam_channel;
|
|
|
|
|
|
use solstice_proto::config;
|
|
|
use solstice_proto::config;
|
|
|
use thiserror::Error;
|
|
|
use thiserror::Error;
|
|
|
|
|
|
use tokio::sync::mpsc;
|
|
|
use ws;
|
|
|
use ws;
|
|
|
|
|
|
|
|
|
use super::request::*;
|
|
|
|
|
|
use super::response::*;
|
|
|
|
|
|
|
|
|
|
|
|
/// This enum contains the possible notifications that the control loop will
|
|
|
|
|
|
/// send to the client.
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
|
pub enum Notification {
|
|
|
|
|
|
/// A new controller has connected: control messages can now be sent on the
|
|
|
|
|
|
/// given channel.
|
|
|
|
|
|
Connected(Sender),
|
|
|
|
|
|
/// The controller has disconnected.
|
|
|
|
|
|
Disconnected,
|
|
|
|
|
|
/// An irretrievable error has arisen.
|
|
|
|
|
|
Error(String),
|
|
|
|
|
|
/// The controller has sent a request.
|
|
|
|
|
|
Request(Request),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
use crate::control::request::*;
|
|
|
|
|
|
use crate::control::response::*;
|
|
|
|
|
|
use crate::dispatcher::Message;
|
|
|
|
|
|
|
|
|
/// This error is returned when a `Sender` fails to send a control request.
|
|
|
/// This error is returned when a `Sender` fails to send a control request.
|
|
|
#[derive(Debug, Error)]
|
|
|
#[derive(Debug, Error)]
|
|
|
@ -50,37 +36,32 @@ impl Sender { |
|
|
/// This struct handles a single websocket connection.
|
|
|
/// This struct handles a single websocket connection.
|
|
|
#[derive(Debug)]
|
|
|
#[derive(Debug)]
|
|
|
struct Handler {
|
|
|
struct Handler {
|
|
|
/// The channel on which to send notifications to the client.
|
|
|
|
|
|
client_tx: crossbeam_channel::Sender<Notification>,
|
|
|
|
|
|
|
|
|
/// The channel on which to send requests to the client.
|
|
|
|
|
|
client_tx: mpsc::UnboundedSender<Message>,
|
|
|
/// The channel on which to send messages to the controller.
|
|
|
/// The channel on which to send messages to the controller.
|
|
|
socket_tx: ws::Sender,
|
|
|
socket_tx: ws::Sender,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
impl Handler {
|
|
|
impl Handler {
|
|
|
fn send_to_client(&self, notification: Notification) -> ws::Result<()> {
|
|
|
|
|
|
match self.client_tx.send(notification) {
|
|
|
|
|
|
Ok(()) => Ok(()),
|
|
|
|
|
|
Err(e) => {
|
|
|
|
|
|
error!("Error sending notification to client: {}", e);
|
|
|
|
|
|
Err(ws::Error::new(ws::ErrorKind::Internal, ""))
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
fn send_to_client(&self, request: Request) -> ws::Result<()> {
|
|
|
|
|
|
self
|
|
|
|
|
|
.client_tx
|
|
|
|
|
|
.send(Message::ControlRequest(request))
|
|
|
|
|
|
.map_err(|err| {
|
|
|
|
|
|
error!("Error sending notification to client: {}", err);
|
|
|
|
|
|
ws::Error::new(ws::ErrorKind::Internal, "")
|
|
|
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
impl ws::Handler for Handler {
|
|
|
impl ws::Handler for Handler {
|
|
|
fn on_open(&mut self, _: ws::Handshake) -> ws::Result<()> {
|
|
|
fn on_open(&mut self, _: ws::Handshake) -> ws::Result<()> {
|
|
|
info!("Websocket open");
|
|
|
info!("Websocket open");
|
|
|
self.send_to_client(Notification::Connected(Sender {
|
|
|
|
|
|
sender: self.socket_tx.clone(),
|
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
fn on_close(&mut self, code: ws::CloseCode, reason: &str) {
|
|
|
fn on_close(&mut self, code: ws::CloseCode, reason: &str) {
|
|
|
info!("Websocket closed: code: {:?}, reason: {:?}", code, reason);
|
|
|
info!("Websocket closed: code: {:?}, reason: {:?}", code, reason);
|
|
|
self
|
|
|
|
|
|
.send_to_client(Notification::Disconnected)
|
|
|
|
|
|
.unwrap_or(())
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
fn on_message(&mut self, msg: ws::Message) -> ws::Result<()> {
|
|
|
fn on_message(&mut self, msg: ws::Message) -> ws::Result<()> {
|
|
|
@ -108,13 +89,16 @@ impl ws::Handler for Handler { |
|
|
debug!("Received control request: {:?}", control_request);
|
|
|
debug!("Received control request: {:?}", control_request);
|
|
|
|
|
|
|
|
|
// Send the control request to the client.
|
|
|
// Send the control request to the client.
|
|
|
self.send_to_client(Notification::Request(control_request))
|
|
|
|
|
|
|
|
|
self.send_to_client(control_request)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
/// Start listening on the socket address stored in configuration, and send
|
|
|
/// Start listening on the socket address stored in configuration, and send
|
|
|
/// control notifications to the client through the given channel.
|
|
|
/// control notifications to the client through the given channel.
|
|
|
pub fn listen(client_tx: crossbeam_channel::Sender<Notification>) {
|
|
|
|
|
|
|
|
|
pub fn listen(
|
|
|
|
|
|
client_tx: mpsc::UnboundedSender<Message>,
|
|
|
|
|
|
socket_rx: mpsc::Receiver<Response>,
|
|
|
|
|
|
) {
|
|
|
let websocket_result = ws::Builder::new()
|
|
|
let websocket_result = ws::Builder::new()
|
|
|
.with_settings(ws::Settings {
|
|
|
.with_settings(ws::Settings {
|
|
|
max_connections: 1,
|
|
|
max_connections: 1,
|
|
|
@ -129,16 +113,14 @@ pub fn listen(client_tx: crossbeam_channel::Sender<Notification>) { |
|
|
Ok(websocket) => websocket,
|
|
|
Ok(websocket) => websocket,
|
|
|
Err(e) => {
|
|
|
Err(e) => {
|
|
|
error!("Unable to build websocket: {}", e);
|
|
|
error!("Unable to build websocket: {}", e);
|
|
|
client_tx
|
|
|
|
|
|
.send(Notification::Error(format!(
|
|
|
|
|
|
"Unable to build websocket: {}",
|
|
|
|
|
|
e
|
|
|
|
|
|
)))
|
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
return;
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: Read responses off `socket_rx` and send them on `client_tx`. When
|
|
|
|
|
|
// the channel is closed, we should stop listening. In the meantime, we can
|
|
|
|
|
|
// at least spawn a task to pass along the responses.
|
|
|
|
|
|
|
|
|
let listen_result =
|
|
|
let listen_result =
|
|
|
websocket.listen((config::CONTROL_HOST, config::CONTROL_PORT));
|
|
|
websocket.listen((config::CONTROL_HOST, config::CONTROL_PORT));
|
|
|
|
|
|
|
|
|
@ -146,12 +128,6 @@ pub fn listen(client_tx: crossbeam_channel::Sender<Notification>) { |
|
|
Ok(_) => (),
|
|
|
Ok(_) => (),
|
|
|
Err(e) => {
|
|
|
Err(e) => {
|
|
|
error!("Unable to listen on websocket: {}", e);
|
|
|
error!("Unable to listen on websocket: {}", e);
|
|
|
client_tx
|
|
|
|
|
|
.send(Notification::Error(format!(
|
|
|
|
|
|
"Unable to listen on websocket: {}",
|
|
|
|
|
|
e
|
|
|
|
|
|
)))
|
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|