diff options
Diffstat (limited to 'games/rstnode/rst-server/src/server.rs')
-rw-r--r-- | games/rstnode/rst-server/src/server.rs | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/games/rstnode/rst-server/src/server.rs b/games/rstnode/rst-server/src/server.rs new file mode 100644 index 000000000000..9badba85d1a6 --- /dev/null +++ b/games/rstnode/rst-server/src/server.rs @@ -0,0 +1,153 @@ +//! Game server state handler +//! +//! A server can host many lobbies at the same time. It listens for +//! connections according to a address given to the initialiser. + +use async_std::sync::{Arc, Mutex}; +use async_trait::async_trait; +use chrono::{DateTime, Utc}; +use rst_core::{ + data::Player, + lobby::LobbyList, + map::Map, + users::UserStore, + wire::{ + Action, AuthErr, Lobby, LobbyErr, LobbyId, LobbyUpdate, MatchErr, MatchId, RegErr, + Response, UpdateState, User, UserId, + }, + GameIf, Match, +}; +use std::{collections::BTreeMap, path::Path}; + +/// A convenience result wrapper for server actions +pub type ServerResult<T> = Result<T, ServerErr>; +pub enum ServerErr { + /// The requested directory is corrupted + NoSuchDir, + /// Corrupted game state + Corrupted, + /// No such match found + NoSuchMatch, +} + +/// The game's server backend +pub struct Server { + matches: BTreeMap<MatchId, Mutex<Match>>, + users: UserStore, + lobbies: LobbyList, +} + +impl Server { + /// Create a new game server + pub(crate) fn new() -> Arc<Self> { + Arc::new(Self { + matches: Default::default(), + users: UserStore::new(), + lobbies: LobbyList::new(), + }) + } + + /// Open the state dir of a game server + pub async fn open(self: Arc<Self>, path: &Path) -> ServerResult<()> { + Ok(()) + } + + /// Stop accepting new game connections and shutdown gracefully + /// + /// Returns the number of matches still going on. + pub async fn shutdown(self: Arc<Self>) -> ServerResult<u64> { + Ok(0) + } + + /// Save and close the statedir and kicking all players + /// + /// Returns the number of players that were kicked off the server + /// prematurely. + pub async fn kill(self: Arc<Self>) -> ServerResult<u64> { + Ok(0) + } + + // pub async fn update_map<F>(self: Arc<Self>, id: MatchId, cb: F) -> ServerResult<Response> + // where + // F: Fn(&mut Map) -> ServerResult<Response>, + // { + // match self.matches.get(&id) { + // Some(ref m) => m.lock().await.map.update(cb), + // None => Err(ServerErr::NoSuchMatch), + // } + // } + + pub async fn update_players<F>(self: Arc<Self>, id: MatchId, cb: F) -> ServerResult<Response> + where + F: Fn(&mut Vec<Player>) -> ServerResult<Response>, + { + match self.matches.get(&id) { + Some(ref mut m) => cb(&mut m.lock().await.players), + None => Err(ServerErr::NoSuchMatch), + } + } +} + +#[async_trait] +impl GameIf for Server { + async fn register(self: Arc<Self>, _name: String, _pw: String) -> Result<UserId, RegErr> { + todo!() + } + + async fn login(self: Arc<Self>, _name: String, _pw: String) -> Result<User, AuthErr> { + todo!() + } + + async fn logout(self: Arc<Self>, _user: User) -> Result<(), AuthErr> { + todo!() + } + + async fn anonymous(self: Arc<Self>, name: String) -> Result<User, AuthErr> { + // let (_, auth) = self.users.add(name, None, true).await; + // Ok(auth) + todo!() + } + + async fn join(self: Arc<Self>, user: User, lobby: LobbyId) -> Result<Lobby, LobbyErr> { + let mu = self.users.get(&user).await?; + self.lobbies.get_mut(lobby, |l| l.join(&mu)).await + } + + async fn leave(self: Arc<Self>, user: User, lobby: LobbyId) -> Result<(), LobbyErr> { + let mu = self.users.get(&user).await?; + self.lobbies.get_mut(lobby, |l| l.leave(&mu)).await + } + + async fn ready( + self: Arc<Self>, + user: User, + lobby: LobbyId, + ready: bool, + ) -> Result<LobbyUpdate, LobbyErr> { + self.lobbies.get_mut(lobby, |l| l.ready(user, ready)).await + } + + /// A start request was received + async fn start_req( + self: Arc<Self>, + user: UserId, + lobby: LobbyId, + ) -> Result<DateTime<Utc>, LobbyErr> { + self.lobbies.get_mut(lobby, |l| l.start(user)).await??; + let _lob = self.lobbies.consume(lobby).await?; + Ok(Utc::now()) + } + + async fn perform_action( + self: Arc<Self>, + user: User, + mtch: MatchId, + act: Action, + ) -> UpdateState { + unimplemented!() + } + + async fn leave_match(self: Arc<Self>, _user: User, _mtch: MatchId) -> Result<(), MatchErr> { + unimplemented!() + } +} |