diff --git a/.idea/leptos-use.iml b/.idea/leptos-use.iml index 39d643e..31e4c90 100644 --- a/.idea/leptos-use.iml +++ b/.idea/leptos-use.iml @@ -54,6 +54,8 @@ + + @@ -115,6 +117,8 @@ + + diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 8a47395..9818f37 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -46,7 +46,8 @@ members = [ ] exclude = [ - "ssr" + "ssr", + "use_webtransport_with_server", ] [package] diff --git a/examples/use_webtransport_with_server/client/Cargo.toml b/examples/use_webtransport_with_server/client/Cargo.toml index f629f2d..5632fa1 100644 --- a/examples/use_webtransport_with_server/client/Cargo.toml +++ b/examples/use_webtransport_with_server/client/Cargo.toml @@ -1,14 +1,14 @@ [package] -name = "use_webtransport" +name = "use_webtransport_with_server_client" version = "0.1.0" edition = "2021" [dependencies] -leptos = { version = "0.5.0-beta2", features = ["nightly", "csr"] } +leptos = { version = "0.5.0-rc1", features = ["nightly", "csr"] } console_error_panic_hook = "0.1" console_log = "1" log = "0.4" -leptos-use = { path = "../..", features = ["docs"] } +leptos-use = { path = "../../..", features = ["docs"] } web-sys = "0.3" [dev-dependencies] diff --git a/examples/use_webtransport_with_server/client/src/main.rs b/examples/use_webtransport_with_server/client/src/main.rs index 52bd825..5c54c23 100644 --- a/examples/use_webtransport_with_server/client/src/main.rs +++ b/examples/use_webtransport_with_server/client/src/main.rs @@ -18,7 +18,7 @@ fn Demo() -> impl IntoView { let id = store_value(0); let transport = use_webtransport_with_options( - "https://echo.webtransport.day", + "https://localhost:4433", UseWebTransportOptions::default() .on_open(move || { set_datagrams_log.update(|log| log.push("Connection opened".to_string())) diff --git a/examples/use_webtransport_with_server/server/Cargo.toml b/examples/use_webtransport_with_server/server/Cargo.toml new file mode 100644 index 0000000..38f0ebd --- /dev/null +++ b/examples/use_webtransport_with_server/server/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "webtransport_test_server" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1" +base64 = "0.21.0" +rcgen = "0.10.0" +ring = "0.16.20" +time = "0.3.21" +tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] } +tracing = "0.1" +tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } +wtransport = "0.1" \ No newline at end of file diff --git a/examples/use_webtransport_with_server/server/cert.pem b/examples/use_webtransport_with_server/server/cert.pem new file mode 100644 index 0000000..99dee79 --- /dev/null +++ b/examples/use_webtransport_with_server/server/cert.pem @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBNTCB3KADAgECAghq294raE5e9TAKBggqhkjOPQQDAjAUMRIwEAYDVQQDDAls +b2NhbGhvc3QwHhcNMjMwOTEzMDEyNzIxWhcNMjMwOTE3MDEyNzIxWjAUMRIwEAYD +VQQDDAlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARel++iw3/0 +CPZTew09XTEmyKWGyUW7clEok17gb6BIqVZHy5pZ+P1F/qHSSuJtzZ+WFueVS1ZO +MCDfQql88sIyoxgwFjAUBgNVHREEDTALgglsb2NhbGhvc3QwCgYIKoZIzj0EAwID +SAAwRQIhAMQi1xToDZY8y4zZMOk7JJ3qqFOei6JkNcZf/68Zdgk3AiBCbPgLxaIw +n4bYLm0yqzQ5jzaJcOkrLMBQakaHJMyFoA== +-----END CERTIFICATE----- diff --git a/examples/use_webtransport_with_server/server/key.pem b/examples/use_webtransport_with_server/server/key.pem new file mode 100644 index 0000000..2c4d2c6 --- /dev/null +++ b/examples/use_webtransport_with_server/server/key.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgsOnsJtFGWK8w011r +400WvxgSScmnnAWFyuQ+o/dhvDGhRANCAARel++iw3/0CPZTew09XTEmyKWGyUW7 +clEok17gb6BIqVZHy5pZ+P1F/qHSSuJtzZ+WFueVS1ZOMCDfQql88sIy +-----END PRIVATE KEY----- diff --git a/examples/use_webtransport_with_server/server/rust-toolchain.toml b/examples/use_webtransport_with_server/server/rust-toolchain.toml new file mode 100644 index 0000000..271800c --- /dev/null +++ b/examples/use_webtransport_with_server/server/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" \ No newline at end of file diff --git a/examples/use_webtransport_with_server/server/src/bin/gencert.rs b/examples/use_webtransport_with_server/server/src/bin/gencert.rs new file mode 100644 index 0000000..6ca6397 --- /dev/null +++ b/examples/use_webtransport_with_server/server/src/bin/gencert.rs @@ -0,0 +1,50 @@ +use base64::engine::general_purpose::STANDARD as Base64Engine; +use base64::Engine; +use rcgen::CertificateParams; +use rcgen::DistinguishedName; +use rcgen::DnType; +use rcgen::KeyPair; +use rcgen::PKCS_ECDSA_P256_SHA256; +use ring::digest::digest; +use ring::digest::SHA256; +use std::fs; +use std::io::Write; +use time::Duration; +use time::OffsetDateTime; + +fn main() { + const COMMON_NAME: &str = "localhost"; + + let mut dname = DistinguishedName::new(); + dname.push(DnType::CommonName, COMMON_NAME); + + let keypair = KeyPair::generate(&PKCS_ECDSA_P256_SHA256).unwrap(); + + let digest = digest(&SHA256, &keypair.public_key_der()); + + let mut cert_params = CertificateParams::new(vec![COMMON_NAME.to_string()]); + cert_params.distinguished_name = dname; + cert_params.alg = &PKCS_ECDSA_P256_SHA256; + cert_params.key_pair = Some(keypair); + cert_params.not_before = OffsetDateTime::now_utc() + .checked_sub(Duration::days(2)) + .unwrap(); + cert_params.not_after = OffsetDateTime::now_utc() + .checked_add(Duration::days(2)) + .unwrap(); + + let certificate = rcgen::Certificate::from_params(cert_params).unwrap(); + + fs::File::create("cert.pem") + .unwrap() + .write_all(certificate.serialize_pem().unwrap().as_bytes()) + .unwrap(); + + fs::File::create("key.pem") + .unwrap() + .write_all(certificate.serialize_private_key_pem().as_bytes()) + .unwrap(); + + println!("Certificate generated"); + println!("Fingerprint: {}", Base64Engine.encode(digest)); +} diff --git a/examples/use_webtransport_with_server/server/src/main.rs b/examples/use_webtransport_with_server/server/src/main.rs new file mode 100644 index 0000000..7b797a1 --- /dev/null +++ b/examples/use_webtransport_with_server/server/src/main.rs @@ -0,0 +1,113 @@ +use anyhow::Result; +use std::time::Duration; +use tracing::error; +use tracing::info; +use tracing::info_span; +use tracing::Instrument; +use tracing_subscriber::filter::LevelFilter; +use tracing_subscriber::EnvFilter; +use wtransport::endpoint::IncomingSession; +use wtransport::tls::Certificate; +use wtransport::Endpoint; +use wtransport::ServerConfig; + +#[tokio::main] +async fn main() -> Result<()> { + init_logging(); + + let config = ServerConfig::builder() + .with_bind_default(4433) + .with_certificate(Certificate::load("cert.pem", "key.pem")?) + .keep_alive_interval(Some(Duration::from_secs(3))) + .build(); + + let server = Endpoint::server(config)?; + + info!("Server listening at localhost:4433"); + + for id in 0.. { + let incoming_session = server.accept().await; + tokio::spawn(handle_connection(incoming_session).instrument(info_span!("Connection", id))); + } + + Ok(()) +} + +async fn handle_connection(incoming_session: IncomingSession) { + let result = handle_connection_impl(incoming_session).await; + error!("{:?}", result); +} + +async fn handle_connection_impl(incoming_session: IncomingSession) -> Result<()> { + let mut buffer = vec![0; 65536].into_boxed_slice(); + + info!("Waiting for session request..."); + + let session_request = incoming_session.await?; + + info!( + "New session: Authority: '{}', Path: '{}'", + session_request.authority(), + session_request.path() + ); + + let connection = session_request.accept().await?; + + info!("Waiting for data from client..."); + + loop { + tokio::select! { + stream = connection.accept_bi() => { + let mut stream = stream?; + info!("Accepted BI stream"); + + let bytes_read = match stream.1.read(&mut buffer).await? { + Some(bytes_read) => bytes_read, + None => continue, + }; + + let str_data = std::str::from_utf8(&buffer[..bytes_read])?; + + info!("Received (bi) '{str_data}' from client"); + + stream.0.write_all(b"ACK").await?; + } + stream = connection.accept_uni() => { + let mut stream = stream?; + info!("Accepted UNI stream"); + + let bytes_read = match stream.read(&mut buffer).await? { + Some(bytes_read) => bytes_read, + None => continue, + }; + + let str_data = std::str::from_utf8(&buffer[..bytes_read])?; + + info!("Received (uni) '{str_data}' from client"); + + let mut stream = connection.open_uni().await?.await?; + stream.write_all(b"ACK").await?; + } + dgram = connection.receive_datagram() => { + let dgram = dgram?; + let str_data = std::str::from_utf8(&dgram)?; + + info!("Received (dgram) '{str_data}' from client"); + + connection.send_datagram(b"ACK")?; + } + } + } +} + +fn init_logging() { + let env_filter = EnvFilter::builder() + .with_default_directive(LevelFilter::INFO.into()) + .from_env_lossy(); + + tracing_subscriber::fmt() + .with_target(true) + .with_level(true) + .with_env_filter(env_filter) + .init(); +}