I am trying to make an HTTP and WebSocket server in Rust using hyper and tungstenite. I need to accept WebSocket upgrades in a function where I handle HTTP requests. This function only has the request as an argument. I could send the stream as an argument to my function using a closure but I get another one of those pesky "use of moved value" errors. This is my code:
use http_body_util::Full;
use hyper::{
body::{Bytes, Incoming},
header,
server::conn::http1,
service::service_fn,
Request, Response, StatusCode,
};
use hyper_util::rt::TokioIo;
use std::{convert::Infallible, error::Error, net::SocketAddr, path::Path};
use tokio::net::TcpListener;
use tokio_tungstenite::accept_async;
async fn handle_request(request: Request<Incoming>) -> Result<Response<Full<Bytes>>, Infallible> {
let mut file_path: &str = "/404.html";
let mut status_code = StatusCode::NOT_FOUND;
match request.uri().path() {
"/" => {
if request.headers().contains_key(header::UPGRADE) {
println!("websocket connection");
//let mut socket = accept_async(request.body());
} else {
file_path = "/index.html";
status_code = StatusCode::OK;
}
}
other => {
let path = String::from("public") + other;
if let Ok(_) = tokio::fs::read(path).await {
file_path = other;
status_code = StatusCode::OK;
};
}
}
let response = Response::builder()
.status(status_code)
.header(header::CONTENT_TYPE, get_content_type(file_path))
.body(Full::new(Bytes::from(
tokio::fs::read(format!("public{file_path}")).await.unwrap(),
)))
.unwrap();
return Ok(response);
}
fn get_content_type(path: &str) -> &str {
match Path::new(path)
.extension()
.and_then(|e| e.to_str())
.unwrap()
{
"html" => "text/html",
"css" => "text/css",
"js" => "application/javascript",
"ico" => "image/x-icon",
_ => "text/plain",
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
let listener = TcpListener::bind(addr).await?;
loop {
let (stream, _) = listener.accept().await?;
let io = TokioIo::new(stream);
tokio::task::spawn(async move {
if let Err(err) = http1::Builder::new()
.serve_connection(io, service_fn(handle_request))
.await
{
println!("Error serving connection: {:?}", err);
}
});
}
}
I tried to use the stream as an argument for my handle_request function. It resulted in a "use of borrowed value" error.