Store values
We will now implement the process
function to handle incoming commands. We will use a HashMap
to store values. SET
commands will insert into the HashMap
and GET
values will load them. Additionally, we will use a loop to accept more than one command per connection.
use tokio::net::TcpStream;
use mini_redis::{Connection, Frame};
async fn process(socket: TcpStream) {
use mini_redis::Command::{self, Get, Set};
use std::collections::HashMap;
// A hashmap is used to store data
let mut db = HashMap::new();
// Connection, provided by `mini-redis`, handles parsing frames from
// the socket
let mut connection = Connection::new(socket);
// Use `read_frame` to receive a command from the connection.
while let Some(frame) = connection.read_frame().await.unwrap() {
let response = match Command::from_frame(frame).unwrap() {
Set(cmd) => {
// The value is stored as `Vec<u8>`
db.insert(cmd.key().to_string(), cmd.value().to_vec());
Frame::Simple("OK".to_string())
}
Get(cmd) => {
if let Some(value) = db.get(cmd.key()) {
// `Frame::Bulk` expects data to be of type `Bytes`. This
// type will be covered later in the tutorial. For now,
// `&Vec<u8>` is converted to `Bytes` using `into()`.
Frame::Bulk(value.clone().into())
} else {
Frame::Null
}
}
cmd => panic!("unimplemented {:?}", cmd),
};
// Write the response to the client
connection.write_frame(&response).await.unwrap();
}
}
Now, start the server:
$ cargo run
and in a separate terminal window, run the hello-redis
example:
$ cargo run --example hello-redis
Now, the output will be:
got value from the server; success=Some(b"world")
We can now get and set values, but there is a problem: The values are not shared between connections. If another socket connects and tries to GET
the hello
key, it will not find anything.
You can find the full code here.
In the next section, we will implement persisting data for all sockets.