Organize code, begin database implementation
This commit is contained in:
parent
376fba6795
commit
4e9784baf4
7 changed files with 594 additions and 177 deletions
183
src/main.rs
183
src/main.rs
|
@ -1,177 +1,18 @@
|
|||
use simple_websockets::{Event, Responder, Message};
|
||||
use std::collections::HashMap;
|
||||
use serde::Serialize;
|
||||
use wana_kana::{ConvertJapanese, IsJapaneseStr};
|
||||
mod database;
|
||||
pub use database::*;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct MessageResponse {
|
||||
event: String,
|
||||
data: MessageResponseData,
|
||||
}
|
||||
mod dictionary;
|
||||
pub use dictionary::*;
|
||||
|
||||
impl MessageResponse {
|
||||
fn to_message(&self) -> Message {
|
||||
Message::Text(serde_json::to_string(&self).unwrap())
|
||||
}
|
||||
}
|
||||
mod server;
|
||||
pub use server::*;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(untagged)]
|
||||
enum MessageResponseData {
|
||||
Greeting {
|
||||
id: u64,
|
||||
},
|
||||
Word {
|
||||
author: u64,
|
||||
word: String,
|
||||
reading: Option<String>,
|
||||
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<u64, Responder>) {
|
||||
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;
|
||||
}
|
||||
mod word;
|
||||
pub use word::*;
|
||||
|
||||
fn main() {
|
||||
let event_hub = simple_websockets::launch(8080)
|
||||
.expect("failed to listen on port 8080");
|
||||
let mut clients: HashMap<u64, Responder> = HashMap::new();
|
||||
let mut next_char: Option<char> = None;
|
||||
let mut last_response: Option<MessageResponse> = None;
|
||||
let mut last_client_id: Option<u64> = 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);
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
const PORT: u16 = 8080;
|
||||
let mut server = Server::new(PORT)
|
||||
.expect(&format!("Failed to start server at port {PORT}"));
|
||||
server.run();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue