diff --git a/Cargo.lock b/Cargo.lock index 916b426..7724c15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -944,9 +944,11 @@ dependencies = [ "etherparse", "futures-util", "log", + "mime_guess", "pcap", "pretty_env_logger", "rtpeeker_common", + "rust-embed", "tokio", "tokio-stream", "warp", @@ -965,6 +967,40 @@ dependencies = [ "webrtc-util 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rust-embed" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e7d90385b59f0a6bf3d3b757f3ca4ece2048265d70db20a2016043d4509a40" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3d8c6fd84090ae348e63a84336b112b5c3918b3bf0493a581f7bd8ee623c29" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "873feff8cb7bf86fdf0a71bb21c95159f4e4a37dd7a4bd1855a940909b583ada" +dependencies = [ + "sha2", + "walkdir", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -986,6 +1022,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -1052,6 +1097,17 @@ dependencies = [ "digest", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -1346,6 +1402,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" diff --git a/Cargo.toml b/Cargo.toml index 2979349..af18bf2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,5 +14,7 @@ futures-util = "0.3" pcap = "1.0.0" etherparse = "0.13.0" clap = { version = "4", features = ["derive"] } +rust-embed = "8.0.0" +mime_guess = "2.0.4" # not using workspaces, as the crates use different targets diff --git a/build.rs b/build.rs index 57f066d..27a5968 100644 --- a/build.rs +++ b/build.rs @@ -1,11 +1,17 @@ use std::env; +use std::process::Command; fn main() { let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); - let out_dir = env::var("OUT_DIR").unwrap(); - println!("MANIFEST_DIR: {:?}", manifest_dir); - println!("OUT_DIR: {:?}", out_dir); + // TODO: in theory we shouldn't modify files outside of OUT_DIR + // but oh well + Command::new("trunk") + .args(["build", "--release", "--dist"]) + .arg(&format!("{}/client/dist", manifest_dir)) + .arg(&format!("{}/client/index.html", manifest_dir)) + .status() + .unwrap(); - panic!(); + println!("cargo:rerun-if-changed=client"); } diff --git a/src/server.rs b/src/server.rs index 918d7c6..2f65256 100644 --- a/src/server.rs +++ b/src/server.rs @@ -7,6 +7,7 @@ use log::{error, info, warn}; use rtpeeker_common::packet::SessionProtocol; use rtpeeker_common::Source; use rtpeeker_common::{Request, Response}; +use rust_embed::RustEmbed; use std::collections::HashMap; use std::net::SocketAddr; use std::sync::{ @@ -15,12 +16,16 @@ use std::sync::{ }; use tokio::sync::{mpsc, mpsc::Sender, RwLock}; use warp::ws::{Message, WebSocket}; -use warp::Filter; +use warp::{http::header::HeaderValue, path::Tail, reply}; +use warp::{Filter, Rejection, Reply}; -const DIST_DIR: &str = "client/dist"; const WS_PATH: &str = "ws"; static NEXT_CLIENT_ID: AtomicUsize = AtomicUsize::new(1); +#[derive(RustEmbed)] +#[folder = "client/dist"] +struct Asset; + struct Client { pub sender: mpsc::Sender, pub source: Option, @@ -82,12 +87,35 @@ pub async fn run( ws.on_upgrade(move |socket| client_connected(socket, clients_cl, source_to_packets_cl)) }); - let routes = ws.or(warp::fs::dir(DIST_DIR)); + let index_html = warp::path::end().and_then(serve_index); + let other = warp::path::tail().and_then(serve); + + let routes = ws.or(index_html).or(other); println!("RTPeeker running on http://{}/", addr); warp::serve(routes).run(addr).await; } +async fn serve_index() -> Result { + serve_impl("index.html").await +} + +async fn serve(path: Tail) -> Result { + serve_impl(path.as_str()).await +} + +async fn serve_impl(path: &str) -> Result { + let asset = Asset::get(path).ok_or_else(warp::reject::not_found)?; + let mime = mime_guess::from_path(path).first_or_octet_stream(); + + let mut res = reply::Response::new(asset.data.into()); + res.headers_mut().insert( + "content-type", + HeaderValue::from_str(mime.as_ref()).unwrap(), + ); + Ok(res) +} + async fn client_connected(ws: WebSocket, clients: Clients, source_to_packets: PacketsMap) { let client_id = NEXT_CLIENT_ID.fetch_add(1, Ordering::Relaxed);