diff options
author | Katharina Fey <kookie@spacekookie.de> | 2020-03-19 09:56:18 +0100 |
---|---|---|
committer | Katharina Fey <kookie@spacekookie.de> | 2020-03-19 09:56:18 +0100 |
commit | a55c5bded047e1e2c54f6e3f25c9b8e36e605110 (patch) | |
tree | b388b829655f975cdc23130680ee4c4108ae0325 | |
parent | 885fcaf2f272d898a265f1b7416ede5801240867 (diff) |
Updating server and map interfaces
-rw-r--r-- | src/_if.rs | 43 | ||||
-rw-r--r-- | src/main.rs | 7 | ||||
-rw-r--r-- | src/map.rs | 6 | ||||
-rw-r--r-- | src/server.rs | 80 | ||||
-rw-r--r-- | src/users.rs | 61 | ||||
-rw-r--r-- | src/wire/mod.rs | 17 |
6 files changed, 190 insertions, 24 deletions
diff --git a/src/_if.rs b/src/_if.rs new file mode 100644 index 000000000000..91cb3a2daf18 --- /dev/null +++ b/src/_if.rs @@ -0,0 +1,43 @@ +//! A common trait interface between the server and the client + +use crate::wire::{ + Action, AuthErr, Lobby, LobbyId, MatchErr, MatchId, RegErr, RoomErr, RoomUpdate, UpdateState, + User, UserId, +}; +use async_trait::async_trait; +use async_std::sync::Arc; +use chrono::{DateTime, Utc}; + +/// The main game interface implemented by the server and client +#[async_trait] +pub trait GameIf { + /// Register a new user on a game server + async fn register(self: Arc<Self>, name: String, pw: String) -> Result<UserId, RegErr>; + + /// Login for an existing user + async fn login(self: Arc<Self>, name: String, pw: String) -> Result<User, AuthErr>; + + /// End a user session (go offline) + async fn logout(self: Arc<Self>, user: User) -> Result<(), AuthErr>; + + /// Register as an anonymous player + async fn anonymous(self: Arc<Self>, name: String) -> Result<User, AuthErr>; + + /// Join a match-making lobby + async fn join(self: Arc<Self>, user: User, lobby: LobbyId) -> Result<Lobby, RoomErr>; + + /// Leave a match-making lobby + async fn leave(self: Arc<Self>, user: User, lobby: LobbyId) -> Result<(), RoomErr>; + + /// Set the player's ready state + async fn ready(self: Arc<Self>, user: User, lobby: LobbyId, ready: bool) -> RoomUpdate; + + /// Send a start request (as lobby admin) + async fn start_req(self: Arc<Self>, user: User, lobby: LobbyId) -> DateTime<Utc>; + + /// Perform a game action as a user + async fn perform_action(self: Arc<Self>, user: User, mtch: MatchId, act: Action) -> UpdateState; + + /// Leave a match + async fn leave_match(self: Arc<Self>, user: User, mtch: MatchId) -> Result<(), MatchErr>; +} diff --git a/src/main.rs b/src/main.rs index e51b38750ead..976a99af2895 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,17 @@ #![allow(warnings)] +mod _if; mod data; mod gens; mod io; +mod lobby; mod map; +mod server; mod stats; +mod users; mod wire; -mod server; + +pub(crate) use identity::Identity as Id; use ggez::{ self, conf, diff --git a/src/map.rs b/src/map.rs index 6d279db468e3..f977bec93e1d 100644 --- a/src/map.rs +++ b/src/map.rs @@ -2,7 +2,7 @@ use crate::{ data::{Link, Node}, - server::{Result, ServerErr}, + server::{ServerResult, ServerErr}, wire::Response }; use async_std::sync::Arc; @@ -28,9 +28,9 @@ impl Map { Arc::new(Self::default()) } - pub fn update<F>(&mut self, cb: F) -> Result<Response> + pub fn update<F>(&mut self, cb: F) -> ServerResult<Response> where - F: Fn(&mut Map) -> Result<Response>, + F: Fn(&mut Map) -> ServerResult<Response>, { unimplemented!() } diff --git a/src/server.rs b/src/server.rs index d8be64ee7b95..6ddfb70a9d41 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,12 +1,19 @@ use crate::{ + _if::GameIf, map::Map, - wire::{Match, MatchId, MatchUser, Response, User, UserId}, + users::UserStore, + wire::{ + Action, AuthErr, Lobby, LobbyId, Match, MatchErr, MatchId, MatchUser, RegErr, Response, + RoomErr, RoomUpdate, UpdateState, User, UserId, + }, }; -use async_std::sync::{Arc, Mutex}; +use async_std::sync::{Arc, Mutex, RwLock}; +use async_trait::async_trait; +use chrono::{DateTime, Utc}; use std::{collections::BTreeMap, path::Path}; /// A convenience result wrapper for server actions -pub type Result<T> = std::result::Result<T, ServerErr>; +pub type ServerResult<T> = Result<T, ServerErr>; pub enum ServerErr { /// The requested directory is corrupted NoSuchDir, @@ -19,7 +26,7 @@ pub enum ServerErr { /// The game's server backend pub struct Server { matches: BTreeMap<MatchId, Mutex<Match>>, - users: BTreeMap<UserId, User>, + users: UserStore, } impl Server { @@ -27,19 +34,19 @@ impl Server { fn new() -> Self { Self { matches: Default::default(), - users: Default::default(), + users: UserStore::new(), } } /// Open the state dir of a game server - pub async fn open(self: Arc<Self>, path: &Path) -> Result<()> { + 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>) -> Result<u64> { + pub async fn shutdown(self: Arc<Self>) -> ServerResult<u64> { Ok(0) } @@ -47,13 +54,13 @@ impl Server { /// /// Returns the number of players that were kicked off the server /// prematurely. - pub async fn kill(self: Arc<Self>) -> Result<u64> { + pub async fn kill(self: Arc<Self>) -> ServerResult<u64> { Ok(0) } - pub async fn update_map<F>(self: Arc<Self>, id: MatchId, cb: F) -> Result<Response> + pub async fn update_map<F>(self: Arc<Self>, id: MatchId, cb: F) -> ServerResult<Response> where - F: Fn(&mut Map) -> Result<Response>, + F: Fn(&mut Map) -> ServerResult<Response>, { match self.matches.get(&id) { Some(ref mut m) => m.lock().await.map.update(cb), @@ -61,9 +68,9 @@ impl Server { } } - pub async fn update_players<F>(self: Arc<Self>, id: MatchId, cb: F) -> Result<Response> + pub async fn update_players<F>(self: Arc<Self>, id: MatchId, cb: F) -> ServerResult<Response> where - F: Fn(&mut Vec<MatchUser>) -> Result<Response>, + F: Fn(&mut Vec<MatchUser>) -> ServerResult<Response>, { match self.matches.get(&id) { Some(ref mut m) => cb(&mut m.lock().await.players), @@ -71,3 +78,52 @@ impl Server { } } } + +#[async_trait] +impl GameIf for Server { + async fn register(self: Arc<Self>, name: String, pw: String) -> Result<UserId, RegErr> { + unimplemented!() + } + + async fn login(self: Arc<Self>, name: String, pw: String) -> Result<User, AuthErr> { + unimplemented!() + } + + async fn logout(self: Arc<Self>, user: User) -> Result<(), AuthErr> { + unimplemented!() + } + + async fn anonymous(self: Arc<Self>, name: String) -> Result<User, AuthErr> { + let (_, auth) = self.users.add(name, None, true).await; + Ok(auth) + } + + async fn join(self: Arc<Self>, user: User, lobby: LobbyId) -> Result<Lobby, RoomErr> { + unimplemented!() + } + + async fn leave(self: Arc<Self>, user: User, lobby: LobbyId) -> Result<(), RoomErr> { + unimplemented!() + } + + async fn ready(self: Arc<Self>, user: User, lobby: LobbyId, ready: bool) -> RoomUpdate { + unimplemented!() + } + + async fn start_req(self: Arc<Self>, user: User, lobby: LobbyId) -> DateTime<Utc> { + unimplemented!() + } + + 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!() + } +} diff --git a/src/users.rs b/src/users.rs new file mode 100644 index 000000000000..edc3c13fe3b1 --- /dev/null +++ b/src/users.rs @@ -0,0 +1,61 @@ +//! A users abstraction module + +use crate::{ + wire::{User, UserId}, + Id, +}; +use async_std::sync::{Arc, RwLock}; +use std::{ + collections::BTreeMap, + sync::atomic::{AtomicUsize, Ordering}, +}; + +pub struct MetaUser { + pub id: UserId, + pub name: String, + pub pw: String, + pub auth: User, +} + +pub struct UserStore { + max: AtomicUsize, + users: RwLock<BTreeMap<UserId, Arc<MetaUser>>>, +} + +impl UserStore { + /// Currently resuming a userstore isn't possible + pub fn new() -> Self { + UserStore { + max: 0.into(), + users: Default::default(), + } + } + + pub async fn add<S: Into<Option<String>>>( + &self, + name: String, + pw: S, + registered: bool, + ) -> (UserId, User) { + let id = self.max.fetch_add(1, Ordering::Relaxed); + let token = Id::random(); + let pw = pw.into().unwrap_or("".into()); + let auth = User { + id, + token, + registered, + }; + + self.users.write().await.insert( + id, + MetaUser { + id, + name, + pw, + auth: auth.clone(), + } + .into(), + ); + (id, auth.clone()) + } +} diff --git a/src/wire/mod.rs b/src/wire/mod.rs index 78d618627d34..bf8dea0e8131 100644 --- a/src/wire/mod.rs +++ b/src/wire/mod.rs @@ -15,6 +15,7 @@ pub use update::*; use crate::{ data::{Color, Player}, map::Map, + Id, }; use serde::{Deserialize, Serialize}; @@ -22,27 +23,27 @@ use serde::{Deserialize, Serialize}; pub type UserId = usize; /// Represents a user payload -#[derive(Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize)] pub struct User { /// The internal user ID - id: UserId, + pub id: UserId, /// The auth token provided by the client - token: String, + pub token: Id, /// Whether the scores will be tracked - registered: bool, + pub registered: bool, } /// A more lobby specific abstraction for a user #[derive(Serialize, Deserialize)] pub struct LobbyUser { /// The user ID - id: UserId, + pub id: UserId, /// Their nick name - name: String, + pub name: String, /// Are they ready? - ready: bool, + pub ready: bool, /// The colour they will be in the match - color: Color, + pub color: Color, } /// An alias for a Room ID |