diff options
author | Katharina Fey <kookie@spacekookie.de> | 2021-02-14 00:06:14 +0100 |
---|---|---|
committer | Katharina Fey <kookie@spacekookie.de> | 2021-02-14 00:06:14 +0100 |
commit | effbdeed66e8de8e769b8ac069926ad1a9110e62 (patch) | |
tree | e4522354e53266204aa9962caccde55d8c815092 /games/rstnode/rst-server | |
parent | 5dab336049dbc6817e9ff212998690f59f6bbfa8 (diff) |
* Add an inbox/ outbox system to server components
* Define a data flow from Request -> computation -> Update
* Create simple handlers to call server or client code for requests
Diffstat (limited to '')
-rw-r--r-- | games/rstnode/rst-server/Cargo.toml | 12 | ||||
-rw-r--r-- | games/rstnode/rst-server/src/constants.rs | 5 | ||||
-rw-r--r-- | games/rstnode/rst-server/src/log.rs | 24 | ||||
-rw-r--r-- | games/rstnode/rst-server/src/main.rs | 19 | ||||
-rw-r--r-- | games/rstnode/rst-server/src/net/mod.rs | 43 | ||||
-rw-r--r-- | games/rstnode/rst-server/src/net/parser.rs | 9 | ||||
-rw-r--r-- | games/rstnode/rst-server/src/server.rs | 153 |
7 files changed, 199 insertions, 66 deletions
diff --git a/games/rstnode/rst-server/Cargo.toml b/games/rstnode/rst-server/Cargo.toml index bf175b81325d..8903e637fc3f 100644 --- a/games/rstnode/rst-server/Cargo.toml +++ b/games/rstnode/rst-server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rst-node-server" -description = "Backend game server" +description = "RST Node game server" version = "0.0.0" edition = "2018" license = "AGPL-3.0-or-later" @@ -8,6 +8,12 @@ authors = ["Bread Machine", "Katharina Fey <kookie@spacekookie.de>"] [dependencies] rst-core = { path = "../rst-core" } -async-std = { version = "1.0", features = ["attributes"] } +async-std = { version = "1.0", features = ["unstable", "attributes"] } +async-trait = "0.1" + +chrono = { version = "0.4", features = ["serde"] } tracing = "0.1" -tracing-subscriber = "0.2"
\ No newline at end of file +tracing-subscriber = "0.2" +num_cpus = "1.0" +systemstat = "0.1" + diff --git a/games/rstnode/rst-server/src/constants.rs b/games/rstnode/rst-server/src/constants.rs index e40a5c35c5db..8dc23f7c68d8 100644 --- a/games/rstnode/rst-server/src/constants.rs +++ b/games/rstnode/rst-server/src/constants.rs @@ -1,5 +1,6 @@ - - pub const NAME: &'static str = "RST Node"; pub const VERSION: &'static str = env!("CARGO_PKG_VERSION"); pub const AUTHORS: &'static str = env!("CARGO_PKG_AUTHORS"); + +pub const DEFAULT_BIND: &'static str = "0.0.0.0"; +pub const DEFAULT_PORT: u16 = 10022; diff --git a/games/rstnode/rst-server/src/log.rs b/games/rstnode/rst-server/src/log.rs index 62d03167bb7a..676395134a59 100644 --- a/games/rstnode/rst-server/src/log.rs +++ b/games/rstnode/rst-server/src/log.rs @@ -8,8 +8,15 @@ const BANNER: &'static str = " ██║ ██║███████║ ██║ ██║ ╚████║╚██████╔╝██████╔╝███████╗ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚══════╝"; +use systemstat::{Platform, System}; use tracing_subscriber::{filter::LevelFilter, fmt, EnvFilter}; +#[cfg(not(target_os = "windows"))] +const PLATFORM_DISCLAIMER: &'static str = "Platform: Unspecified *nix-like"; +#[cfg(target_os = "windows")] +static PLATFORM_DISCLAIMER: &'static str = + "WARNING: Windows server hosts are not officially supported!"; + pub(crate) fn initialise() { let filter = EnvFilter::try_from_env("RST_LOG") .unwrap_or_default() @@ -19,13 +26,24 @@ pub(crate) fn initialise() { // Initialise the logger fmt().with_env_filter(filter).init(); - info!("Initialising server..."); + info!("Initialising..."); info!("{}", BANNER); - info!("Available cores: unknown"); - info!("Available RAM: unknown"); + info!("{}", PLATFORM_DISCLAIMER); + info!("Available cores: {}", num_cpus::get()); + info!("Available RAM: {}", mem()); info!("Version: {}", crate::constants::VERSION); } +fn mem() -> String { + let sys = System::new(); + let mem = sys.memory().unwrap(); + format!( + "{} / {}", + mem.free.to_string_as(true), + mem.total.to_string_as(true) + ) +} + #[macro_export] macro_rules! fatal { () => { diff --git a/games/rstnode/rst-server/src/main.rs b/games/rstnode/rst-server/src/main.rs index d3335e941ca8..fbdd33bb864d 100644 --- a/games/rstnode/rst-server/src/main.rs +++ b/games/rstnode/rst-server/src/main.rs @@ -1,15 +1,22 @@ +//! RST Node game server + +// Remove the warning spam +#![allow(warnings)] + #[macro_use] extern crate tracing; -mod constants; -mod log; -mod net; -use net::ServerEndpoint; +pub(crate) mod constants; +pub(crate) mod log; + +use rst_core::net::Endpoint; #[async_std::main] async fn main() { log::initialise(); - let serv = ServerEndpoint::new("0.0.0.0:10022").await; - serv.listen().await; + let addr = format!("{}:{}", constants::DEFAULT_BIND, constants::DEFAULT_PORT); + let serv = Endpoint::new(addr.as_str()).await; + // serv.listen().await; + // net::run().await; } diff --git a/games/rstnode/rst-server/src/net/mod.rs b/games/rstnode/rst-server/src/net/mod.rs deleted file mode 100644 index deb35f7f89b9..000000000000 --- a/games/rstnode/rst-server/src/net/mod.rs +++ /dev/null @@ -1,43 +0,0 @@ -#![allow(unused)] - -mod parser; - -use async_std::{ - net::UdpSocket, - sync::{Arc, RwLock}, - task, -}; -use rst_core::Id; -use std::{collections::BTreeMap, net::SocketAddr}; - -pub struct ServerEndpoint { - socket: UdpSocket, - bind: String, - clients: RwLock<BTreeMap<Id, Client>>, -} - -impl ServerEndpoint { - pub async fn new(bind: &str) -> Arc<Self> { - let socket = UdpSocket::bind(bind).await.unwrap(); - Arc::new(Self { - socket, - bind: bind.into(), - clients: Default::default(), - }) - } - - pub async fn listen(self: &Arc<Self>) { - let mut buf = vec![0; 1024]; - - info!("Listening for connections on {}", self.bind); - - loop { - let (_, peer) = self.socket.recv_from(&mut buf).await.unwrap(); - } - } -} - -pub struct Client { - addr: SocketAddr, -} - diff --git a/games/rstnode/rst-server/src/net/parser.rs b/games/rstnode/rst-server/src/net/parser.rs deleted file mode 100644 index d320e13095bb..000000000000 --- a/games/rstnode/rst-server/src/net/parser.rs +++ /dev/null @@ -1,9 +0,0 @@ -use rst_core::wire::Request; - -pub async fn request(req: Request) { - use Request::*; - match req { - Register(name, pw) => {}, - _ => todo!(), - } -} 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!() + } +} |