WIP - break server logic into two files
This commit is contained in:
parent
254bbe8723
commit
0f36ab55f2
2 changed files with 142 additions and 132 deletions
134
server/src/lib.rs
Normal file
134
server/src/lib.rs
Normal file
|
@ -0,0 +1,134 @@
|
|||
use rocket::serde::{Deserialize, Serialize};
|
||||
use rocket::tokio::sync::broadcast::Sender;
|
||||
use rocket::tokio::sync::RwLock;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{LazyLock, Weak};
|
||||
use word_grid::api::{APIGame, ApiState, Update};
|
||||
use word_grid::dictionary::{Dictionary, DictionaryImpl};
|
||||
use word_grid::game::{Error, PlayedTile};
|
||||
use word_grid::player_interaction::ai::Difficulty;
|
||||
use ws::frame::{CloseCode, CloseFrame};
|
||||
|
||||
pub static DICTIONARY: LazyLock<DictionaryImpl> =
|
||||
LazyLock::new(|| DictionaryImpl::create_from_path("../resources/dictionary.csv"));
|
||||
|
||||
pub fn escape_characters(x: &str) -> String {
|
||||
let x = x
|
||||
.replace("&", "&")
|
||||
.replace("<", "<")
|
||||
.replace(">", ">");
|
||||
|
||||
x
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, PartialEq)]
|
||||
pub struct Player {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Debug)]
|
||||
pub struct PartyInfo {
|
||||
pub ais: Vec<Difficulty>,
|
||||
pub players: Vec<Player>,
|
||||
}
|
||||
|
||||
impl PartyInfo {
|
||||
fn new(host: Player) -> Self {
|
||||
Self {
|
||||
ais: Vec::new(),
|
||||
players: vec![host],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Room {
|
||||
pub party_info: PartyInfo,
|
||||
pub game: Option<APIGame>,
|
||||
pub sender: Sender<(Option<Player>, InnerRoomMessage)>,
|
||||
}
|
||||
|
||||
impl Room {
|
||||
pub fn new(host: Player) -> Self {
|
||||
Self {
|
||||
party_info: PartyInfo::new(host),
|
||||
game: None,
|
||||
sender: Sender::new(5),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum RoomEvent {
|
||||
PlayerJoined { player: Player },
|
||||
PlayerLeft { player: Player },
|
||||
AIJoined { difficulty: Difficulty },
|
||||
AILeft { index: usize },
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum GameEvent {
|
||||
TurnAction { state: ApiState, committed: bool },
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum ServerToClientMessage {
|
||||
RoomChange { event: RoomEvent, info: PartyInfo },
|
||||
GameEvent { event: GameEvent },
|
||||
GameError { error: Error },
|
||||
Invalid { reason: String },
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum GameMove {
|
||||
Pass,
|
||||
Exchange {
|
||||
tiles: Vec<bool>,
|
||||
},
|
||||
Play {
|
||||
played_tiles: Vec<Option<PlayedTile>>,
|
||||
commit_move: bool,
|
||||
},
|
||||
AddToDictionary {
|
||||
word: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum ClientToServerMessage {
|
||||
Load,
|
||||
StartGame,
|
||||
GameMove { r#move: GameMove },
|
||||
AddAI { difficulty: Difficulty },
|
||||
RemoveAI { index: usize },
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum InnerRoomMessage {
|
||||
PassThrough(ServerToClientMessage),
|
||||
GameEvent(Option<Update>),
|
||||
}
|
||||
|
||||
pub type RoomMap = HashMap<String, Weak<RwLock<Room>>>;
|
||||
|
||||
pub fn reject_websocket_with_reason(
|
||||
ws: ws::WebSocket,
|
||||
close_code: CloseCode,
|
||||
reason: String,
|
||||
) -> ws::Channel<'static> {
|
||||
ws.channel(move |mut stream| {
|
||||
Box::pin(async move {
|
||||
let closeframe = CloseFrame {
|
||||
code: close_code,
|
||||
reason: reason.into(),
|
||||
};
|
||||
let _ = stream.close(Some(closeframe)).await;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
})
|
||||
}
|
|
@ -10,125 +10,19 @@ use rocket::tokio::sync::broadcast::Sender;
|
|||
use rocket::tokio::sync::{Mutex, RwLock};
|
||||
use rocket::tokio::time::interval;
|
||||
use rocket::{tokio, State};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, LazyLock, Weak};
|
||||
use server::{
|
||||
escape_characters, reject_websocket_with_reason, ClientToServerMessage, GameEvent, GameMove,
|
||||
InnerRoomMessage, Player, Room, RoomEvent, RoomMap, ServerToClientMessage, DICTIONARY,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::select;
|
||||
use word_grid::api::{APIGame, ApiState, Update};
|
||||
use word_grid::dictionary::{Dictionary, DictionaryImpl};
|
||||
use word_grid::game::{Error, Game, PlayedTile};
|
||||
use word_grid::player_interaction::ai::Difficulty;
|
||||
use ws::frame::{CloseCode, CloseFrame};
|
||||
use word_grid::api::{APIGame, Update};
|
||||
use word_grid::game::Game;
|
||||
use ws::frame::CloseCode;
|
||||
use ws::stream::DuplexStream;
|
||||
use ws::Message;
|
||||
|
||||
static DICTIONARY: LazyLock<DictionaryImpl> =
|
||||
LazyLock::new(|| DictionaryImpl::create_from_path("../resources/dictionary.csv"));
|
||||
|
||||
fn escape_characters(x: &str) -> String {
|
||||
let x = x
|
||||
.replace("&", "&")
|
||||
.replace("<", "<")
|
||||
.replace(">", ">");
|
||||
|
||||
x
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, PartialEq)]
|
||||
struct Player {
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Debug)]
|
||||
struct PartyInfo {
|
||||
ais: Vec<Difficulty>,
|
||||
players: Vec<Player>,
|
||||
}
|
||||
|
||||
impl PartyInfo {
|
||||
fn new(host: Player) -> Self {
|
||||
Self {
|
||||
ais: Vec::new(),
|
||||
players: vec![host],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Room {
|
||||
party_info: PartyInfo,
|
||||
game: Option<APIGame>,
|
||||
sender: Sender<(Option<Player>, InnerRoomMessage)>,
|
||||
}
|
||||
|
||||
impl Room {
|
||||
fn new(host: Player) -> Self {
|
||||
Self {
|
||||
party_info: PartyInfo::new(host),
|
||||
game: None,
|
||||
sender: Sender::new(5),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
enum RoomEvent {
|
||||
PlayerJoined { player: Player },
|
||||
PlayerLeft { player: Player },
|
||||
AIJoined { difficulty: Difficulty },
|
||||
AILeft { index: usize },
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
enum GameEvent {
|
||||
TurnAction { state: ApiState, committed: bool },
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
enum ServerToClientMessage {
|
||||
RoomChange { event: RoomEvent, info: PartyInfo },
|
||||
GameEvent { event: GameEvent },
|
||||
GameError { error: Error },
|
||||
Invalid { reason: String },
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
enum GameMove {
|
||||
Pass,
|
||||
Exchange {
|
||||
tiles: Vec<bool>,
|
||||
},
|
||||
Play {
|
||||
played_tiles: Vec<Option<PlayedTile>>,
|
||||
commit_move: bool,
|
||||
},
|
||||
AddToDictionary {
|
||||
word: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
enum ClientToServerMessage {
|
||||
Load,
|
||||
StartGame,
|
||||
GameMove { r#move: GameMove },
|
||||
AddAI { difficulty: Difficulty },
|
||||
RemoveAI { index: usize },
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum InnerRoomMessage {
|
||||
PassThrough(ServerToClientMessage),
|
||||
GameEvent(Option<Update>),
|
||||
}
|
||||
|
||||
type RoomMap = HashMap<String, Weak<RwLock<Room>>>;
|
||||
|
||||
async fn incoming_message_handler<E: std::fmt::Display>(
|
||||
message: Option<Result<Message, E>>,
|
||||
sender: &Sender<(Option<Player>, InnerRoomMessage)>,
|
||||
|
@ -357,24 +251,6 @@ async fn outgoing_message_handler<E: std::fmt::Debug>(
|
|||
}
|
||||
}
|
||||
|
||||
fn reject_websocket_with_reason(
|
||||
ws: ws::WebSocket,
|
||||
close_code: CloseCode,
|
||||
reason: String,
|
||||
) -> ws::Channel<'static> {
|
||||
ws.channel(move |mut stream| {
|
||||
Box::pin(async move {
|
||||
let closeframe = CloseFrame {
|
||||
code: close_code,
|
||||
reason: reason.into(),
|
||||
};
|
||||
let _ = stream.close(Some(closeframe)).await;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
#[get("/room/<id>?<player_name>")]
|
||||
async fn room(
|
||||
id: &str,
|
||||
|
|
Loading…
Reference in a new issue