Get rooms working
This commit is contained in:
parent
c4eece7ffd
commit
85cc6c2f35
9 changed files with 266 additions and 143 deletions
|
@ -11,11 +11,13 @@
|
|||
<div id="split">
|
||||
<div>
|
||||
<div id="shiritori"></div>
|
||||
<input id="shiritori-input" onfocusout="setTimeout(() => this.focus(), 100)" autofocus>
|
||||
<input id="shiritori-input" autocomplete="off" autofocus>
|
||||
</div>
|
||||
<iframe src="https://jisho.org"></iframe>
|
||||
</div>
|
||||
<p id="shiritori-players"></p>
|
||||
<button onclick="changeRoom('lobby')">Back to lobby</button>
|
||||
Change room: <input id="room-input" autocomplete="off">
|
||||
</div>
|
||||
<script src="shiritori.js"></script>
|
||||
</body>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
ws = new WebSocket("ws://localhost:8080");
|
||||
const div = document.querySelector("#shiritori");
|
||||
const input = document.querySelector("#shiritori-input");
|
||||
const roomInput = document.querySelector("#room-input");
|
||||
const players = document.querySelector("#shiritori-players");
|
||||
const iframe = document.querySelector("iframe");
|
||||
console.log("yo");
|
||||
let id = null;
|
||||
|
||||
function displayWord(_word, end, delay) {
|
||||
|
@ -29,6 +29,9 @@ function updateInput(data) {
|
|||
input.placeholder = waiting ? "Waiting for other players..." : `${data.next_mora}…`;
|
||||
input.disabled = waiting;
|
||||
if (!waiting) input.focus();
|
||||
} else {
|
||||
input.placeholder = "";
|
||||
input.focus();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,9 +43,11 @@ ws.onmessage = e => {
|
|||
const { event, data } = JSON.parse(e.data);
|
||||
switch (event) {
|
||||
case "greeting":
|
||||
id = data.id;
|
||||
div.innerHTML = "";
|
||||
updateInput(data);
|
||||
lookUpWord(data.word.word);
|
||||
if (typeof data.word !== "undefined") {
|
||||
lookUpWord(data.word.word);
|
||||
}
|
||||
break;
|
||||
case "word":
|
||||
displayWord(data.word, true, 0);
|
||||
|
@ -50,7 +55,6 @@ ws.onmessage = e => {
|
|||
lookUpWord(data.word.word);
|
||||
break;
|
||||
case "history":
|
||||
console.log(data);
|
||||
for (let i = 0; i < data.words.length; i++) {
|
||||
displayWord(data.words[i], false, 0.1 * i);
|
||||
}
|
||||
|
@ -67,7 +71,26 @@ ws.onmessage = e => {
|
|||
|
||||
input.addEventListener('keypress', e => {
|
||||
if (e.key === 'Enter') {
|
||||
ws.send(input.value);
|
||||
ws.send(JSON.stringify({
|
||||
word: {
|
||||
word: input.value
|
||||
}
|
||||
}));
|
||||
input.value = "";
|
||||
}
|
||||
});
|
||||
|
||||
function changeRoom(room) {
|
||||
ws.send(JSON.stringify({
|
||||
changeRoom: {
|
||||
name: room
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
roomInput.addEventListener('keypress', e => {
|
||||
if (e.key === 'Enter') {
|
||||
changeRoom(roomInput.value);
|
||||
roomInput.value = "";
|
||||
}
|
||||
})
|
||||
|
|
|
@ -9,6 +9,7 @@ body {
|
|||
height: 100vh;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
div#content {
|
||||
width: 32em;
|
||||
|
@ -36,7 +37,6 @@ div#shiritori {
|
|||
padding: 2px;
|
||||
height: 24em;
|
||||
overflow-y: scroll;
|
||||
text-align: center;
|
||||
}
|
||||
div#shiritori, input#shiritori-input, #split > :last-child {
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
|
@ -49,6 +49,9 @@ div#shiritori, input#shiritori-input {
|
|||
}
|
||||
input {
|
||||
font-size: 1em;
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
border: none;
|
||||
padding: 0.25em;
|
||||
}
|
||||
input#shiritori-input {
|
||||
width: 100%;
|
||||
|
@ -66,9 +69,6 @@ div#shiritori {
|
|||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
p#shiritori-players {
|
||||
text-align: center;
|
||||
}
|
||||
#split {
|
||||
display: flex;
|
||||
gap: 0.5em;
|
||||
|
@ -83,3 +83,10 @@ a {
|
|||
a:hover {
|
||||
border-bottom: 2px solid;
|
||||
}
|
||||
button {
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
font-size: inherit;
|
||||
cursor: pointer;
|
||||
padding: 1em;
|
||||
border: 0;
|
||||
}
|
||||
|
|
|
@ -100,6 +100,11 @@ impl Client {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns (old_room, &new_room)
|
||||
pub fn switch_rooms(&mut self, new_room: Rc<RefCell<Room>>) -> (Rc<RefCell<Room>>, Rc<RefCell<Room>>) {
|
||||
(std::mem::replace(&mut self.room, new_room), self.room.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Client {
|
||||
|
|
|
@ -3,38 +3,30 @@ use wana_kana::{ConvertJapanese, IsJapaneseStr};
|
|||
fn raw_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)
|
||||
)
|
||||
// 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)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn lookup(query: &str) -> Option<jisho::Entry> {
|
||||
match raw_lookup(&query) {
|
||||
match raw_lookup(query) {
|
||||
Some(result) => Some(result.clone()),
|
||||
None => {
|
||||
if query.is_hiragana() {
|
||||
// looking up ごりら doesn't return ゴリラ
|
||||
// jisho::lookup for some reason refers to input string,
|
||||
// so cloning is required
|
||||
match raw_lookup(&query.to_katakana()) {
|
||||
Some(entry) => Some(entry.clone()),
|
||||
None => None,
|
||||
}
|
||||
raw_lookup(&query.to_katakana()).cloned()
|
||||
} else if query.is_katakana() {
|
||||
// looking up シリトリ doesn't return 尻取り
|
||||
match raw_lookup(&query.to_hiragana()) {
|
||||
Some(entry) => Some(entry.clone()),
|
||||
None => None,
|
||||
}
|
||||
raw_lookup(&query.to_hiragana()).cloned()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ mod client;
|
|||
mod database;
|
||||
mod dictionary;
|
||||
mod response;
|
||||
mod request;
|
||||
mod room;
|
||||
mod server;
|
||||
mod utils;
|
||||
|
|
12
src/request.rs
Normal file
12
src/request.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum MessageRequest {
|
||||
Word {
|
||||
word: String,
|
||||
},
|
||||
ChangeRoom {
|
||||
name: String,
|
||||
},
|
||||
}
|
10
src/room.rs
10
src/room.rs
|
@ -16,12 +16,13 @@ use crate::word::Word;
|
|||
|
||||
use wana_kana::{ConvertJapanese, IsJapaneseStr};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RoomSettings {
|
||||
pub name: String,
|
||||
pub database_settings: DatabaseSettings,
|
||||
}
|
||||
|
||||
pub struct Room {
|
||||
name: String,
|
||||
database: Database,
|
||||
next_mora: Option<String>,
|
||||
last_client_id: Option<u64>,
|
||||
|
@ -30,12 +31,17 @@ pub struct Room {
|
|||
impl Room {
|
||||
pub fn new(settings: RoomSettings) -> Result<Self, DatabaseCreationError> {
|
||||
Ok(Self {
|
||||
name: settings.name,
|
||||
database: Database::new(settings.database_settings)?,
|
||||
next_mora: None,
|
||||
last_client_id: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn next_mora(&self) -> &Option<String> {
|
||||
&self.next_mora
|
||||
}
|
||||
|
@ -88,7 +94,7 @@ impl Room {
|
|||
} 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.into();
|
||||
self.next_mora = Some(get_final_mora(&word.reading));
|
||||
self.database.add_word(&word).unwrap(); // TODO: replace .unwrap() with ?
|
||||
self.last_client_id = Some(client_id);
|
||||
|
|
297
src/server.rs
297
src/server.rs
|
@ -1,13 +1,14 @@
|
|||
use crate::client::{Client, ClientInfo};
|
||||
use crate::database::{DatabaseCreationError, DatabaseSettings, DatabaseType};
|
||||
use crate::response::MessageResponseData;
|
||||
use crate::request::MessageRequest;
|
||||
use crate::room::{Room, RoomSettings};
|
||||
|
||||
use derive_more::From;
|
||||
use simple_websockets::{Event, EventHub, Message, Responder};
|
||||
use std::cell::RefCell;
|
||||
use std::cell::{RefCell, Ref};
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use std::rc::{Rc, Weak};
|
||||
|
||||
#[derive(From, Debug)]
|
||||
pub enum ServerCreationError {
|
||||
|
@ -18,6 +19,7 @@ pub enum ServerCreationError {
|
|||
#[derive(From, Debug)]
|
||||
pub enum ServerError {
|
||||
DatabaseError(rusqlite::Error),
|
||||
RoomCreationError(RoomCreationError),
|
||||
}
|
||||
|
||||
pub struct ServerSettings {
|
||||
|
@ -37,40 +39,92 @@ impl Default for ServerSettings {
|
|||
pub struct Server {
|
||||
event_hub: EventHub,
|
||||
lobby: Rc<RefCell<Room>>,
|
||||
rooms: HashMap<String, Room>,
|
||||
clients: HashMap<u64, Client>,
|
||||
rooms: HashMap<String, Weak<RefCell<Room>>>,
|
||||
clients: HashMap<u64, RefCell<Client>>,
|
||||
}
|
||||
|
||||
#[derive(From, Debug)]
|
||||
pub enum RoomCreationError {
|
||||
DatabaseCreationError(DatabaseCreationError),
|
||||
NameConflict,
|
||||
}
|
||||
|
||||
const LOBBY_NAME: &str = "lobby";
|
||||
|
||||
impl Server {
|
||||
pub fn new(settings: &ServerSettings) -> Result<Self, ServerCreationError> {
|
||||
let lobby = Rc::new(RefCell::new(Room::new(RoomSettings {
|
||||
name: LOBBY_NAME.to_string(),
|
||||
database_settings: DatabaseSettings {
|
||||
db_type: match settings.testing {
|
||||
true => DatabaseType::InMemory,
|
||||
false => DatabaseType::OnDisk("shiritori.sb".to_string()),
|
||||
},
|
||||
},
|
||||
})?));
|
||||
let lobby_weak = Rc::downgrade(&lobby);
|
||||
Ok(Self {
|
||||
event_hub: simple_websockets::launch(settings.port)?,
|
||||
lobby: Rc::new(RefCell::new(Room::new(RoomSettings {
|
||||
database_settings: DatabaseSettings {
|
||||
db_type: match settings.testing {
|
||||
true => DatabaseType::InMemory,
|
||||
false => DatabaseType::OnDisk("shiritori.sb".to_string()),
|
||||
},
|
||||
},
|
||||
..Default::default()
|
||||
})?)),
|
||||
rooms: HashMap::new(),
|
||||
lobby,
|
||||
rooms: {
|
||||
let mut rooms = HashMap::new();
|
||||
rooms.insert(LOBBY_NAME.to_string(), lobby_weak);
|
||||
rooms
|
||||
},
|
||||
clients: HashMap::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_client(&self, id: u64) -> Option<&Client> {
|
||||
self.clients.get(&id)
|
||||
}
|
||||
|
||||
pub fn run(&mut self) {
|
||||
loop {
|
||||
match match self.event_hub.poll_event() {
|
||||
Event::Connect(client_id, responder) => {
|
||||
self.handle_connection(client_id, responder)
|
||||
let client = self.new_client(client_id, responder);
|
||||
self.clients.insert(client_id, client);
|
||||
let client = self.clients.get(&client_id).unwrap().borrow(); // moved, get it again
|
||||
self.handle_connection(&client)
|
||||
}
|
||||
Event::Disconnect(client_id) => self.handle_disconnection(client_id),
|
||||
Event::Message(client_id, message) => self.handle_message(client_id, message),
|
||||
Event::Disconnect(client_id) => {
|
||||
let client = self.clients.remove(&client_id).unwrap();
|
||||
let client_ref = client.borrow();
|
||||
self.handle_disconnection(&client_ref)
|
||||
},
|
||||
Event::Message(client_id, message) => {
|
||||
println!("Received a message from client #{client_id}: {:?}", message);
|
||||
let message = match self.process_message(message) {
|
||||
Ok(message) => message,
|
||||
Err(error) => {
|
||||
let client = self.clients.get(&client_id).unwrap();
|
||||
let client_ref = client.borrow();
|
||||
client_ref.send(MessageResponseData::Error { message: error.to_string() }.into_message());
|
||||
continue;
|
||||
},
|
||||
};
|
||||
match message {
|
||||
MessageRequest::Word { word } => {
|
||||
let client = self.clients.get(&client_id).unwrap();
|
||||
let client_ref = client.borrow();
|
||||
match client_ref.room.borrow_mut().handle_query(&word, client_id) {
|
||||
// Broadcast new words to all clients in same room
|
||||
Ok(response) => self.announce_to_room(&client_ref.room, response),
|
||||
// Send errors to only this client
|
||||
Err(message) => {
|
||||
client_ref.send(
|
||||
MessageResponseData::Error {
|
||||
message: message.to_string(),
|
||||
}
|
||||
.into_message(),
|
||||
);
|
||||
},
|
||||
};
|
||||
Ok(())
|
||||
},
|
||||
MessageRequest::ChangeRoom { name } => {
|
||||
self.switch_rooms(client_id, name).unwrap();
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
},
|
||||
} {
|
||||
Ok(()) => {}
|
||||
Err(error) => println!("{:?}", error),
|
||||
|
@ -78,80 +132,128 @@ impl Server {
|
|||
}
|
||||
}
|
||||
|
||||
fn new_client(&mut self, client_id: u64, responder: Responder) -> &Client {
|
||||
let client = Client::new(
|
||||
fn new_client(&self, client_id: u64, responder: Responder) -> RefCell<Client> {
|
||||
RefCell::new(Client::new(
|
||||
ClientInfo::Ws {
|
||||
id: client_id,
|
||||
responder,
|
||||
discord_info: None,
|
||||
},
|
||||
self.lobby.clone(),
|
||||
);
|
||||
self.clients.insert(client_id, client);
|
||||
self.clients.get(&client_id).unwrap()
|
||||
))
|
||||
}
|
||||
|
||||
fn new_room(&mut self, name: &str) -> Result<Rc<RefCell<Room>>, RoomCreationError> {
|
||||
if self.rooms.contains_key(name) {
|
||||
return Err(RoomCreationError::NameConflict);
|
||||
}
|
||||
let room = Rc::new(RefCell::new(Room::new(RoomSettings {
|
||||
name: name.to_owned(),
|
||||
database_settings: DatabaseSettings {
|
||||
db_type: DatabaseType::InMemory,
|
||||
},
|
||||
})?));
|
||||
self.rooms.insert(name.to_owned(), Rc::downgrade(&room));
|
||||
Ok(room)
|
||||
}
|
||||
|
||||
fn switch_rooms(&mut self, client_id: u64, room_name: String) -> Result<(), ServerError> {
|
||||
let room = self.rooms.get(&room_name)
|
||||
// upgrade Weak to Rc if exists
|
||||
.and_then(|weak| weak.upgrade()) // Option<Weak<RefCell<Room>>> -> Option<Option<Rc<RefCell<Room>>>>
|
||||
.map(Ok) // Option<Rc<RefCell<Room>>> -> Option<Result<Rc<RefCell<Room>>>>
|
||||
// if not exists OR failed to upgrade (value dropped), it will be None.
|
||||
// in that case, initialize a new room
|
||||
.unwrap_or_else(|| self.new_room(&room_name))?;
|
||||
let client = self.clients.get(&client_id).unwrap();
|
||||
let (old_room, room) = {
|
||||
let mut client_mut = client.borrow_mut();
|
||||
// Skip logic and return if going into same room
|
||||
if client_mut.room.borrow().name().eq(&room_name) {
|
||||
return Ok(());
|
||||
}
|
||||
client_mut.switch_rooms(room)
|
||||
};
|
||||
// Clean up old room to be dropped
|
||||
// However, lobby will never be dropped
|
||||
let old_room = if Rc::strong_count(&old_room) <= 1 {
|
||||
if !Rc::ptr_eq(&old_room, &self.lobby) {
|
||||
self.rooms.remove(old_room.borrow().name());
|
||||
println!("Removing room, {}!", old_room.borrow().name());
|
||||
};
|
||||
None
|
||||
} else {
|
||||
Some(old_room)
|
||||
};
|
||||
// broadcast reference count minus one
|
||||
// (We still have an Rc hanging around here)
|
||||
//self.broadcast_offseted_player_count(&old_room, -1);
|
||||
if let Some(old_room) = old_room {
|
||||
self.broadcast_player_count(&old_room);
|
||||
}
|
||||
self.broadcast_player_count(&room);
|
||||
|
||||
self.room_welcome(&client.borrow())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_connection(
|
||||
&mut self,
|
||||
client_id: u64,
|
||||
responder: Responder,
|
||||
&self,
|
||||
client: &Ref<Client>,
|
||||
) -> Result<(), ServerError> {
|
||||
// Debug
|
||||
println!("A client connected with id #{}", client_id);
|
||||
println!("A client connected with id #{}", client.id());
|
||||
|
||||
{
|
||||
// Initialize client
|
||||
let client = self.new_client(client_id, responder);
|
||||
|
||||
// Get immutable access to room
|
||||
let room = client.room.borrow();
|
||||
|
||||
// Send client greeting
|
||||
client.send(
|
||||
MessageResponseData::Greeting {
|
||||
id: client_id,
|
||||
next_mora: room.next_mora().clone(),
|
||||
}
|
||||
.into_message(),
|
||||
);
|
||||
|
||||
// Sent recent message history
|
||||
client.send(
|
||||
MessageResponseData::History {
|
||||
words: room.get_history()?,
|
||||
}
|
||||
.into_message(),
|
||||
);
|
||||
}
|
||||
self.room_welcome(client)?;
|
||||
|
||||
// Number of clients on Rc<RefCell<Room>> reference counter will be one more
|
||||
self.broadcast_player_count(&self.lobby);
|
||||
self.broadcast_player_count(&client.room);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_disconnection(&mut self, client_id: u64) -> Result<(), ServerError> {
|
||||
fn room_welcome(&self, client: &Ref<Client>) -> Result<(), ServerError> {
|
||||
// Get immutable access to room
|
||||
let room = client.room.borrow();
|
||||
|
||||
// Send client greeting
|
||||
client.send(
|
||||
MessageResponseData::Greeting {
|
||||
id: client.id(),
|
||||
next_mora: room.next_mora().clone(),
|
||||
}
|
||||
.into_message(),
|
||||
);
|
||||
|
||||
// Sent recent message history
|
||||
client.send(
|
||||
MessageResponseData::History {
|
||||
words: room.get_history()?,
|
||||
}
|
||||
.into_message(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_disconnection(&self, client: &Ref<Client>) -> Result<(), ServerError> {
|
||||
let client_id = client.id();
|
||||
|
||||
// Debug
|
||||
println!("Client #{} disconnected.", client_id);
|
||||
|
||||
// Remove client
|
||||
// At this point, client should be dropped
|
||||
let client = self.clients.remove(&client_id).unwrap();
|
||||
|
||||
// Get room
|
||||
let room = client.room;
|
||||
println!("Client #{client_id} disconnected.");
|
||||
|
||||
// Number of clients on Rc<RefCell<Room>> reference counter will be one less
|
||||
self.broadcast_player_count(&room);
|
||||
self.broadcast_player_count(&client.room);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn for_client_in_room(&self, room: &Rc<RefCell<Room>>, mut closure: impl FnMut(&Client) -> ()) {
|
||||
for (_id, client) in self
|
||||
fn for_client_in_room(&self, room: &Rc<RefCell<Room>>, mut closure: impl FnMut(Ref<Client>)) {
|
||||
for client in self
|
||||
.clients
|
||||
.iter()
|
||||
.filter(|(_id, client)| Rc::<RefCell<Room>>::ptr_eq(room, &client.room))
|
||||
.filter(|(_id, client)| Rc::<RefCell<Room>>::ptr_eq(room, &client.borrow().room))
|
||||
.map(|(_id, refcell)| refcell.borrow())
|
||||
{
|
||||
closure(client);
|
||||
}
|
||||
|
@ -164,13 +266,14 @@ impl Server {
|
|||
}
|
||||
|
||||
fn broadcast_player_count(&self, room: &Rc<RefCell<Room>>) {
|
||||
let response = MessageResponseData::PlayerCount {
|
||||
players: self.client_count_in_room(room) as u64,
|
||||
}
|
||||
.into_response();
|
||||
for (_id, client) in self.clients.iter() {
|
||||
client.send(response.to_message());
|
||||
}
|
||||
self.broadcast_offseted_player_count(room, 0);
|
||||
}
|
||||
|
||||
fn broadcast_offseted_player_count(&self, room: &Rc<RefCell<Room>>, offset: i32) {
|
||||
let players = (self.client_count_in_room(room) as i32 + offset) as u64;
|
||||
println!("Broadcast player count {players} for room {}", room.borrow().name());
|
||||
let response = MessageResponseData::PlayerCount { players };
|
||||
self.announce_to_room(room, response);
|
||||
}
|
||||
|
||||
fn announce_to_room(&self, room: &Rc<RefCell<Room>>, response_data: MessageResponseData) {
|
||||
|
@ -180,44 +283,16 @@ impl Server {
|
|||
});
|
||||
}
|
||||
|
||||
fn handle_message(&mut self, client_id: u64, message: Message) -> Result<(), ServerError> {
|
||||
fn process_message(&self, message: Message) -> Result<MessageRequest, &str> {
|
||||
// Ignore binary messages
|
||||
let message = match message {
|
||||
Message::Text(message) => {
|
||||
// Debug
|
||||
println!(
|
||||
"Received a message from client #{}: {:?}",
|
||||
client_id, message
|
||||
);
|
||||
|
||||
message
|
||||
}
|
||||
Message::Binary(message) => {
|
||||
// Debug
|
||||
println!(
|
||||
"Received a binary message from client #{}: {:?}",
|
||||
client_id, message
|
||||
);
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
let message: MessageRequest = match serde_json::from_str(&match message {
|
||||
Message::Text(message) => message,
|
||||
Message::Binary(_message) => return Err("Invalid request."),
|
||||
}) {
|
||||
Ok(message) => message,
|
||||
Err(_) => return Err("Invalid request."),
|
||||
};
|
||||
|
||||
let client = self.get_client(client_id).unwrap();
|
||||
|
||||
match client.room.borrow_mut().handle_query(&message, client_id) {
|
||||
// Broadcast new words to all clients in same room
|
||||
Ok(response) => self.announce_to_room(&client.room, response),
|
||||
// Send errors to only this client
|
||||
Err(message) => {
|
||||
client.send(
|
||||
MessageResponseData::Error {
|
||||
message: message.to_string(),
|
||||
}
|
||||
.into_message(),
|
||||
);
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
Ok(message)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue