diff --git a/Cargo.lock b/Cargo.lock index 9d0873d..cd780ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,26 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -40,12 +20,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bitflags" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c70beb79cbb5ce9c4f8e20849978f34225931f665bb49efa6982875a4d5facb3" - [[package]] name = "block-buffer" version = "0.10.4" @@ -85,22 +59,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "chrono" -version = "0.4.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-integer", - "num-traits", - "serde", - "time", - "wasm-bindgen", - "winapi", -] - [[package]] name = "clipboard-win" version = "4.5.0" @@ -112,28 +70,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "core-foundation-sys" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" - [[package]] name = "cpufeatures" version = "0.2.6" @@ -153,63 +89,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "cxx" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 2.0.13", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.13", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn 1.0.109", -] - [[package]] name = "digest" version = "0.10.6" @@ -284,18 +163,6 @@ dependencies = [ "str-buf", ] -[[package]] -name = "fallible-iterator" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" - -[[package]] -name = "fallible-streaming-iterator" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" - [[package]] name = "fd-lock" version = "3.0.12" @@ -398,28 +265,10 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashlink" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69fe1fcf8b4278d860ad0548329f892a3631fb63f82574df68275f34cdbe0ffa" -dependencies = [ - "hashbrown", -] - [[package]] name = "hermit-abi" version = "0.2.6" @@ -452,30 +301,6 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" -[[package]] -name = "iana-time-zone" -version = "0.1.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" -dependencies = [ - "cxx", - "cxx-build", -] - [[package]] name = "idna" version = "0.3.0" @@ -546,26 +371,6 @@ version = "0.2.141" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" -[[package]] -name = "libsqlite3-sys" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] - [[package]] name = "linux-raw-sys" version = "0.3.1" @@ -605,7 +410,7 @@ checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys 0.45.0", ] @@ -634,30 +439,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" dependencies = [ "autocfg", - "bitflags 1.3.2", + "bitflags", "cfg-if", "libc", ] -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - [[package]] name = "num_cpus" version = "1.15.0" @@ -735,12 +521,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkg-config" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" - [[package]] name = "ppv-lite86" version = "0.2.17" @@ -811,7 +591,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] @@ -834,37 +614,13 @@ dependencies = [ "xmlparser", ] -[[package]] -name = "rusqlite" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2" -dependencies = [ - "bitflags 2.1.0", - "chrono", - "fallible-iterator", - "fallible-streaming-iterator", - "hashlink", - "libsqlite3-sys", - "smallvec", -] - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - [[package]] name = "rustix" version = "0.37.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" dependencies = [ - "bitflags 1.3.2", + "bitflags", "errno", "io-lifetimes", "libc", @@ -878,7 +634,7 @@ version = "10.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1e83c32c3f3c33b08496e0d1df9ea8c64d39adb8eb36a1ebb1440c690697aef" dependencies = [ - "bitflags 1.3.2", + "bitflags", "cfg-if", "clipboard-win", "dirs-next", @@ -907,18 +663,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "scratch" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" - -[[package]] -name = "semver" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" - [[package]] name = "serde" version = "1.0.160" @@ -965,10 +709,7 @@ dependencies = [ name = "shiritori" version = "0.1.0" dependencies = [ - "chrono", - "derive_more", "jisho", - "rusqlite", "serde", "serde_json", "simple-websockets", @@ -1058,15 +799,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - [[package]] name = "thiserror" version = "1.0.40" @@ -1087,17 +819,6 @@ dependencies = [ "syn 2.0.13", ] -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] - [[package]] name = "tinyvec" version = "1.6.0" @@ -1236,12 +957,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.4" @@ -1259,12 +974,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1341,30 +1050,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.0", -] - [[package]] name = "windows-sys" version = "0.45.0" diff --git a/Cargo.toml b/Cargo.toml index 7eefd21..6469755 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,10 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -chrono = { version = "0.4.24", features = ["serde"] } -derive_more = "0.99.17" jisho = "0.1.5" -rusqlite = { version = "0.29.0", features = ["chrono", "bundled"] } serde = { version = "1.0.160", features = ["serde_derive"] } serde_json = "1.0.95" simple-websockets = "0.1.5" diff --git a/src/database.rs b/src/database.rs deleted file mode 100644 index 59563be..0000000 --- a/src/database.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::Word; - -use derive_more::From; -use std::path::PathBuf; -use rusqlite::{Connection, Result, params}; - -pub struct Database { - conn: Connection, -} - -#[derive(From, Debug)] -pub enum DatabaseCreationError { - RusqliteError(rusqlite::Error), - IoError(std::io::Error), -} - -impl Database { - pub fn new( - testing: bool, - ) -> Result { - let conn = if testing { - Connection::open_in_memory() - } else { - let path = PathBuf::from("shiritori.db"); - //fs::create_dir_all(path.parent().unwrap())?; - Connection::open(path) - }?; - conn.execute( - "CREATE TABLE IF NOT EXISTS word ( - id INTEGER PRIMARY KEY, - word TEXT, reading TEXT, - timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, - )", - params![], - )?; - Ok(Self { conn }) - } - - pub fn load_words_before(&self, before_id: i64) -> Result> { - self.conn - .prepare("SELECT id, word, reading, timestamp FROM word WHERE id < ? DESC LIMIT 10")? - .query_map(params![before_id], |row| { - Ok(Word { - id: row.get(0)?, - word: row.get(1)?, - reading: row.get(2)?, - timestamp: row.get(3)?, - }) - })? - .collect::>>() - } -} diff --git a/src/dictionary.rs b/src/dictionary.rs deleted file mode 100644 index 6399e6c..0000000 --- a/src/dictionary.rs +++ /dev/null @@ -1,15 +0,0 @@ -use wana_kana::{ConvertJapanese, IsJapaneseStr}; - -pub fn lookup(input: &str) -> Option<&jisho::Entry> { - let input = input.trim(); - jisho::lookup(input).into_iter().find(|&word| ( - // If input has no kanji, - // we can just compare the input to the reading verbatim - // ensuring both are hiragana - (input.is_kana() && input.to_hiragana() == word.reading.to_hiragana()) || - // Otherwise, we have to ensure that the input - // is verbosely the same. - // However, this will cause problems for some words. - // For example, 照り焼き will be accepted but 照焼 won't. - (input == word.kanji))) -} diff --git a/src/main.rs b/src/main.rs index b51f3f0..f1a830f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,177 @@ -mod database; -pub use database::*; +use simple_websockets::{Event, Responder, Message}; +use std::collections::HashMap; +use serde::Serialize; +use wana_kana::{ConvertJapanese, IsJapaneseStr}; -mod dictionary; -pub use dictionary::*; +#[derive(Serialize)] +struct MessageResponse { + event: String, + data: MessageResponseData, +} -mod server; -pub use server::*; +impl MessageResponse { + fn to_message(&self) -> Message { + Message::Text(serde_json::to_string(&self).unwrap()) + } +} -mod word; -pub use word::*; +#[derive(Serialize)] +#[serde(untagged)] +enum MessageResponseData { + Greeting { + id: u64, + }, + Word { + author: u64, + word: String, + reading: Option, + next_char: char, + }, + PlayerCount { + players: u64, + }, + Error { + message: String, + }, +} + +impl MessageResponseData { + fn get_name(&self) -> String { + String::from(match self { + Self::Greeting { .. } => "greeting", + Self::Word { .. } => "word", + Self::PlayerCount { .. } => "playerCount", + Self::Error { .. } => "error", + }) + } + + fn to_response(self) -> MessageResponse { + MessageResponse { + event: self.get_name(), + data: self, + } + } + + fn to_message(self) -> Message { + self.to_response().to_message() + } +} + +fn broadcast_player_count(clients: &mut HashMap) { + let response = MessageResponseData::PlayerCount { players: clients.len() as u64 }.to_response(); + for (_client, responder) in clients.iter() { + responder.send(response.to_message()); + } +} + +fn lookup(input: &str) -> Option<&jisho::Entry> { + let input = input.trim(); + for word in jisho::lookup(input) { + if + // If input has no kanji, + // we can just compare the input to the reading verbatim + // ensuring both are hiragana + (input.is_kana() && input.to_hiragana() == word.reading.to_hiragana()) || + // Otherwise, we have to ensure that the input + // is verbosely the same. + // However, this will cause problems for some words. + // For example, 照り焼き will be accepted but 照焼 won't. + (input == word.kanji) { + return Some(word); + } + } + return None; +} fn main() { - const PORT: u16 = 8080; - let mut server = Server::new(PORT) - .unwrap_or_else(|_| panic!("Failed to start server at port {PORT}")); - server.run(); + let event_hub = simple_websockets::launch(8080) + .expect("failed to listen on port 8080"); + let mut clients: HashMap = HashMap::new(); + let mut next_char: Option = None; + let mut last_response: Option = None; + let mut last_client_id: Option = None; + loop { + match event_hub.poll_event() { + Event::Connect(client_id, responder) => { + println!("A client connected with id #{}", client_id); + responder.send(MessageResponseData::Greeting { id: client_id }.to_message()); + if let Some(ref last_response) = last_response { + responder.send(last_response.to_message()); + } + clients.insert(client_id, responder); + broadcast_player_count(&mut clients); + }, + Event::Disconnect(client_id) => { + println!("Client #{} disconnected.", client_id); + clients.remove(&client_id); + broadcast_player_count(&mut clients); + }, + Event::Message(client_id, message) => { + // Ignore binary messages + let message = match message { + Message::Text(message) => message, + Message::Binary(_) => return, + }; + + // Debug + println!("Received a message from client #{}: {:?}", client_id, message); + + let response = if Some(client_id) == last_client_id { + MessageResponseData::Error { + message: String::from("It's not your turn!"), + } + } else { + match lookup(&message) { + Some(entry) => { + if entry.reading.chars().last().unwrap().to_string().to_hiragana() == "ん" { + MessageResponseData::Error { + message: String::from("Can't end with ん!"), + } + } else if next_char.is_none() || entry.reading.chars().next().unwrap().to_string().to_hiragana().chars().next().unwrap() == next_char.unwrap() { + next_char = { + // If final character is lengthener or not kana + // Use semifinal + let mut final_chars = entry.reading.chars().rev(); + let final_char = final_chars.next().unwrap(); + Some(if final_char == 'ー' || !final_char.to_string().is_kana() { + final_chars.next().unwrap() + } else { + final_char + }.to_string().to_hiragana().chars().next().unwrap()) + }; + MessageResponseData::Word { + author: client_id, + word: entry.kanji.to_owned(), + reading: Some(entry.reading.to_owned()), + next_char: next_char.unwrap(), + } + } else { + MessageResponseData::Error { + message: String::from("Wrong starting kana!"), + } + } + } + None => MessageResponseData::Error { + message: String::from("Not in dictionary!"), + }, + } + }.to_response(); + + match response.data { + // Send errors to only this client + MessageResponseData::Error { .. } => { + clients.get(&client_id).unwrap().send(response.to_message()); + }, + // Broadcast everything else to all clients + _ => { + for (_client, responder) in clients.iter() { + responder.send(response.to_message()); + } + last_response = Some(response); + last_client_id = Some(client_id); + }, + } + }, + } + } } diff --git a/src/server.rs b/src/server.rs deleted file mode 100644 index f7efebb..0000000 --- a/src/server.rs +++ /dev/null @@ -1,181 +0,0 @@ -use crate::dictionary::lookup; - -use simple_websockets::{Event, Responder, Message, EventHub}; -use std::collections::HashMap; -use serde::Serialize; -use wana_kana::{ConvertJapanese, IsJapaneseStr}; - -#[derive(Serialize)] -struct MessageResponse { - event: String, - data: MessageResponseData, -} - -impl MessageResponse { - fn to_message(&self) -> Message { - Message::Text(serde_json::to_string(&self).unwrap()) - } -} - -#[derive(Serialize)] -#[serde(untagged)] -enum MessageResponseData { - Greeting { - id: u64, - }, - Word { - author: u64, - word: String, - reading: Option, - next_char: char, - }, - PlayerCount { - players: u64, - }, - Error { - message: String, - }, -} - -impl MessageResponseData { - fn get_name(&self) -> String { - String::from(match self { - Self::Greeting { .. } => "greeting", - Self::Word { .. } => "word", - Self::PlayerCount { .. } => "playerCount", - Self::Error { .. } => "error", - }) - } - - fn into_response(self) -> MessageResponse { - MessageResponse { - event: self.get_name(), - data: self, - } - } - - fn into_message(self) -> Message { - self.into_response().to_message() - } -} - -pub struct Server { - event_hub: EventHub, - clients: HashMap, - next_char: Option, - last_response: Option, - last_client_id: Option, -} - -impl Server { - pub fn new(port: u16) -> Result { - Ok(Server { - event_hub: simple_websockets::launch(port)?, - clients: HashMap::new(), - next_char: None, - last_response: None, - last_client_id: None, - }) - } - - pub fn run(&mut self) { - loop { - match self.event_hub.poll_event() { - Event::Connect(client_id, responder) => self.handle_connection(client_id, responder), - Event::Disconnect(client_id) => self.handle_disconnection(client_id), - Event::Message(client_id, message) => self.handle_message(client_id, message), - } - } - } - - fn broadcast_player_count(&self) { - let response = MessageResponseData::PlayerCount { players: self.clients.len() as u64 }.into_response(); - for (_client, responder) in self.clients.iter() { - responder.send(response.to_message()); - } - } - - fn handle_connection(&mut self, client_id: u64, responder: Responder) { - println!("A client connected with id #{}", client_id); - responder.send(MessageResponseData::Greeting { id: client_id }.into_message()); - if let Some(ref last_response) = self.last_response { - responder.send(last_response.to_message()); - } - self.clients.insert(client_id, responder); - self.broadcast_player_count(); - } - - fn handle_disconnection(&mut self, client_id: u64) { - println!("Client #{} disconnected.", client_id); - self.clients.remove(&client_id); - self.broadcast_player_count(); - } - - fn handle_message(&mut self, client_id: u64, message: Message) { - // Ignore binary messages - let message = match message { - Message::Text(message) => message, - Message::Binary(_) => return, - }; - - // Debug - println!("Received a message from client #{}: {:?}", client_id, message); - - let response = if Some(client_id) == self.last_client_id { - MessageResponseData::Error { - message: String::from("It's not your turn!"), - } - } else { - match lookup(&message) { - Some(entry) => { - if entry.reading.chars().last().unwrap().to_string().to_hiragana() == "ん" { - MessageResponseData::Error { - message: String::from("Can't end with ん!"), - } - } else if self.next_char.is_none() || entry.reading.chars().next().unwrap().to_string().to_hiragana().chars().next().unwrap() == self.next_char.unwrap() { - self.next_char = { - // If final character is lengthener or not kana - // Use semifinal - let mut final_chars = entry.reading.chars().rev(); - let final_char = final_chars.next().unwrap(); - Some(if final_char == 'ー' || !final_char.to_string().is_kana() { - final_chars.next().unwrap() - } else { - final_char - }.to_string().to_hiragana().chars().next().unwrap()) - }; - MessageResponseData::Word { - author: client_id, - word: entry.kanji.to_owned(), - reading: Some(entry.reading.to_owned()), - next_char: self.next_char.unwrap(), - } - } else { - MessageResponseData::Error { - message: String::from("Wrong starting kana!"), - } - } - } - None => MessageResponseData::Error { - message: String::from("Not in dictionary!"), - }, - } - }.into_response(); - - match response.data { - // Send errors to only this client - MessageResponseData::Error { .. } => { - self.clients.get(&client_id).unwrap().send(response.to_message()); - }, - // Broadcast everything else to all clients - _ => { - for (_client, responder) in self.clients.iter() { - responder.send(response.to_message()); - } - self.last_response = Some(response); - self.last_client_id = Some(client_id); - }, - } - - } -} diff --git a/src/word.rs b/src/word.rs deleted file mode 100644 index 08bc818..0000000 --- a/src/word.rs +++ /dev/null @@ -1,11 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::Serialize; - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Word { - pub id: i64, - pub word: String, - pub reading: String, - pub timestamp: DateTime, -}