Added JS client

This commit is contained in:
2023-05-12 20:58:50 +02:00
parent 797dba0efb
commit 4e891ce3a4
15 changed files with 1587 additions and 1 deletions

View File

@@ -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
View 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(())
}