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 }