Reputation: 95
I am quite new to Rust, and I'm still trying to be sure I understand principles doing a small project creating a server that uses a TcpStream. The server asks for a client for a code, which has to be 8 characters long. If it's not, it shall ask again for a new code. Here is what I have so far :
fn loby_matcher(stream: &mut TcpStream) -> std::io::Result<(String, usize), >{
let mut game_code = String::new();
let mut reader = BufReader::new(stream);
let len : usize = reader.read_line(&mut game_code)?;
match len {
8 => len,
_ => return Err(Error::new(ErrorKind::Other, "wrong game code")),
};
Ok((game_code, len))
}
pub fn create_game_matcher(mut stream: TcpStream) -> std::io::Result<()>{
println!("Creating a new game! Waiting for the code.");
let game_code: String;
let len: usize;
loop {
(game_code, len) = match loby_matcher(&mut stream) {
Ok(game_code) => break (game_code, len),
Err(e) => {
stream.write("Wrong code\n".as_bytes());
(String::new(),0)
}
};
};
println!("Received : {} size {}", game_code, len);
// println!("Closing connection now I guess?");
Ok(())
}
fn start_server(address: &str, port: &str) -> std::io::Result<()>{
let listener = TcpListener::bind(format!("{}:{}", address, port))?;
for stream in listener.incoming() {
// not using ? as we do not want to stop the server for wrong connection
let stream = stream.unwrap();
thread::spawn(move || {
create_game_matcher(stream);
});
}
Ok(())
}
The loop asking for a new code when an error occurs seems wrong, but I cannot figure out a way of doing that. Also, I know I should create a custom error in order to be able to make a difference between a wrong code and an I/O error on my TCPstream, which I will do later. What would be the right way of looping while a specific error occurs?
If you see anything wrong in the code, do not hesitate to tell me how I could improve it.
Upvotes: 5
Views: 3448
Reputation: 26197
I'm assuming you're asking how to resolve the issue in create_game_matcher
. If so, then you need to move your assignment further out.
To compare the error inside io::Error
, can be cumbersome. You can check the kind using e.kind() == ErrorKind::Other
. However, the actual error could be anything, and doesn't require implementing PartialEq
for &str
. The easiest is probably just to do e.to_string() == "wrong game code"
.
But like you mention, the most idiomatic approach would be to create a your own error type.
pub fn create_game_matcher(mut stream: TcpStream) -> std::io::Result<()> {
println!("Creating a new game! Waiting for the code.");
let (game_code, len) = loop {
match loby_matcher(&mut stream) {
Ok(game_code) => break game_code,
// Err(e) if e.kind() == ErrorKind::Other && e.to_string() == "wrong game code" => {
// or just (for ease of use)
Err(e) if e.to_string() == "wrong game code" => {
stream.write("Wrong code\n".as_bytes())?;
}
Err(e) => return Err(e),
};
};
println!("Received : {} size {}", game_code, len);
// println!("Closing connection now I guess?");
Ok(())
}
Since you want to loop until loby_matcher
succeeds, then (String::new(), 0)
can be removed. You also forgot to check whether stream.write
failed, so I've added an ?
.
Alternatively, given that you always break after the assignment, you could also express it like this:
pub fn create_game_matcher(mut stream: TcpStream) -> std::io::Result<()> {
println!("Creating a new game! Waiting for the code.");
let game_code: String;
let len: usize;
loop {
match loby_matcher(&mut stream) {
Ok((game_code_, len_)) => {
game_code = game_code_;
len = len_;
break;
}
Err(e) if e.to_string() == "wrong game code" => {
stream.write("Wrong code\n".as_bytes())?;
}
Err(e) => return Err(e),
};
}
println!("Received : {} size {}", game_code, len);
// println!("Closing connection now I guess?");
Ok(())
}
Upvotes: 4