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));
     }
 }