* 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 requestswip/yesman
parent
5dab336049
commit
effbdeed66
@ -0,0 +1,61 @@ |
||||
//! Logging specifics
|
||||
|
||||
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() |
||||
.add_directive(LevelFilter::DEBUG.into()) |
||||
.add_directive("async_std=error".parse().unwrap()) |
||||
.add_directive("gfx_device_gl=error".parse().unwrap()) |
||||
.add_directive("ggez=error".parse().unwrap()) |
||||
.add_directive("selectors=error".parse().unwrap()) |
||||
.add_directive("gilrs=error".parse().unwrap()) |
||||
.add_directive("mio=error".parse().unwrap()); |
||||
|
||||
// Initialise the logger
|
||||
fmt().with_env_filter(filter).init(); |
||||
info!("Initialising..."); |
||||
info!("{}", BANNER); |
||||
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 { |
||||
() => { |
||||
error!("Unknown failure!"); |
||||
std::process::exit(2) |
||||
}; |
||||
($($arg:tt)*) => ({ |
||||
error!($($arg)*); |
||||
std::process::exit(2) |
||||
}) |
||||
} |
@ -0,0 +1 @@ |
||||
//! Client networking endpoint logic
|
@ -0,0 +1,70 @@ |
||||
#![allow(unused)] |
||||
|
||||
use super::ClientState; |
||||
use async_trait::async_trait; |
||||
use chrono::{DateTime, Utc}; |
||||
use rst_core::{ |
||||
wire::{ |
||||
game::Action, AuthErr, Lobby, LobbyErr, LobbyId, LobbyUpdate, MatchErr, MatchId, RegErr, |
||||
UpdateState, User, UserId, |
||||
}, |
||||
GameIf, Match, |
||||
}; |
||||
use std::sync::Arc; |
||||
|
||||
#[async_trait] |
||||
impl GameIf for ClientState { |
||||
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> { |
||||
todo!() |
||||
} |
||||
|
||||
async fn join(self: Arc<Self>, user: User, lobby: LobbyId) -> Result<Lobby, LobbyErr> { |
||||
todo!() |
||||
} |
||||
|
||||
async fn leave(self: Arc<Self>, user: User, lobby: LobbyId) -> Result<(), LobbyErr> { |
||||
todo!() |
||||
} |
||||
|
||||
async fn ready( |
||||
self: Arc<Self>, |
||||
user: User, |
||||
lobby: LobbyId, |
||||
ready: bool, |
||||
) -> Result<LobbyUpdate, LobbyErr> { |
||||
todo!() |
||||
} |
||||
|
||||
async fn start_req( |
||||
self: Arc<Self>, |
||||
user: UserId, |
||||
lobby: LobbyId, |
||||
) -> Result<DateTime<Utc>, LobbyErr> { |
||||
todo!() |
||||
} |
||||
|
||||
async fn perform_action( |
||||
self: Arc<Self>, |
||||
user: User, |
||||
mtch: MatchId, |
||||
act: Action, |
||||
) -> UpdateState { |
||||
todo!() |
||||
} |
||||
|
||||
async fn leave_match(self: Arc<Self>, user: User, mtch: MatchId) -> Result<(), MatchErr> { |
||||
todo!() |
||||
} |
||||
} |
@ -0,0 +1,10 @@ |
||||
use rst_core::map::{Map, MapNode}; |
||||
|
||||
/// Client map state wrapper
|
||||
///
|
||||
/// The map state is calculated by the server and updates are streamed
|
||||
/// to all clients in a [Match](rst_core::Match).
|
||||
pub struct MapState { |
||||
inner: Map, |
||||
} |
||||
|
@ -0,0 +1,51 @@ |
||||
pub use crate::wire::{AuthErr, LobbyErr, MatchErr, RegErr}; |
||||
use serde::{Deserialize, Serialize}; |
||||
use std::fmt::{self, Display, Formatter}; |
||||
|
||||
/// A wrapper around the different RST node errors that can occur
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)] |
||||
pub enum Error { |
||||
/// Failure in the registration process
|
||||
Register(RegErr), |
||||
/// Failure in the authentication process
|
||||
Auth(AuthErr), |
||||
/// Failure handling a lobby
|
||||
Lobby(LobbyErr), |
||||
/// Failure in a match setting
|
||||
Match(MatchErr), |
||||
} |
||||
|
||||
impl std::error::Error for Error {} |
||||
|
||||
impl Display for Error { |
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
||||
write!(f, "An RST error") |
||||
} |
||||
} |
||||
|
||||
/// A RST Node specific error
|
||||
pub type Result<T> = std::result::Result<T, Error>; |
||||
|
||||
impl From<RegErr> for Error { |
||||
fn from(e: RegErr) -> Self { |
||||
Error::Register(e) |
||||
} |
||||
} |
||||
|
||||
impl From<AuthErr> for Error { |
||||
fn from(e: AuthErr) -> Self { |
||||
Error::Auth(e) |
||||
} |
||||
} |
||||
|
||||
impl From<LobbyErr> for Error { |
||||
fn from(e: LobbyErr) -> Self { |
||||
Error::Lobby(e) |
||||
} |
||||
} |
||||
|
||||
impl From<MatchErr> for Error { |
||||
fn from(e: MatchErr) -> Self { |
||||
Error::Match(e) |
||||
} |
||||
} |
@ -0,0 +1,78 @@ |
||||
use crate::wire::{ |
||||
game::{Action, Update}, |
||||
Lobby, |
||||
}; |
||||
|
||||
use async_std::sync::RwLock; |
||||
use std::collections::VecDeque; |
||||
|
||||
pub enum ClientUpdate { |
||||
/// Change to the lobby state
|
||||
Lobby(Lobby), |
||||
/// A game simulation update
|
||||
GameUpdate(Update), |
||||
} |
||||
|
||||
impl<'l> From<&'l Lobby> for ClientUpdate { |
||||
fn from(l: &'l Lobby) -> Self { |
||||
ClientUpdate::Lobby(l.clone()) |
||||
} |
||||
} |
||||
|
||||
impl<'l> From<&'l Update> for ClientUpdate { |
||||
fn from(u: &'l Update) -> Self { |
||||
ClientUpdate::GameUpdate(u.clone()) |
||||
} |
||||
} |
||||
|
||||
/// A message out buffer that can be attached to any server entity
|
||||
pub struct Outbox { |
||||
queue: RwLock<VecDeque<ClientUpdate>>, |
||||
} |
||||
|
||||
impl Outbox { |
||||
pub fn new() -> Self { |
||||
Self { |
||||
queue: Default::default(), |
||||
} |
||||
} |
||||
|
||||
/// Queue a new item to send out
|
||||
pub async fn queue(&self, update: impl Into<ClientUpdate>) { |
||||
let mut q = self.queue.write().await; |
||||
q.push_back(update.into()); |
||||
} |
||||
|
||||
/// Run a closure for all queued items
|
||||
pub async fn run_for<F: Fn(&ClientUpdate)>(&self, handle: F) { |
||||
let q = self.queue.read().await; |
||||
q.iter().for_each(|item| handle(item)); |
||||
} |
||||
|
||||
/// Clear the outbox for the next update interval
|
||||
pub async fn clear(&self) { |
||||
self.queue.write().await.clear(); |
||||
} |
||||
} |
||||
|
||||
pub struct Inbox { |
||||
queue: RwLock<VecDeque<Action>>, |
||||
} |
||||
|
||||
impl Inbox { |
||||
pub fn new() -> Self { |
||||
Self { |
||||
queue: Default::default(), |
||||
} |
||||
} |
||||
|
||||
/// Queue a new item to send out
|
||||
pub async fn queue(&self, update: impl Into<Action>) { |
||||
let mut q = self.queue.write().await; |
||||
q.push_back(update.into()); |
||||
} |
||||
|
||||
pub async fn pop(&self) -> Option<Action> { |
||||
self.queue.write().await.pop_front() |
||||
} |
||||
} |
@ -0,0 +1,49 @@ |
||||
use crate::{server::Server, Id}; |
||||
use async_std::{ |
||||
net::UdpSocket, |
||||
sync::{Arc, RwLock}, |
||||
task, |
||||
}; |
||||
use std::{ |
||||
collections::BTreeMap, |
||||
net::SocketAddr, |
||||
sync::atomic::{AtomicBool, Ordering}, |
||||
}; |
||||
|
||||
pub struct Endpoint { |
||||
running: AtomicBool, |
||||
socket: UdpSocket, |
||||
bind: String, |
||||
clients: RwLock<BTreeMap<Id, Client>>, |
||||
} |
||||
|
||||
pub struct Client {} |
||||
|
||||
impl Endpoint { |
||||
pub async fn new(bind: &str) -> Arc<Self> { |
||||
let socket = UdpSocket::bind(bind).await.unwrap(); |
||||
Arc::new(Self { |
||||
running: true.into(), |
||||
socket, |
||||
bind: bind.into(), |
||||
clients: Default::default(), |
||||
}) |
||||
} |
||||
|
||||
/// Stop the endpoint
|
||||
pub fn stop(self: &Arc<Self>) { |
||||
self.running.store(false, Ordering::Relaxed); |
||||
} |
||||
|
||||
pub async fn listen(self: &Arc<Self>, serv: Arc<Server>) { |
||||
let mut buf = vec![0; 1024]; |
||||
|
||||
info!("Listening for connections on {}", self.bind); |
||||
while self.running.load(Ordering::Relaxed) { |
||||
let (int, peer) = self.socket.recv_from(&mut buf).await.unwrap(); |
||||
if int > 1024 { |
||||
warn!("Read a larger chunk than buffer?"); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,52 @@ |
||||
use crate::{ |
||||
error::Error, |
||||
wire::{ |
||||
AuthErr, Lobby, LobbyErr, LobbyId, LobbyUpdate, MatchErr, RegErr, Response, UpdateState, |
||||
User, UserId, |
||||
}, |
||||
}; |
||||
use chrono::{DateTime, Utc}; |
||||
|
||||
pub fn register(r: Result<UserId, RegErr>) -> Response { |
||||
Response::Register(r) |
||||
} |
||||
|
||||
pub fn login(r: Result<User, AuthErr>) -> Response { |
||||
Response::Login(r) |
||||
} |
||||
|
||||
pub fn logout(r: Result<(), AuthErr>) -> Response { |
||||
Response::Logout(r) |
||||
} |
||||
|
||||
pub fn rooms(r: Vec<(String, LobbyId)>) -> Response { |
||||
Response::Rooms(r) |
||||
} |
||||
|
||||
pub fn join(r: Result<Lobby, LobbyErr>) -> Response { |
||||
Response::Join(r) |
||||
} |
||||
|
||||
pub fn leave(r: Result<(), LobbyErr>) -> Response { |
||||
Response::Leave(r) |
||||
} |
||||
|
||||
pub fn ready(r: LobbyUpdate) -> Response { |
||||
Response::Ready(r) |
||||
} |
||||
|
||||
pub fn start_req(r: DateTime<Utc>) -> Response { |
||||
Response::StartReq(r) |
||||
} |
||||
|
||||
pub fn game_update(r: UpdateState) -> Response { |
||||
Response::GameUpdate(r) |
||||
} |
||||
|
||||
pub fn leave_game(r: Result<(), MatchErr>) -> Response { |
||||
Response::LeaveGame(r) |
||||
} |
||||
|
||||
pub fn invalid() -> Response { |
||||
Response::Invalid |
||||
} |
@ -0,0 +1,17 @@ |
||||
use crate::{ |
||||
net::Client, |
||||
server::Server, |
||||
wire::{Request, Response}, |
||||
}; |
||||
use async_std::sync::{Receiver, Sender}; |
||||
|
||||
pub struct Handler { |
||||
tx: Sender<Response>, |
||||
} |
||||
|
||||
impl Handler { |
||||
/// Start a message handler with a handle to send a reply back to the clients
|
||||
pub fn start(req: Request) { |
||||
|
||||
} |
||||
} |
@ -0,0 +1,20 @@ |
||||
mod endpoint; |
||||
pub use endpoint::*; |
||||
|
||||
mod gen; |
||||
pub use gen::*; |
||||
|
||||
mod handler; |
||||
pub use handler::*; |
||||
|
||||
mod parser; |
||||
pub use parser::*; |
||||
|
||||
// #[async_std::test]
|
||||
// async fn user_connection() {
|
||||
// let serv = Server::new();
|
||||
// let ep = Endpoint::new("localhost:9999").await;
|
||||
// task::spawn(async move { ep.listen(serv).await });
|
||||
|
||||
// // Create a fake client here
|
||||
// }
|
@ -0,0 +1,17 @@ |
||||
use crate::{ |
||||
error::Error, |
||||
wire::{Request, Response}, |
||||
GameIf, |
||||
}; |
||||
use std::sync::Arc; |
||||
|
||||
/// Parse a request and call a game interface function for it
|
||||
pub async fn request(req: Request, game: Arc<impl GameIf>) -> Response { |
||||
use Request::*; |
||||
match req { |
||||
Register(name, pw) => super::register(game.register(name, pw).await), |
||||
Login(name, pw_hash) => super::login(game.login(name, pw_hash).await), |
||||
Logout(user) => super::logout(game.logout(user).await), |
||||
_ => super::invalid(), |
||||
} |
||||
} |
@ -0,0 +1,5 @@ |
||||
mod action; |
||||
pub use action::*; |
||||
|
||||
mod update; |
||||
pub use update::*; |
@ -0,0 +1,25 @@ |
||||
//! This module implements the client-server game protocol
|
||||
|
||||
use super::{Request, Response}; |
||||
|
||||
pub enum NetErr { |
||||
Refused, |
||||
Dropped, |
||||
Timeout, |
||||
BadData, |
||||
} |
||||
|
||||
/// Use this function to send a request to a partical remote
|
||||
///
|
||||
/// The function makes sure that you get a valid response back, but
|
||||
/// does not yet ensure that this response is correct for the request
|
||||
/// in question.
|
||||
pub fn request_to(r: Request, remote: String) -> Result<Response, NetErr> { |
||||
todo!() |
||||
} |
||||
|
||||
/// Use this function to send a response to a client
|
||||
pub fn response_to(r: Response, client: String) -> Result<(), NetErr> { |
||||
todo!() |
||||
} |
||||
|
@ -0,0 +1,41 @@ |
||||
use crate::wire::{Action, LobbyId, MatchId, Request, User}; |
||||
|
||||
pub fn register(name: String, pw: String) -> Request { |
||||
Request::Register(name, pw) |
||||
} |
||||
c |
||||
pub fn login(name: String, pw: String) -> Request { |
||||
Request::Login(name, pw) |
||||
} |
||||
|
||||
pub fn logout(user: User) -> Request { |
||||
Request::Logout(user) |
||||
} |
||||
|
||||
pub fn anonymous(name: String) -> Request { |
||||
Request::Anonymous(name) |
||||
} |
||||
|
||||
pub fn join(user: User, lid: LobbyId) -> Request { |
||||
Request::Join(user, lid) |
||||
} |
||||
|
||||
pub fn leave(user: User, lid: LobbyId) -> Request { |
||||
Request::Leave(user, lid) |
||||
} |
||||
|
||||
pub fn ready(user: User, lid: LobbyId, ready: bool) -> Request { |
||||
Request::Ready(user, lid, ready) |
||||
} |
||||
|
||||
pub fn start_req(user: User, lid: LobbyId) -> Request { |
||||
Request::StartReq(user, lid) |
||||
} |
||||
|
||||
pub fn game_action(user: User, mid: MatchId, act: Action) -> Request { |
||||
Request::GameAction(user, mid, act) |
||||
} |
||||
|
||||
pub fn leave_game(user: User, mid: MatchId) -> Request { |
||||
Request::LeaveGame(user, mid) |
||||
} |
@ -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; |
||||
|
@ -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;
|
||||
} |
||||
|
@ -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, |
||||
} |
||||
|
@ -1,9 +0,0 @@ |
||||
use rst_core::wire::Request; |
||||
|
||||
pub async fn request(req: Request) { |
||||
use Request::*; |
||||
match req { |
||||
Register(name, pw) => {}, |
||||
_ => todo!(), |
||||
} |
||||
} |
@ -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!() |
||||
} |
||||
} |
Loading…
Reference in new issue