Updating server and map interfaces

wip/yesman
Katharina Fey 4 years ago
parent 885fcaf2f2
commit a55c5bded0
Signed by: kookie
GPG Key ID: F972AEEA2887D547
  1. 43
      src/_if.rs
  2. 7
      src/main.rs
  3. 6
      src/map.rs
  4. 80
      src/server.rs
  5. 61
      src/users.rs
  6. 17
      src/wire/mod.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>;
}

@ -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,

@ -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!()
}

@ -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!()
}
}

@ -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())
}
}

@ -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

Loading…
Cancel
Save