]> piware.de Git - learn-rust.git/blobdiff - tokio-tutorial-mini-redis/src/bin/server.rs
tokio-tutorial-mini-redis: Add proper error handling
[learn-rust.git] / tokio-tutorial-mini-redis / src / bin / server.rs
index 2488f033ead6e2808c08fe6f4499e3b0818f9d15..962c923dab5c13b17c34a50504c71a324f2733bf 100644 (file)
@@ -1,4 +1,5 @@
 use std::collections::HashMap;
+use std::error::Error;
 use std::sync::{Arc, Mutex};
 
 use bytes::Bytes;
@@ -8,33 +9,49 @@ use tokio::net::{TcpListener, TcpStream};
 
 type Db = Arc<Mutex<HashMap<String, Bytes>>>;
 
+const LISTEN: &str = "127.0.0.1:6379";
+
 #[tokio::main]
 async fn main() {
-    let listener = TcpListener::bind("127.0.0.1:6379").await.unwrap();
+    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug")).init();
+
+    let listener = TcpListener::bind(LISTEN).await.unwrap();
+    log::info!("Listening on {}", LISTEN);
     let db: Db = Arc::new(Mutex::new(HashMap::new()));
 
     loop {
-        // The second item contains the IP and port of the new connection
-        let (socket, _) = listener.accept().await.unwrap();
-        let db_i = db.clone();
-        tokio::spawn(async move { process(socket, db_i).await });
+        match listener.accept().await {
+            Ok((socket, addr)) => {
+                log::debug!("got connection from {:?}", addr);
+                let db_i = db.clone();
+                tokio::spawn(async move {
+                    if let Err(e) = process(socket, db_i).await {
+                        log::warn!("failed: {:?}", e);
+                    }
+                });
+            },
+            Err(e) => log::warn!("Failed to accept connection: {}", e),
+        };
     }
 }
 
-async fn process(socket: TcpStream, db: Db) {
+async fn process(socket: TcpStream, db: Db) -> Result<(), Box<dyn Error + Send + Sync>> {
     let mut connection = Connection::new(socket);
 
-    while let Some(frame) = connection.read_frame().await.unwrap() {
-        let response = match Command::from_frame(frame).unwrap() {
+    while let Some(frame) = connection.read_frame().await? {
+        let response = match Command::from_frame(frame)? {
             Set(cmd) => {
                 // The value is stored as `Vec<u8>`
                 db.lock().unwrap().insert(cmd.key().to_string(), cmd.value().clone());
+                log::debug!("Set {} → {:?}", &cmd.key(), &cmd.value());
                 Frame::Simple("OK".to_string())
             }
             Get(cmd) => {
                 if let Some(value) = db.lock().unwrap().get(cmd.key()) {
+                    log::debug!("Get {} → {:?}", &cmd.key(), &value);
                     Frame::Bulk(value.clone())
                 } else {
+                    log::debug!("Get {} unknown key", &cmd.key());
                     Frame::Null
                 }
             }
@@ -42,6 +59,7 @@ async fn process(socket: TcpStream, db: Db) {
         };
 
         // Write the response to the client
-        connection.write_frame(&response).await.unwrap();
+        connection.write_frame(&response).await?;
     }
+    Ok(())
 }