master
Elnu 2 years ago
parent ed11799bf5
commit c4eece7ffd

@ -13,11 +13,11 @@
use crate::room::Room; use crate::room::Room;
use std::cmp::{PartialEq, Eq}; use simple_websockets::{Message, Responder};
use std::cell::RefCell;
use std::cmp::{Eq, PartialEq};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::rc::Rc; use std::rc::Rc;
use std::cell::RefCell;
use simple_websockets::{Responder, Message};
pub struct DiscordInfo { pub struct DiscordInfo {
pub username: String, pub username: String,
@ -47,7 +47,9 @@ pub enum ClientInfo {
impl ClientInfo { impl ClientInfo {
fn id(&self) -> u64 { fn id(&self) -> u64 {
match self { match self {
Self::Ws { id, discord_info, .. } => match discord_info { Self::Ws {
id, discord_info, ..
} => match discord_info {
// Discord-verified websocket connection // Discord-verified websocket connection
Some(discord_info) => discord_info.id, Some(discord_info) => discord_info.id,
// Anonymous websocket connection // Anonymous websocket connection
@ -93,7 +95,9 @@ impl Client {
pub fn send(&self, message: Message) -> bool { pub fn send(&self, message: Message) -> bool {
match &self.info { match &self.info {
ClientInfo::Ws { responder, .. } => responder.send(message), ClientInfo::Ws { responder, .. } => responder.send(message),
ClientInfo::Discord { .. } => unimplemented!("no networking implementation for Discord connections"), ClientInfo::Discord { .. } => {
unimplemented!("no networking implementation for Discord connections")
}
} }
} }
} }

@ -1,8 +1,8 @@
use crate::word::Word; use crate::word::Word;
use derive_more::From; use derive_more::From;
use rusqlite::{params, Connection, Result};
use std::path::PathBuf; use std::path::PathBuf;
use rusqlite::{Connection, Result, params};
pub struct Database { pub struct Database {
conn: Connection, conn: Connection,
@ -46,10 +46,11 @@ impl Database {
.prepare("SELECT id FROM word ORDER BY id DESC LIMIT 1")? .prepare("SELECT id FROM word ORDER BY id DESC LIMIT 1")?
.query_map(params![], |row| row.get(0))? .query_map(params![], |row| row.get(0))?
.collect::<Result<Vec<i64>>>()? .collect::<Result<Vec<i64>>>()?
.first() { .first()
Some(id) => *id, {
None => 0, // first database entry is id 1 Some(id) => *id,
}; None => 0, // first database entry is id 1
};
Ok(Self { conn, last_word_id }) Ok(Self { conn, last_word_id })
} }
@ -70,10 +71,7 @@ impl Database {
pub fn add_word(&mut self, word: &Word) -> Result<()> { pub fn add_word(&mut self, word: &Word) -> Result<()> {
self.conn.execute( self.conn.execute(
"INSERT INTO word (word, reading) VALUES (?1, ?2)", "INSERT INTO word (word, reading) VALUES (?1, ?2)",
params![ params![word.word, word.reading,],
word.word,
word.reading,
],
)?; )?;
self.last_word_id += 1; self.last_word_id += 1;
Ok(()) Ok(())

@ -2,7 +2,8 @@ use wana_kana::{ConvertJapanese, IsJapaneseStr};
fn raw_lookup(input: &str) -> Option<&jisho::Entry> { fn raw_lookup(input: &str) -> Option<&jisho::Entry> {
let input = input.trim(); let input = input.trim();
jisho::lookup(input).into_iter().find(|&word| ( jisho::lookup(input).into_iter().find(|&word| {
(
// If input has no kanji, // If input has no kanji,
// we can just compare the input to the reading verbatim // we can just compare the input to the reading verbatim
// ensuring both are hiragana // ensuring both are hiragana
@ -11,7 +12,9 @@ fn raw_lookup(input: &str) -> Option<&jisho::Entry> {
// is verbosely the same. // is verbosely the same.
// However, this will cause problems for some words. // However, this will cause problems for some words.
// For example, 照り焼き will be accepted but 照焼 won't. // For example, 照り焼き will be accepted but 照焼 won't.
(input == word.kanji))) (input == word.kanji)
)
})
} }
pub fn lookup(query: &str) -> Option<jisho::Entry> { pub fn lookup(query: &str) -> Option<jisho::Entry> {

@ -11,7 +11,11 @@ use crate::server::{Server, ServerSettings};
fn main() { fn main() {
let settings = ServerSettings::default(); let settings = ServerSettings::default();
let mut server = Server::new(&settings) let mut server = Server::new(&settings).unwrap_or_else(|error| {
.unwrap_or_else(|error| panic!("Failed to start server at port {}: {:?}", settings.port, error)); panic!(
"Failed to start server at port {}: {:?}",
settings.port, error
)
});
server.run(); server.run();
} }

@ -11,10 +11,10 @@
use crate::database::{Database, DatabaseCreationError, DatabaseSettings}; use crate::database::{Database, DatabaseCreationError, DatabaseSettings};
use crate::dictionary::lookup; use crate::dictionary::lookup;
use crate::response::MessageResponseData; use crate::response::MessageResponseData;
use crate::utils::{get_starting_mora, get_final_mora}; use crate::utils::{get_final_mora, get_starting_mora};
use crate::word::Word; use crate::word::Word;
use wana_kana::{IsJapaneseStr, ConvertJapanese}; use wana_kana::{ConvertJapanese, IsJapaneseStr};
#[derive(Default)] #[derive(Default)]
pub struct RoomSettings { pub struct RoomSettings {
@ -41,11 +41,16 @@ impl Room {
} }
pub fn get_history(&self) -> rusqlite::Result<Vec<Word>> { pub fn get_history(&self) -> rusqlite::Result<Vec<Word>> {
self.database.load_words_before(self.database.last_word_id + 1) self.database
.load_words_before(self.database.last_word_id + 1)
} }
// Err(&str) will be converted to MessageResponseData::Error // Err(&str) will be converted to MessageResponseData::Error
pub fn handle_query(&mut self, query: &str, client_id: u64) -> Result<MessageResponseData, &str> { pub fn handle_query(
&mut self,
query: &str,
client_id: u64,
) -> Result<MessageResponseData, &str> {
// Ensure query isn't from last player // Ensure query isn't from last player
if Some(client_id) == self.last_client_id { if Some(client_id) == self.last_client_id {
return Err("It's not your turn!"); return Err("It's not your turn!");
@ -70,9 +75,19 @@ impl Room {
// Send result // Send result
match dictionary_result { match dictionary_result {
Some(entry) => { Some(entry) => {
if entry.reading.chars().last().unwrap().to_string().to_hiragana() == "ん" { if entry
.reading
.chars()
.last()
.unwrap()
.to_string()
.to_hiragana()
== "ん"
{
Err("Can't end with ん!") Err("Can't end with ん!")
} else if self.next_mora.is_none() || get_starting_mora(&entry.reading).eq(self.next_mora.as_deref().unwrap()) { } else if self.next_mora.is_none()
|| get_starting_mora(&entry.reading).eq(self.next_mora.as_deref().unwrap())
{
let word: Word = entry.clone().into(); let word: Word = entry.clone().into();
self.next_mora = Some(get_final_mora(&word.reading)); self.next_mora = Some(get_final_mora(&word.reading));
self.database.add_word(&word).unwrap(); // TODO: replace .unwrap() with ? self.database.add_word(&word).unwrap(); // TODO: replace .unwrap() with ?

@ -1,13 +1,13 @@
use crate::client::{Client, ClientInfo}; use crate::client::{Client, ClientInfo};
use crate::database::{DatabaseSettings, DatabaseType, DatabaseCreationError}; use crate::database::{DatabaseCreationError, DatabaseSettings, DatabaseType};
use crate::response::MessageResponseData; use crate::response::MessageResponseData;
use crate::room::{Room, RoomSettings}; use crate::room::{Room, RoomSettings};
use derive_more::From;
use simple_websockets::{Event, EventHub, Message, Responder};
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use std::cell::RefCell;
use simple_websockets::{Event, Responder, Message, EventHub};
use derive_more::From;
#[derive(From, Debug)] #[derive(From, Debug)]
pub enum ServerCreationError { pub enum ServerCreationError {
@ -66,27 +66,36 @@ impl Server {
pub fn run(&mut self) { pub fn run(&mut self) {
loop { loop {
match match self.event_hub.poll_event() { match match self.event_hub.poll_event() {
Event::Connect(client_id, responder) => self.handle_connection(client_id, responder), Event::Connect(client_id, responder) => {
self.handle_connection(client_id, responder)
}
Event::Disconnect(client_id) => self.handle_disconnection(client_id), Event::Disconnect(client_id) => self.handle_disconnection(client_id),
Event::Message(client_id, message) => self.handle_message(client_id, message), Event::Message(client_id, message) => self.handle_message(client_id, message),
} { } {
Ok(()) => {}, Ok(()) => {}
Err(error) => println!("{:?}", error), Err(error) => println!("{:?}", error),
} }
} }
} }
fn new_client(&mut self, client_id: u64, responder: Responder) -> &Client { fn new_client(&mut self, client_id: u64, responder: Responder) -> &Client {
let client = Client::new(ClientInfo::Ws { let client = Client::new(
id: client_id, ClientInfo::Ws {
responder, id: client_id,
discord_info: None, responder,
}, self.lobby.clone()); discord_info: None,
},
self.lobby.clone(),
);
self.clients.insert(client_id, client); self.clients.insert(client_id, client);
self.clients.get(&client_id).unwrap() self.clients.get(&client_id).unwrap()
} }
fn handle_connection(&mut self, client_id: u64, responder: Responder) -> Result<(), ServerError> { fn handle_connection(
&mut self,
client_id: u64,
responder: Responder,
) -> Result<(), ServerError> {
// Debug // Debug
println!("A client connected with id #{}", client_id); println!("A client connected with id #{}", client_id);
@ -98,15 +107,21 @@ impl Server {
let room = client.room.borrow(); let room = client.room.borrow();
// Send client greeting // Send client greeting
client.send(MessageResponseData::Greeting { client.send(
id: client_id, MessageResponseData::Greeting {
next_mora: room.next_mora().clone(), id: client_id,
}.into_message()); next_mora: room.next_mora().clone(),
}
.into_message(),
);
// Sent recent message history // Sent recent message history
client.send(MessageResponseData::History { client.send(
words: room.get_history()?, MessageResponseData::History {
}.into_message()); words: room.get_history()?,
}
.into_message(),
);
} }
// Number of clients on Rc<RefCell<Room>> reference counter will be one more // Number of clients on Rc<RefCell<Room>> reference counter will be one more
@ -133,7 +148,11 @@ impl Server {
} }
fn for_client_in_room(&self, room: &Rc<RefCell<Room>>, mut closure: impl FnMut(&Client) -> ()) { fn for_client_in_room(&self, room: &Rc<RefCell<Room>>, mut closure: impl FnMut(&Client) -> ()) {
for (_id, client) in self.clients.iter().filter(|(_id, client)| Rc::<RefCell<Room>>::ptr_eq(room, &client.room)) { for (_id, client) in self
.clients
.iter()
.filter(|(_id, client)| Rc::<RefCell<Room>>::ptr_eq(room, &client.room))
{
closure(client); closure(client);
} }
} }
@ -145,7 +164,10 @@ impl Server {
} }
fn broadcast_player_count(&self, room: &Rc<RefCell<Room>>) { fn broadcast_player_count(&self, room: &Rc<RefCell<Room>>) {
let response = MessageResponseData::PlayerCount { players: self.client_count_in_room(room) as u64 }.into_response(); let response = MessageResponseData::PlayerCount {
players: self.client_count_in_room(room) as u64,
}
.into_response();
for (_id, client) in self.clients.iter() { for (_id, client) in self.clients.iter() {
client.send(response.to_message()); client.send(response.to_message());
} }
@ -163,13 +185,19 @@ impl Server {
let message = match message { let message = match message {
Message::Text(message) => { Message::Text(message) => {
// Debug // Debug
println!("Received a message from client #{}: {:?}", client_id, message); println!(
"Received a message from client #{}: {:?}",
client_id, message
);
message message
} }
Message::Binary(message) => { Message::Binary(message) => {
// Debug // Debug
println!("Received a binary message from client #{}: {:?}", client_id, message); println!(
"Received a binary message from client #{}: {:?}",
client_id, message
);
return Ok(()); return Ok(());
} }
@ -182,7 +210,12 @@ impl Server {
Ok(response) => self.announce_to_room(&client.room, response), Ok(response) => self.announce_to_room(&client.room, response),
// Send errors to only this client // Send errors to only this client
Err(message) => { Err(message) => {
client.send(MessageResponseData::Error { message: message.to_string() }.into_message()); client.send(
MessageResponseData::Error {
message: message.to_string(),
}
.into_message(),
);
} }
}; };
Ok(()) Ok(())

@ -38,10 +38,13 @@ pub fn get_final_mora(word: &str) -> String {
let mut iter = word.chars().rev(); let mut iter = word.chars().rev();
let final_char = iter.next().unwrap(); let final_char = iter.next().unwrap();
match final_char { match final_char {
'ゃ' | 'ゅ' | 'ょ' => format!("{}{final_char}", match iter.next() { 'ゃ' | 'ゅ' | 'ょ' => format!(
Some(c) => c.to_string(), "{}{final_char}",
None => String::from(""), match iter.next() {
}), Some(c) => c.to_string(),
None => String::from(""),
}
),
_ => final_char.to_string(), _ => final_char.to_string(),
} }
} }

@ -1,6 +1,6 @@
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::Serialize;
use jisho::Entry; use jisho::Entry;
use serde::Serialize;
use std::convert::From; use std::convert::From;
#[derive(Serialize)] #[derive(Serialize)]

Loading…
Cancel
Save