Make asynchronous via tokio
Change-Id: I2a7f4be44e51815b8ae34eeb4f4a54430160fd84
Reviewed-on: https://git.clicks.codes/c/Clicks/BYO/HttpServer/rust/+/255
Reviewed-by: Samuel Shuert <coded@clicks.codes>
Tested-by: Skyler Grey <minion@clicks.codes>
diff --git a/src/main.rs b/src/main.rs
index 3b23e05..eb6b198 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,91 +1,93 @@
-use std::{net::TcpListener, io::{Write, Read}, collections::HashMap};
+use std::{io::Result, collections::HashMap};
+use tokio::{net::{TcpListener, TcpStream}, io::{AsyncReadExt, AsyncWriteExt}};
+
use itertools::Itertools;
use nom::AsChar;
-fn main() {
- let listener = TcpListener::bind("127.0.0.1:4221").unwrap();
+async fn process_socket(mut stream: TcpStream) {
+ println!("accepted new connection");
- for stream in listener.incoming() {
- match stream {
- Ok(mut _stream) => {
- println!("accepted new connection");
+ let mut request: HashMap<String, String> = HashMap::new();
+ let mut line_num: usize = 0;
+ loop {
+ let mut line = String::default();
- let mut request: HashMap<String, String> = HashMap::new();
- let mut line_num: usize = 0;
- loop {
- let mut line = String::default();
+ loop {
+ let mut buf: [u8; 1] = [0; 1];
+ stream.read_exact(&mut buf).await.unwrap();
- loop {
- let mut buf: [u8; 1] = [0; 1];
- _stream.read_exact(&mut buf).unwrap();
-
- let character = buf[0].as_char();
- if character == '\n' {
- break
- } else if character != '\r' {
- line.push(character);
- }
- }
-
- if line_num == 0 {
- let mut splits = line.split(' ');
- request.insert("method".to_owned(), splits.next().unwrap().to_owned());
- request.insert("path".to_owned(), splits.next().unwrap().to_owned());
- } else {
- let mut splits = line.split(": ");
- let key = splits.next().unwrap();
- let value = splits.next().unwrap();
- request.insert(key.to_owned(), value.to_owned());
- }
-
- if request.contains_key("User-Agent") { break };
- line_num += 1;
- }
-
- println!("{:?}", request);
-
- let mut path = request.get("path").unwrap().split("/");
-
- let response_status: String;
- let mut response_headers: Vec<String> = vec![];
- let response_body: String;
-
- // println!("{:?}", path);
-
- path.next().unwrap();
-
- match path.next().unwrap() {
- "" => {
- response_status = "200 OK".into();
- response_body = "".into();
- },
- "echo" => {
- response_status = "200 OK".into();
- response_body = path.join("/");
- response_headers.push("Content-Type: text/plain".into());
-
- },
- "user-agent" => {
- response_status = "200 OK".into();
- response_body = request.get("User-Agent").unwrap().into();
- response_headers.push("Content-Type: text/plain".into());
- },
- _ => {
- response_status = "404 Not Found".into();
- response_body = "".into();
- }
- }
-
- if response_body.len() > 0 {
- response_headers.push(format!("Content-Length: {}", response_body.len()));
- }
-
- _stream.write(format!("HTTP/1.1 {response_status}\r\n{}\r\n\r\n{response_body}", response_headers.join("\r\n")).as_bytes()).unwrap();
- }
- Err(e) => {
- println!("error: {}", e);
+ let character = buf[0].as_char();
+ if character == '\n' {
+ break
+ } else if character != '\r' {
+ line.push(character);
}
}
+
+ if line_num == 0 {
+ let mut splits = line.split(' ');
+ request.insert("method".to_owned(), splits.next().unwrap().to_owned());
+ request.insert("path".to_owned(), splits.next().unwrap().to_owned());
+ } else {
+ let mut splits = line.split(": ");
+ let key = splits.next().unwrap();
+ let value = splits.next().unwrap();
+ request.insert(key.to_owned(), value.to_owned());
+ }
+
+ if request.contains_key("User-Agent") { break };
+ line_num += 1;
+ }
+
+ println!("{:?}", request);
+
+ let mut path = request.get("path").unwrap().split("/");
+
+ let response_status: String;
+ let mut response_headers: Vec<String> = vec![];
+ let response_body: String;
+
+ // println!("{:?}", path);
+
+ path.next().unwrap();
+
+ match path.next().unwrap() {
+ "" => {
+ response_status = "200 OK".into();
+ response_body = "".into();
+ },
+ "echo" => {
+ response_status = "200 OK".into();
+ response_body = path.join("/");
+ response_headers.push("Content-Type: text/plain".into());
+ },
+ "user-agent" => {
+ response_status = "200 OK".into();
+ response_body = request.get("User-Agent").unwrap().into();
+ response_headers.push("Content-Type: text/plain".into());
+ },
+ _ => {
+ response_status = "404 Not Found".into();
+ response_body = "".into();
+ }
+ }
+
+ if response_body.len() > 0 {
+ response_headers.push(format!("Content-Length: {}", response_body.len()));
+ }
+
+ stream.write(format!("HTTP/1.1 {response_status}\r\n{}\r\n\r\n{response_body}", response_headers.join("\r\n")).as_bytes()).await.unwrap();
+
+}
+
+#[tokio::main]
+async fn main() -> Result<()> {
+ let listener = TcpListener::bind("127.0.0.1:4221").await?;
+ let mut futures = vec![];
+
+ loop {
+ let (socket, _) = listener.accept().await?;
+ futures.push(process_socket(socket));
}
}