aboutsummaryrefslogtreecommitdiff
path: root/games/rstnode/rst-server/src
diff options
context:
space:
mode:
Diffstat (limited to 'games/rstnode/rst-server/src')
-rw-r--r--games/rstnode/rst-server/src/constants.rs5
-rw-r--r--games/rstnode/rst-server/src/log.rs24
-rw-r--r--games/rstnode/rst-server/src/main.rs19
-rw-r--r--games/rstnode/rst-server/src/net/mod.rs43
-rw-r--r--games/rstnode/rst-server/src/net/parser.rs9
-rw-r--r--games/rstnode/rst-server/src/server.rs153
6 files changed, 190 insertions, 63 deletions
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!()
+ }
+}