use std::net::SocketAddr; use axum::{ extract::{ws::{Message, WebSocket, WebSocketUpgrade}, ConnectInfo}, response::IntoResponse, routing::any, Router, }; use axum_extra::TypedHeader; use futures::StreamExt; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; use tower_http::{ services::ServeDir, trace::{DefaultMakeSpan, TraceLayer}, }; async fn serve() { // diagnostics tracing_subscriber::registry() .with( tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| { format!("{}=debug,tower_http=debug", env!("CARGO_CRATE_NAME")).into() }), ) .with(tracing_subscriber::fmt::layer()) .init(); let app = Router::new() .route("/imgstream", any(ws_handler)) // logging middleware .layer( TraceLayer::new_for_http() .make_span_with(DefaultMakeSpan::default().include_headers(true)), ); // run it with hyper let listener = tokio::net::TcpListener::bind("127.0.0.1:3000") .await .unwrap(); tracing::debug!("listening on {}", listener.local_addr().unwrap()); axum::serve( listener, app.into_make_service_with_connect_info::(), ) .await .unwrap(); } async fn ws_handler( ws: WebSocketUpgrade, user_agent: Option>, ConnectInfo(addr): ConnectInfo, ) -> impl IntoResponse { let user_agent = if let Some(TypedHeader(user_agent)) = user_agent { user_agent.to_string() } else { String::from("Unknown browser") }; println!("`{user_agent}` at {addr} connected."); // finalize the upgrade process by returning upgrade callback. // we can customize the callback by sending additional info such as address. ws.on_upgrade(move |socket| img_stream(socket, addr)) } async fn img_stream(mut socket: WebSocket, who: SocketAddr) { let (mut sender, mut receiver) = socket.split(); while true { } }