From 265b78dc51c822764a604ef402253de339941853 Mon Sep 17 00:00:00 2001 From: Nikita Vilunov Date: Tue, 14 Feb 2023 20:07:07 +0100 Subject: [PATCH] improve newtypes --- src/core/player.rs | 16 ++++++++++++++-- src/core/room.rs | 14 +++++++++++++- src/projections/irc/mod.rs | 37 +++++++++++++++++++------------------ 3 files changed, 46 insertions(+), 21 deletions(-) diff --git a/src/core/player.rs b/src/core/player.rs index 0df6924..865d87e 100644 --- a/src/core/player.rs +++ b/src/core/player.rs @@ -25,9 +25,21 @@ use crate::{ util::table::{AnonTable, Key as AnonKey}, }; -/// Opaque player identifier. +/// Opaque player identifier. Cannot contain spaces, must be shorter than 32. #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct PlayerId(pub ByteVec); +pub struct PlayerId(ByteVec); +impl PlayerId { + pub fn from_bytes(bytes: ByteVec) -> Result { + if bytes.len() > 32 { + return Err(anyhow::Error::msg("Nickname cannot be longer than 32 symbols")); + } + if bytes.contains(&b' ') { + return Err(anyhow::Error::msg("Nickname cannot contain spaces")); + } + Ok(PlayerId(bytes)) + } + pub fn as_bytes(&self) -> &ByteVec { &self.0 } +} #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ConnectionId(pub AnonKey); diff --git a/src/core/room.rs b/src/core/room.rs index 359a7a3..0ee8c47 100644 --- a/src/core/room.rs +++ b/src/core/room.rs @@ -17,7 +17,19 @@ use super::player::{ConnectionId, IncomingPlayerEvent}; /// Opaque room id #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct RoomId(pub ByteVec); +pub struct RoomId(ByteVec); +impl RoomId { + pub fn from_bytes(bytes: ByteVec) -> Result { + if bytes.len() > 32 { + return Err(anyhow::Error::msg("Room name cannot be longer than 32 symbols")); + } + if bytes.contains(&b' ') { + return Err(anyhow::Error::msg("Room name cannot contain spaces")); + } + Ok(RoomId(bytes)) + } + pub fn as_bytes(&self) -> &ByteVec { &self.0 } +} /// Shared datastructure for storing metadata about rooms. #[derive(Clone)] diff --git a/src/projections/irc/mod.rs b/src/projections/irc/mod.rs index ccb38ca..5b8019e 100644 --- a/src/projections/irc/mod.rs +++ b/src/projections/irc/mod.rs @@ -152,7 +152,7 @@ async fn handle_registered_socket<'a>( let mut buffer = vec![]; log::info!("Handling registered user: {user:?}"); - let player_id = PlayerId(user.nickname.clone()); + let player_id = PlayerId::from_bytes(user.nickname.clone())?; let mut connection = players.connect_to_player(player_id.clone()).await; ServerMessage { @@ -214,7 +214,7 @@ async fn handle_registered_socket<'a>( produce_on_join_cmd_messages( &config, &user, - &Chan::Global(room.id.0.clone()), + &Chan::Global(room.id.as_bytes().clone()), room, writer, ) @@ -243,7 +243,7 @@ async fn handle_registered_socket<'a>( if player_id == author_id { if let Some(room) = rooms.get_room(&room_id) { let room_info = room.get_room_info().await; - let chan = Chan::Global(room_id.0); + let chan = Chan::Global(room_id.as_bytes().clone()); produce_on_join_cmd_messages(&config, &user, &chan, &room_info, writer).await?; writer.flush().await?; } else { @@ -252,8 +252,8 @@ async fn handle_registered_socket<'a>( } else { ServerMessage { tags: vec![], - sender: Some(author_id.0.clone()), - body: ServerMessageBody::Join(Chan::Global(room_id.0)), + sender: Some(author_id.as_bytes().clone()), + body: ServerMessageBody::Join(Chan::Global(room_id.as_bytes().clone())), }.write_async(writer).await?; writer.flush().await? } @@ -262,8 +262,8 @@ async fn handle_registered_socket<'a>( if player_id != author_id || connection.connection_id != connection_id { ServerMessage { tags: vec![], - sender: Some(author_id.0.clone()), - body: ServerMessageBody::PrivateMessage { target: Recipient::Chan(Chan::Global(room_id.0)), body: body.as_bytes().to_vec() } + sender: Some(author_id.as_bytes().clone()), + body: ServerMessageBody::PrivateMessage { target: Recipient::Chan(Chan::Global(room_id.as_bytes().clone())), body: body.as_bytes().to_vec() } }.write_async(writer).await?; writer.flush().await? } @@ -274,7 +274,7 @@ async fn handle_registered_socket<'a>( sender: Some(config.server_name.as_bytes().to_vec()), body: ServerMessageBody::N332Topic { client: user.nickname.clone(), - chat: Chan::Global(room_id.0.clone()), + chat: Chan::Global(room_id.as_bytes().clone()), topic: new_topic, }, }.write_async(writer).await?; @@ -315,11 +315,10 @@ async fn handle_incoming_message( handle_join(&config, &user, user_handle, chan, writer).await?; } ClientMessage::PrivateMessage { recipient, body } => match recipient { - Recipient::Chan(Chan::Global(room)) => match String::from_utf8(body) { + Recipient::Chan(Chan::Global(chan)) => match String::from_utf8(body) { Ok(body) => { - user_handle - .send_message(RoomId(room.clone()), body.clone()) - .await + let room_id = RoomId::from_bytes(chan)?; + user_handle.send_message(room_id, body.clone()).await } Err(err) => log::warn!("failed to parse incoming message: {err}"), }, @@ -327,8 +326,9 @@ async fn handle_incoming_message( }, ClientMessage::Topic { chan, topic } => { match chan { - Chan::Global(ref room) => { - let room = rooms.get_room(&RoomId(room.clone())); + Chan::Global(chan) => { + let room_id = RoomId::from_bytes(chan)?; + let room = rooms.get_room(&room_id); if let Some(mut room) = room { room.set_topic(topic).await; } @@ -353,8 +353,9 @@ async fn handle_join( writer: &mut (impl AsyncWrite + Unpin), ) -> Result<()> { match chan { - Chan::Global(ref room) => { - let room_info = user_handle.join_room(RoomId(room.clone())).await?; + Chan::Global(chan) => { + let room_id = RoomId::from_bytes(chan.clone())?; + let room_info = user_handle.join_room(room_id).await?; } Chan::Local(_) => {} }; @@ -387,13 +388,13 @@ async fn produce_on_join_cmd_messages( .write_async(writer) .await?; let mut members = if let Some(head) = room_info.members.first() { - head.0.clone() + head.as_bytes().clone() } else { user.nickname.clone() }; for i in &room_info.members[1..] { members.push(b' '); - members.extend(&i.0); + members.extend(i.as_bytes()); } ServerMessage { tags: vec![],