Added JS client
This commit is contained in:
@@ -18,6 +18,7 @@ use d3270_common::b3270::operation::Action;
|
||||
pub mod arbiter;
|
||||
pub mod gen_connection;
|
||||
pub mod tcp_server;
|
||||
pub mod ws_server;
|
||||
|
||||
struct TaggedJoinHandle {
|
||||
handle: JoinHandle<anyhow::Error>,
|
||||
@@ -65,6 +66,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
let mut args_iter = std::env::args_os().peekable();
|
||||
let mut connect_str = None;
|
||||
let mut tcp_listen = None;
|
||||
let mut http_listen = None;
|
||||
|
||||
args_iter.next(); // skip program name.
|
||||
|
||||
@@ -94,7 +96,17 @@ async fn main() -> anyhow::Result<()> {
|
||||
.map_err(|_| anyhow!("Failed to parse tcp-listen address"))?
|
||||
.parse()
|
||||
.map(Some)
|
||||
.map_err(|_| anyhow!("Invalid listen address"))?;
|
||||
.map_err(|_| anyhow!("Failed to parse tcp-listen address"))?;
|
||||
}
|
||||
"-http-listen" => {
|
||||
http_listen = args_iter
|
||||
.next()
|
||||
.ok_or_else(|| anyhow!("Arg required for -http-listen"))?
|
||||
.into_string()
|
||||
.map_err(|_| anyhow!("Failed to parse http-listen address"))?
|
||||
.parse()
|
||||
.map(Some)
|
||||
.map_err(|_| anyhow!("Failed to parse http-listen address"))?;
|
||||
}
|
||||
"-e" => {
|
||||
'skip: while let Some(arg) = args_iter.peek() {
|
||||
@@ -131,6 +143,10 @@ async fn main() -> anyhow::Result<()> {
|
||||
let tcp_listener = tcp_server::listener_proc(addr, arbiter_req.clone()).await?;
|
||||
handles.push(tcp_listener.tagged("tcp_listener"));
|
||||
}
|
||||
if let Some(addr) = http_listen {
|
||||
let ws_listener = ws_server::start_ws_server(addr, arbiter_req.clone()).await?;
|
||||
handles.push(ws_listener.tagged("ws_server"));
|
||||
}
|
||||
let ((source, error), _, _) = select_all(handles).await;
|
||||
error!(source, %error, "A core task failed");
|
||||
|
||||
|
||||
53
d3270d/src/ws_server.rs
Normal file
53
d3270d/src/ws_server.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
use std::net::SocketAddr;
|
||||
use anyhow::anyhow;
|
||||
use tide::prelude::*;
|
||||
use tide::Request;
|
||||
use tide_websockets::{WebSocketConnection, self as ws};
|
||||
use tokio::select;
|
||||
use tokio::task::JoinHandle;
|
||||
use crate::arbiter::ArbiterHandleRequester;
|
||||
use crate::gen_connection::GenConnection;
|
||||
use futures::stream::StreamExt;
|
||||
use tracing::{info, warn};
|
||||
use d3270_common::b3270::Indication;
|
||||
|
||||
pub async fn start_ws_server(socket: SocketAddr, handle_requester: ArbiterHandleRequester, ) -> anyhow::Result<JoinHandle<anyhow::Error>> {
|
||||
let mut app = tide::Server::with_state(handle_requester);
|
||||
app.with(tide_tracing::TraceMiddleware::new());
|
||||
app.at("/api/ws").get(tide_websockets::WebSocket::new(handle_websocket));
|
||||
|
||||
let mut listener = app.bind(socket.clone()).await?;
|
||||
Ok(tokio::task::spawn(async move {
|
||||
info!(%socket, "Starting HTTP server");
|
||||
listener.accept().await
|
||||
.map(|()| anyhow!("HTTP server returned early"))
|
||||
.unwrap_or_else(Into::into)
|
||||
}))
|
||||
}
|
||||
|
||||
async fn handle_websocket(req: Request<ArbiterHandleRequester>, mut ws: WebSocketConnection) -> tide::Result<()> {
|
||||
let mut arbiter = GenConnection::new(req.state().clone()).await?;
|
||||
|
||||
// TODO: do authenticatey things
|
||||
|
||||
'main: loop {
|
||||
select! {
|
||||
msg = ws.next() => {
|
||||
let msg: ws::Message = if let Some(msg) = msg { msg? } else { break 'main; };
|
||||
match msg {
|
||||
ws::Message::Text(text) => arbiter.handle_client_line(text).await?,
|
||||
ws::Message::Binary(_) => warn!("Unexpected binary message from client"),
|
||||
ws::Message::Ping(data) => ws.send(ws::Message::Pong(data)).await?,
|
||||
ws::Message::Close(_) => break 'main,
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
msg = arbiter.next_indication() => {
|
||||
let msg: Indication = if let Some(msg) = msg { msg } else { break 'main; };
|
||||
ws.send_json(&msg).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user