0.3.5-alpha.9
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
# file: crates/apps/game-realtime-webtransport-datagram-smoke/Cargo.toml
|
||||
# version: 1
|
||||
|
||||
[package]
|
||||
name = "game-realtime-webtransport-datagram-smoke"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
authors.workspace = true
|
||||
publish.workspace = true
|
||||
|
||||
[dependencies]
|
||||
game-logging-lib = { path = "../../common/game-logging-lib" }
|
||||
game-realtime-webtransport-lib = { path = "../../common/game-realtime-webtransport-lib" }
|
||||
tokio = { workspace = true, features = ["macros", "rt", "time"] }
|
||||
tracing.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -0,0 +1,101 @@
|
||||
// file: crates/apps/game-realtime-webtransport-datagram-smoke/src/main.rs
|
||||
// version: 1
|
||||
|
||||
#![warn(missing_docs)]
|
||||
#![deny(unreachable_pub)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
//! Executable localhost smoke for the backend-specific WebTransport datagram capability.
|
||||
|
||||
const CLIENT_DATAGRAM: &[u8] = b"games.sasedev-webtransport-client-datagram";
|
||||
const DATAGRAM_RECEIVE_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(2);
|
||||
const SERVER_DATAGRAM: &[u8] = b"games.sasedev-webtransport-server-datagram";
|
||||
const SMOKE_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const TRACING_TARGET: &str = "games::realtime::webtransport::datagram-smoke";
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() -> std::process::ExitCode {
|
||||
let _logging_guard = match game_logging_lib::init_console_tracing() {
|
||||
std::result::Result::Ok(guard) => guard,
|
||||
std::result::Result::Err(error) => {
|
||||
eprintln!("failed to initialize WebTransport datagram smoke tracing: {error}");
|
||||
return std::process::ExitCode::FAILURE;
|
||||
},
|
||||
};
|
||||
tracing::info!(target: TRACING_TARGET, "WebTransport datagram smoke started");
|
||||
let result = tokio::time::timeout(SMOKE_TIMEOUT, run_smoke()).await;
|
||||
return match result {
|
||||
std::result::Result::Ok(std::result::Result::Ok(())) => {
|
||||
tracing::info!(target: TRACING_TARGET, "WebTransport datagram smoke passed");
|
||||
println!("game-realtime-webtransport-datagram-smoke: PASS");
|
||||
std::process::ExitCode::SUCCESS
|
||||
},
|
||||
std::result::Result::Ok(std::result::Result::Err(error)) => {
|
||||
tracing::error!(target: TRACING_TARGET, detail = error.as_str(), "WebTransport datagram smoke failed");
|
||||
eprintln!("game-realtime-webtransport-datagram-smoke: FAIL: {error}");
|
||||
std::process::ExitCode::FAILURE
|
||||
},
|
||||
std::result::Result::Err(_) => {
|
||||
tracing::error!(target: TRACING_TARGET, timeout_ms = SMOKE_TIMEOUT.as_millis(), "WebTransport datagram smoke timed out");
|
||||
eprintln!("game-realtime-webtransport-datagram-smoke: FAIL: smoke timed out");
|
||||
std::process::ExitCode::FAILURE
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async fn run_smoke() -> std::result::Result<(), String> {
|
||||
let identity = match game_realtime_webtransport_lib::WebTransportServerIdentity::generate_loopback() {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(format!("loopback identity generation failed: {error}")),
|
||||
};
|
||||
let certificate_hash = identity.certificate_hash().clone();
|
||||
let bind_address = std::net::SocketAddr::from(([127, 0, 0, 1], 0));
|
||||
let server_config = game_realtime_webtransport_lib::WebTransportServerConfig::new(bind_address, identity);
|
||||
let mut listener = match game_realtime_webtransport_lib::WebTransportListener::bind(server_config) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(format!("listener bind failed: {error}")),
|
||||
};
|
||||
let endpoint = format!("https://{}/datagram-smoke", listener.local_addr());
|
||||
let client_config = match game_realtime_webtransport_lib::WebTransportClientConfig::new(endpoint.as_str(), certificate_hash) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(format!("client configuration failed: {error}")),
|
||||
};
|
||||
let (server_result, client_result) = tokio::join!(listener.accept(), game_realtime_webtransport_lib::connect(&client_config));
|
||||
let server_session = match server_result {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(format!("server accept failed: {error}")),
|
||||
};
|
||||
let client_session = match client_result {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(format!("client connect failed: {error}")),
|
||||
};
|
||||
let client_max = client_session.max_datagram_size();
|
||||
let server_max = server_session.max_datagram_size();
|
||||
if CLIENT_DATAGRAM.len() > client_max || SERVER_DATAGRAM.len() > server_max {
|
||||
return std::result::Result::Err(format!("negotiated datagram capacity too small: client_max={client_max}, server_max={server_max}"));
|
||||
}
|
||||
tracing::info!(target: TRACING_TARGET, client_max, server_max, "WebTransport datagram capacities negotiated");
|
||||
if let std::result::Result::Err(error) = client_session.send_datagram(CLIENT_DATAGRAM) {
|
||||
return std::result::Result::Err(format!("client datagram send failed: {error}"));
|
||||
}
|
||||
let server_received = match tokio::time::timeout(DATAGRAM_RECEIVE_TIMEOUT, server_session.receive_datagram()).await {
|
||||
std::result::Result::Ok(std::result::Result::Ok(value)) => value,
|
||||
std::result::Result::Ok(std::result::Result::Err(error)) => return std::result::Result::Err(format!("server datagram receive failed: {error}")),
|
||||
std::result::Result::Err(_) => return std::result::Result::Err(String::from("server datagram receive timed out; datagram delivery is not guaranteed")),
|
||||
};
|
||||
if server_received.as_slice() != CLIENT_DATAGRAM {
|
||||
return std::result::Result::Err(String::from("server received an unexpected datagram payload"));
|
||||
}
|
||||
if let std::result::Result::Err(error) = server_session.send_datagram(SERVER_DATAGRAM) {
|
||||
return std::result::Result::Err(format!("server datagram send failed: {error}"));
|
||||
}
|
||||
let client_received = match tokio::time::timeout(DATAGRAM_RECEIVE_TIMEOUT, client_session.receive_datagram()).await {
|
||||
std::result::Result::Ok(std::result::Result::Ok(value)) => value,
|
||||
std::result::Result::Ok(std::result::Result::Err(error)) => return std::result::Result::Err(format!("client datagram receive failed: {error}")),
|
||||
std::result::Result::Err(_) => return std::result::Result::Err(String::from("client datagram receive timed out; datagram delivery is not guaranteed")),
|
||||
};
|
||||
if client_received.as_slice() != SERVER_DATAGRAM {
|
||||
return std::result::Result::Err(String::from("client received an unexpected datagram payload"));
|
||||
}
|
||||
return std::result::Result::Ok(());
|
||||
}
|
||||
Reference in New Issue
Block a user