1 use { 2 hyper::{ 3 service::{make_service_fn, service_fn}, 4 Body, Request, Response, Server, StatusCode, 5 }, 6 tokio::fs::File, 7 tokio_util::codec::{BytesCodec, FramedRead}, 8 }; 9 10 type GenericError = Box<dyn std::error::Error + Send + Sync>; 11 type Result<T> = std::result::Result<T, GenericError>; 12 static NOTFOUND: &[u8] = b"Not Found"; 13 14 async fn handle_connection(req: Request<Body>) -> Result<Response<Body>> { 15 let path = req.uri().path(); 16 17 let mut file_path: String = String::from(""); 18 19 if path.ends_with(".m3u8") { 20 //http://127.0.0.1/app_name/stream_name/stream_name.m3u8 21 let m3u8_index = path.find(".m3u8").unwrap(); 22 23 if m3u8_index > 0 { 24 let (left, _) = path.split_at(m3u8_index); 25 let rv: Vec<_> = left.split('/').collect(); 26 27 let app_name = String::from(rv[1]); 28 let stream_name = String::from(rv[2]); 29 30 file_path = format!("./{app_name}/{stream_name}/{stream_name}.m3u8"); 31 } 32 } else if path.ends_with(".ts") { 33 //http://127.0.0.1/app_name/stream_name/ts_name.m3u8 34 let ts_index = path.find(".ts").unwrap(); 35 36 if ts_index > 0 { 37 let (left, _) = path.split_at(ts_index); 38 39 let rv: Vec<_> = left.split('/').collect(); 40 41 let app_name = String::from(rv[1]); 42 let stream_name = String::from(rv[2]); 43 let ts_name = String::from(rv[3]); 44 45 file_path = format!("./{app_name}/{stream_name}/{ts_name}.ts"); 46 } 47 } 48 49 simple_file_send(file_path.as_str()).await 50 } 51 52 /// HTTP status code 404 53 fn not_found() -> Response<Body> { 54 Response::builder() 55 .status(StatusCode::NOT_FOUND) 56 .body(NOTFOUND.into()) 57 .unwrap() 58 } 59 60 async fn simple_file_send(filename: &str) -> Result<Response<Body>> { 61 // Serve a file by asynchronously reading it by chunks using tokio-util crate. 62 63 if let Ok(file) = File::open(filename).await { 64 let stream = FramedRead::new(file, BytesCodec::new()); 65 let body = Body::wrap_stream(stream); 66 return Ok(Response::new(body)); 67 } 68 69 Ok(not_found()) 70 } 71 72 pub async fn run(port: usize) -> Result<()> { 73 let listen_address = format!("0.0.0.0:{port}"); 74 let sock_addr = listen_address.parse().unwrap(); 75 76 let new_service = 77 make_service_fn(move |_| async { Ok::<_, GenericError>(service_fn(handle_connection)) }); 78 79 let server = Server::bind(&sock_addr).serve(new_service); 80 log::info!("Hls server listening on http://{}", sock_addr); 81 server.await?; 82 83 Ok(()) 84 } 85