aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKatharina Fey <kookie@spacekookie.de>2020-03-19 09:56:18 +0100
committerKatharina Fey <kookie@spacekookie.de>2020-03-19 09:56:18 +0100
commita55c5bded047e1e2c54f6e3f25c9b8e36e605110 (patch)
treeb388b829655f975cdc23130680ee4c4108ae0325
parent885fcaf2f272d898a265f1b7416ede5801240867 (diff)
Updating server and map interfaces
-rw-r--r--src/_if.rs43
-rw-r--r--src/main.rs7
-rw-r--r--src/map.rs6
-rw-r--r--src/server.rs80
-rw-r--r--src/users.rs61
-rw-r--r--src/wire/mod.rs17
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