exercises

Log | Files | Refs | README

client.rs (3831B)


      1 use bytes::Bytes;
      2 use mini_redis::client;
      3 use tokio::sync::{mpsc, oneshot};
      4 
      5 /// Multiple different commands are multiplexed over a single channel.
      6 #[derive(Debug)]
      7 enum Command {
      8     Get {
      9         key: String,
     10         resp: Responder<Option<Bytes>>,
     11     },
     12     Set {
     13         key: String,
     14         val: Bytes,
     15         resp: Responder<()>,
     16     },
     17 }
     18 
     19 /// Provided by the requester and used by the manager task to send the command
     20 /// response back to the requester
     21 type Responder<T> = oneshot::Sender<mini_redis::Result<T>>;
     22 
     23 #[tokio::main]
     24 async fn main() {
     25     // The mpsc channel supports sending many values from many producers to
     26     // a single consumer
     27     //
     28     // Create a new channel with a capacity of at most 32.
     29     // It returns two values: a sender and a receiver
     30     //
     31     // tx and rx:
     32     // This naming comes from electronics and networking, where signal lines
     33     // are often labeled TX (transmit) and RX (receive), and Rust’s channel
     34     // examples follow the same tradition to indicate which end sends and which
     35     // end receives.
     36     let (tx, mut rx) = mpsc::channel(32);
     37 
     38     // Sending from multiple tasks is done by cloning the Sender
     39     let tx2 = tx.clone();
     40 
     41     // Spawn a task that processes messages from the channel.
     42     // First, a client connection is established to Redis.
     43     // Then, received commands are issued via the Redis connection.
     44     //
     45     // The `move` keyword is used to **move** ownership of `rx` into the task.
     46     let manager = tokio::spawn(async move {
     47         // Establish a connection to the server
     48         let mut client = client::connect("127.0.0.1:6379").await.unwrap();
     49 
     50         // Start receiving messages
     51         while let Some(cmd) = rx.recv().await {
     52             match cmd {
     53                 Command::Get { key, resp } => {
     54                     let res = client.get(&key).await;
     55 
     56                     // Calling send on oneshot::Sender completes immediately
     57                     // and does not require an .await. This is because send on
     58                     // a oneshot channel will always fail or succeed immediately
     59                     // without any form of waiting.
     60                     let _ = resp.send(res);
     61                 }
     62                 Command::Set { key, val, resp } => {
     63                     let res = client.set(&key, val).await;
     64 
     65                     // Calling send on oneshot::Sender completes immediately
     66                     // and does not require an .await. This is because send on
     67                     // a oneshot channel will always fail or succeed immediately
     68                     // without any form of waiting.
     69                     let _ = resp.send(res);
     70                 }
     71             }
     72         }
     73     });
     74 
     75     // Both messages are sent to the single Receiver handle.
     76     // It is not possible to clone the receiver of an mpsc channel.
     77     let t1 = tokio::spawn(async move {
     78         let (resp_tx, resp_rx) = oneshot::channel();
     79         let cmd = Command::Get {
     80             key: "foo".to_string(),
     81             resp: resp_tx,
     82         };
     83 
     84         // Send the Get request
     85         tx.send(cmd).await.unwrap();
     86 
     87         // Await the response
     88         let res = resp_rx.await;
     89         println!("GOT = {:?}", res);
     90     });
     91 
     92     let t2 = tokio::spawn(async move {
     93         let (resp_tx, resp_rx) = oneshot::channel();
     94         let cmd = Command::Set {
     95             key: "foo".to_string(),
     96             val: "bar".into(),
     97             resp: resp_tx,
     98         };
     99 
    100         // Send the SET request
    101         tx2.send(cmd).await.unwrap();
    102 
    103         // Await the response
    104         let res = resp_rx.await;
    105         println!("GOT = {:?}", res);
    106     });
    107 
    108     // At the bottom of the main function, we .await the join handles to ensure
    109     // the commands fully complete before the process exits.
    110     t1.await.unwrap();
    111     t2.await.unwrap();
    112     manager.await.unwrap();
    113 }