diff options
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 145 |
1 files changed, 46 insertions, 99 deletions
diff --git a/src/main.rs b/src/main.rs index cafc9d4..b3c3cf9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,33 +1,21 @@ -#[macro_use] extern crate anyhow; - -pub use anyhow::{ Result, Error }; - use std::{ convert::Infallible, collections::HashMap, + error::Error, net::SocketAddr, - sync::Arc, }; +use warp::Filter; mod types; mod conn; mod minesweeper; use types::*; -use hyper::{ Body, Request, Server }; -use hyper::server::conn::{ AddrStream, AddrIncoming }; -use hyper::service::{make_service_fn, service_fn, Service}; use tokio::sync::RwLock; -use std::fs; - -use futures_util::{future, pin_mut, ready, stream::TryStreamExt, StreamExt, sink::SinkExt, TryFutureExt}; -use hyper_tungstenite::{ tungstenite::protocol::Message, HyperWebsocket }; -use tokio_rustls::{ rustls, Accept, server::TlsStream, TlsAcceptor }; -use rustls::{ServerConnection, SupportedCipherSuite, ProtocolVersion, ServerConfig, - Certificate, PrivateKey}; +const FONT_FILE: &[u8] = include_bytes!("./VT323-Regular.ttf"); -fn main() -> Result<()> { +fn main() -> Result<(), Box<dyn Error>> { let conf = Config { cert_path: "./cert.pem".to_owned(), pkey_path: "./cert.rsa".to_owned(), @@ -40,91 +28,59 @@ fn main() -> Result<()> { peers: PeerMap::new(RwLock::new(HashMap::new())), }; - let cert_pem = fs::read(&state.conf.cert_path)?; - let pkey_pem = fs::read(&state.conf.pkey_path)?; + tokio_main(state) +} - // Build TLS configuration. - let tls_cfg = { - let certs: Vec<Certificate> = rustls_pemfile::certs(&mut &*cert_pem) - .map(|mut certs| certs.drain(..).map(Certificate).collect())?; - if certs.len() < 1 { - return Err(anyhow!("No certificates found")); - } - let mut keys: Vec<PrivateKey> = rustls_pemfile::rsa_private_keys(&mut &*pkey_pem) - .map(|mut keys| keys.drain(..).map(PrivateKey).collect())?; - if keys.len() < 1 { - return Err(anyhow!("No private keys found")); - } +#[tokio::main] +async fn tokio_main(state: State) -> Result<(), Box<dyn Error>> { + // Start the temporary single lobby + let (cmd_tx, cmd_rx) = tokio::sync::mpsc::unbounded_channel(); + let _game_t = tokio::spawn(gameloop(cmd_rx, state.peers.clone())); - let mut tls_cfg = ServerConfig::builder() - .with_safe_defaults() - .with_no_client_auth() - .with_single_cert(certs, keys.remove(0))?; + let cmd_filter = warp::any().map(move || cmd_tx.clone()); - // Configure ALPN to accept HTTP/2, HTTP/1.1 in that order. - tls_cfg.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()]; - tls_cfg + let page_route = { + use warp::*; + get() + .and(path("font.ttf")) + .map(|| FONT_FILE) + .or(fs::file(state.conf.page_path.clone())) }; - tokio_main(state, tls_cfg) -} + let websocket_route = { + let state = state.clone(); + use warp::*; + path("ws") + .and(ws()) + .and(addr::remote()) + .and(cmd_filter) + .map(move |ws: warp::ws::Ws, saddr: Option<SocketAddr>, cmd_tx: CmdTx| { + let state = state.clone(); + println!("conn from {saddr:?}"); + ws.on_upgrade(move |socket| { + let conn_data = types::ConnData { remote_addr: saddr.unwrap(), cmd_tx: cmd_tx.clone(), peers: state.peers.clone() }; + conn::peer_connection(socket, conn_data) + }) + }) + }; + let routes = websocket_route.or(page_route); -#[tokio::main] -async fn tokio_main(state: State, tls_conf: ServerConfig) -> Result<()> { - let server = main_server(state.clone(), tls_conf); + let server = warp::serve(routes) + .tls() + .cert_path(state.conf.cert_path) + .key_path(state.conf.pkey_path) + .run(state.conf.socket_addr); println!("Serving on {}", state.conf.socket_addr); - server.await?; + server.await; Ok(()) } -async fn main_server(state: State, tls_conf: ServerConfig) -> Result<()> { - // Create a TCP listener, that uses TLS - let listener = tokio::net::TcpListener::bind(&state.conf.socket_addr).await?; - let local_addr = listener.local_addr()?; - let acceptor = tokio_rustls::TlsAcceptor::from(Arc::new(tls_conf)); - let http = hyper::server::conn::Http::new(); - - // Start the temporary single lobby - let (cmd_tx, cmd_rx) = futures::channel::mpsc::unbounded(); - let game_t = tokio::spawn(gameloop(cmd_rx, state.peers.clone())); - - loop { - let (conn, remote_addr) = listener.accept().await?; - let acceptor = acceptor.clone(); - let http = http.clone(); - let cloned_state = state.clone(); - let cmd_tx = cmd_tx.clone(); - let fut = async move { - match acceptor.accept(conn).await { - Ok(stream) => { - let page = tokio::fs::read_to_string(&cloned_state.conf.page_path).await; - if let Err(e) = page { return Err(anyhow!("couldn't read page file: {e}")); } - - let handler = conn::PerConnHandler { - state: cloned_state, - local_addr, - remote_addr, - game_cmd_tx: cmd_tx, - page: page.unwrap(), - }; - if let Err(e) = http.serve_connection(stream, handler).await { - eprintln!("hyper error for {remote_addr}: {e}"); - } - }, - Err(e) => eprintln!("TLS error for {remote_addr}: {e}"), - } - Ok(()) - }; - tokio::spawn(fut); - } -} - // If a move is made, broadcast new board, else just send current board -async fn gameloop(mut move_rx: futures::channel::mpsc::UnboundedReceiver<MetaMove>, peers: PeerMap) { +async fn gameloop(mut move_rx: tokio::sync::mpsc::UnboundedReceiver<MetaMove>, peers: PeerMap) { use minesweeper::*; let mut game = Game::new(Board::new(75,35), (75*35)/8); let mut latest_player_name = None; - while let Some(req) = move_rx.next().await { + while let Some(req) = move_rx.recv().await { let done = game.phase == Phase::Die || game.phase == Phase::Win; match req { MetaMove::Move(m, o) => if !done { @@ -137,6 +93,7 @@ async fn gameloop(mut move_rx: futures::channel::mpsc::UnboundedReceiver<MetaMov MetaMove::Dump => (), MetaMove::Reset => { game = Game::new(Board::new(75,35), (75*35)/8); }, } + use warp::ws::Message; let mut reply = vec![Message::binary(game.board.render())]; let lpname = latest_player_name.as_ref().map(|s| s.as_str()).unwrap_or("unknown player"); match game.phase { @@ -148,21 +105,11 @@ async fn gameloop(mut move_rx: futures::channel::mpsc::UnboundedReceiver<MetaMov let peers = peers.read().await; for (addr, p) in peers.iter() { for r in reply.iter() { - if let Err(e) = p.tx.unbounded_send(r.clone()) { - println!("couldn't send game update {r} to {addr}: {e}"); + if let Err(e) = p.tx.send(r.clone()) { + println!("couldn't send game update {r:?} to {addr}: {e}"); } } } } } } - -fn error(err: String) -> std::io::Error { - std::io::Error::new(std::io::ErrorKind::Other, err) -} - -async fn shutdown_signal() { - tokio::signal::ctrl_c() - .await - .expect("failed to install CTRL+C signal handler"); -} |