summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml1
-rw-r--r--src/gameserver.rs75
2 files changed, 39 insertions, 37 deletions
diff --git a/Cargo.toml b/Cargo.toml
index bbd5c8e..36937a3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,3 +17,4 @@ serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
ctrlc = { version = "3.1", features = ["termination"] }
structopt = "0.3"
+unicode_categories = "0.1.1"
diff --git a/src/gameserver.rs b/src/gameserver.rs
index 7136399..b3d893a 100644
--- a/src/gameserver.rs
+++ b/src/gameserver.rs
@@ -4,6 +4,7 @@ use std::collections::HashMap;
use std::io;
use serde_json::{Value, json};
+use unicode_categories::UnicodeCategories;
use crate::{
controls::{Control, Action},
@@ -20,6 +21,17 @@ enum Message {
Invalid(String)
}
+struct MessageError {
+ typ: String,
+ text: String
+}
+
+macro_rules! merr {
+ (name, $text: expr) => {merr!("invalidname", $text)};
+ (action, $text: expr) => {merr!("invalidaction", $text)};
+ ($typ: expr, $text: expr) => {MessageError{typ: $typ.to_string(), text: $text.to_string()}};
+}
+
pub struct GameServer {
players: HashMap<(usize, usize), PlayerId>,
@@ -49,9 +61,10 @@ impl GameServer {
}
for (serverid, messages, left) in input {
for (id, message) in messages {
- let r = self.handle_message((serverid, id), parse_message(&message));
- if let Some(action) = r {
- actions.push(action);
+ match self.handle_message((serverid, id), parse_message(&message)){
+ Ok(Some(action)) => {actions.push(action);}
+ Ok(None) => {}
+ Err(err) => {let _ = self.send_error((serverid, id), &err.typ, &err.text);}
}
}
for id in left {
@@ -97,68 +110,56 @@ impl GameServer {
self.send(player, json!(["error", errname, err_text]))
}
- fn handle_message(&mut self, (serverid, connectionid): (usize, usize), msg: Message) -> Option<Action> {
+ fn handle_message(&mut self, (serverid, connectionid): (usize, usize), msg: Message) -> Result<Option<Action>, MessageError> {
let id = (serverid, connectionid);
match msg {
Message::Name(name) => {
- if name.len() > 256 {
- let _ = self.send_error(id, "invalidname", "A name can not be longer than 256 bytes");
- return None
+ if name.len() > 99 {
+ return Err(merr!(name, "A name can not be longer than 99 bytes"));
}
if name.len() == 0 {
- let _ = self.send_error(id, "invalidname", "A name must have at least one character");
- return None
+ return Err(merr!(name, "A name must have at least one character"));
}
let (firstchar, username) = name.split_at(1);
if firstchar == "~" {
if Some(username.to_string()) != self.servers[serverid].get_name(connectionid) {
- let _ = self.send_error(id, "invalidname", "A tilde name must match your username");
- return None;
+ return Err(merr!(name, "A tilde name must match your username"));
+ }
+ } else {
+ for chr in name.chars() {
+ if !(chr.is_letter() || chr.is_number() || chr.is_punctuation_connector()){
+ return Err(merr!(name, "A name can only contain letters, numbers and underscores"));
+ }
}
}
if self.players.contains_key(&id) {
- let _ = self.send_error(id, "invalidaction", "You can not change your name");
- return None;
+ return Err(merr!(action, "You can not change your name"));
}
let player = PlayerId{name};
if self.connections.contains_key(&player) {
- let _ = self.send_error(id, "nametaken", "Another connections to this player exists already");
- return None;
+ return Err(merr!("nametaken", "Another connection to this player exists already"));
}
self.broadcast_message(&format!("{} connected", player.name));
self.players.insert(id, player.clone());
self.connections.insert(player.clone(), id);
- Some(Action::Join(player))
+ Ok(Some(Action::Join(player)))
}
Message::Chat(text) => {
- if let Some(player) = self.players.get(&id) {
- let name = player.name.clone();
- self.broadcast_message(&format!("{}: {}", name, text));
- } else {
- let _ = self.send_error(id, "invalidaction", "Set a name before you send other messages");
- }
- None
+ let player = self.players.get(&id).ok_or(merr!(action, "Set a name before you send any other messages"))?;
+ let name = player.name.clone();
+ self.broadcast_message(&format!("{}: {}", name, text));
+ Ok(None)
}
Message::Input(inp) => {
- if let Some(player) = self.players.get(&id) {
- if let Some(control) = Control::from_json(&inp) {
- Some(Action::Input(player.clone(), control))
- } else {
- let _ = self.send_error(id, "invalidaction", &format!("unknown action: {}", inp));
- None
- }
- } else {
- let _ = self.send_error(id, "invalidaction", "Set a name before you send other messages");
- None
- }
+ let player = self.players.get(&id).ok_or(merr!(action, "Set a name before you send any other messages"))?;
+ let control = Control::from_json(&inp).ok_or(merr!(action, &format!("unknown action: {}", inp)))?;
+ Ok(Some(Action::Input(player.clone(), control)))
}
Message::Invalid(text) => {
- let _ = self.send_error(id, "invalidmessage", &format!("Invalid: {}", text));
- None
+ Err(merr!("invalidmessage", &format!("Invalid: {}", text)))
}
}
}
-
}