]> piware.de Git - learn-rust.git/blob - tokio-tutorial-jbarszczewski/src/main.rs
tokio-tutorial-jbarszczewski: Implement actual balance data handling
[learn-rust.git] / tokio-tutorial-jbarszczewski / src / main.rs
1 use std::str;
2 use std::sync::{ Arc, Mutex };
3
4 use tokio::io::{ AsyncReadExt, AsyncWriteExt };
5 use tokio::net::{ TcpListener, TcpStream };
6
7 #[tokio::main]
8 async fn main() {
9     let balance = Arc::new(Mutex::new(0.0f64));
10     let listener = TcpListener::bind("127.0.0.1:8181").await.unwrap();
11
12     loop {
13         let (stream, _) = listener.accept().await.unwrap();
14         let balance_ref = balance.clone();
15         tokio::spawn(async move { handle_connection(stream, balance_ref).await });
16     }
17 }
18
19 async fn handle_connection(mut stream: TcpStream, balance: Arc<Mutex<f64>>) {
20     // Read the first 16 characters from the incoming stream
21     let mut buffer = [0; 16];
22     assert!(stream.read(&mut buffer).await.unwrap() >= 16);
23     // First 4 characters are used to detect HTTP method
24     let method_type = match str::from_utf8(&buffer[0..4]) {
25         Ok(v) => v,
26         Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
27     };
28
29     let contents = match method_type {
30         "GET " => {
31             format!("{{\"balance\": {}}}", balance.lock().unwrap())
32         }
33         "POST" => {
34             // Take characters after 'POST /' until whitespace is detected.
35             let input: String = buffer[6..16]
36                 .iter()
37                 .take_while(|x| **x != 32u8)
38                 .map(|x| *x as char)
39                 .collect();
40             let balance_update = input.parse::<f64>().unwrap();
41             println!("got POST request to update by {}", balance_update);
42             let mut locked_balance = balance.lock().unwrap();
43             *locked_balance += balance_update;
44             format!("{{\"balance\": {}}}", locked_balance)
45         }
46         _ => {
47             panic!("Invalid HTTP method!")
48         }
49     };
50
51     let response = format!(
52         "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{}",
53         contents.len(),
54         contents
55     );
56     assert!(stream.write(response.as_bytes()).await.unwrap() > 0);
57     stream.flush().await.unwrap();
58 }