The mailbox

Bring your TCP server and the protocol we wrote yesterday together.

1. Turn you project into a workspace

The workspace should contain your server and the redisish library.

 📂 mailbox-server
 ┣ 📄 Cargo.toml
 ┃
 ┣ 📂 redisish
 ┃  ┣ 📄 Cargo.toml
 ┃  ┗ ...
 ┃
 ┣ 📂 mailbox
   ┣ 📄 Cargo.toml
   â”— ...
$ cat mailbox-server/Cargo.toml
[workspace]
members = ["redisish", "mailbox"]
$ cat mailbox-server/mailbox/Cargo.toml
[dependencies]
redisish = { path = "../redisish" }

2. Accept connections and implement the protocol

  1. Every connection just sends one command

  2. PUBLISH inserts into a message queue

  3. RETRIEVE retrieves a message, in a FIFO fashion

Use .unwrap for all error handling in the beginning.

Use std::collections::VecDeque for storing.

3. Do proper error handling

Implement std::error::Error for all your error types and start passing around a dynamically dispatched error.

Note

To send and receive messages, you can either use nc or telnet. Alternatively, you can use the client provided: https://github.com/ferrous-systems/teaching-material/tree/main/assignments/solutions/tcp-client

Usage:

$ cargo run -- "PUBLISH This is my message"
$ cargo run -- "RETRIEVE"

Help

The help section omits Step 4, "proper error handling" and makes the server panic if bad data is received.

Parsing a command from a TCPStream

We highly recommend moving reading and parsing into its own function.

// At the top of your file
use std::net::{TcpListener,TcpStream};
use std::io::prelude::*;

fn read_command(stream: &mut TcpStream) -> redisish::Command {
    let mut read_buffer = String::new(); (1)
    stream.read_to_string(&mut read_buffer).unwrap(); (2)

    redisish::parse(&read_buffer).unwrap() (3)
}
1 Allocate a read buffer (initially empty).
2 Read all data into the buffer until the client sends EOF.
3 Parse the incoming buffer

Handling the received command

You can copy-paste this snippet to quickly set you up reading and matching commands.

let command = read_command(&mut stream);
match command {
    redisish::Command::Publish(message) => {

    }
    redisish::Command::Retrieve => {

    }
}