Maintain state records for connected players

This commit is contained in:
Tangent Wantwight 2020-05-30 16:10:55 -04:00
parent 750cfe1630
commit 43babbbfab
1 changed files with 60 additions and 14 deletions

View File

@ -5,10 +5,13 @@ use serde_json::json;
use std::sync::Arc; use std::sync::Arc;
use stream::iter; use stream::iter;
pub async fn greet<T>(sink: &mut T) -> Result<()> /// There is a point at which a client falls far enough behind
where /// that it's probably not worth trying to catch them up; for now,
T: Sink<ServerMessage, Error = Error> + Unpin, /// implement this as a buffer size limit and disconnect a client if
{ /// the cap is reached. More elegant solutions may be reached in the future.
const CHANNEL_BUFFER: usize = 200;
pub async fn greet(sink: &mut Sender<ServerMessage>) -> Result<()> {
let mut greeting = iter(vec![ let mut greeting = iter(vec![
ServerMessage::Meta { ServerMessage::Meta {
m: Meta { m: Meta {
@ -16,7 +19,10 @@ where
helo: Some("Dedicated base2020 server".into()), helo: Some("Dedicated base2020 server".into()),
}, },
}, },
ServerMessage::SetState { u: Some(0), s: json!({}) }, ServerMessage::SetState {
u: Some(0),
s: json!({}),
},
]) ])
.map(Ok); .map(Ok);
@ -25,7 +31,12 @@ where
.context("Greeting client") .context("Greeting client")
} }
pub struct PlayerState {
sender: Sender<ServerMessage>,
}
pub struct Server { pub struct Server {
players: Vec<Option<PlayerState>>,
} }
#[derive(Clone)] #[derive(Clone)]
@ -37,6 +48,7 @@ impl Server {
pub fn create() -> Handle { pub fn create() -> Handle {
Handle { Handle {
server: Arc::new(Mutex::new(Server { server: Arc::new(Mutex::new(Server {
players: Vec::new(),
})), })),
} }
} }
@ -44,28 +56,62 @@ impl Server {
pub fn process_message(&mut self, player: usize, msg: ClientMessage) { pub fn process_message(&mut self, player: usize, msg: ClientMessage) {
debug!("Client#{} message: {:?}", player, &msg); debug!("Client#{} message: {:?}", player, &msg);
} }
pub async fn add_player(&mut self, mut sender: Sender<ServerMessage>) -> Result<PlayerId> {
// TODO: limit total number of players
// allot player ID
let player_id = self
.players
.iter()
.position(|slot| slot.is_none())
.unwrap_or_else(|| {
self.players.push(None);
self.players.len() - 1
});
// connect player
greet(&mut sender).await?;
self.players[player_id] = Some(PlayerState { sender });
info!("Client#{} connected", player_id);
Ok(player_id)
}
pub fn remove_player(&mut self, player_id: PlayerId) {
if player_id < self.players.len() && self.players[player_id].is_some() {
self.players[player_id] = None;
info!("Client#{} disconnected", player_id);
} else {
error!("Tried to disconnect Client#{} but there was no record for them", player_id);
}
}
} }
where
{
pub async fn run_client( pub async fn run_client(
handle: Handle, handle: Handle,
source: &mut (impl Stream<Item = Result<ClientMessage, Error>> + Send + Unpin), source: &mut (impl Stream<Item = Result<ClientMessage, Error>> + Send + Unpin),
mut sink: &mut (impl Sink<ServerMessage, Error = Error> + Send + Unpin), sink: &mut (impl Sink<ServerMessage, Error = Error> + Send + Unpin),
) -> Result<()> { ) -> Result<()> {
let output_task = async { let (sender, receiver) = channel(CHANNEL_BUFFER);
greet(&mut sink).await?;
Ok::<(), Error>(()) // register player
}; let player_id = handle.server.lock().await.add_player(sender).await?;
let output_task = receiver.map(Ok).forward(sink);
let input_task = async { let input_task = async {
loop { loop {
match source.next().await { match source.next().await {
Some(Ok(msg)) => handle.server.lock().await.process_message(0, msg), Some(Ok(msg)) => handle.server.lock().await.process_message(player_id, msg),
Some(Err(error)) => return Err(error), Some(Err(error)) => return Err(error),
None => break Ok(()), None => break Ok(()),
} }
} }
}; };
try_join(output_task, input_task).await.map(|((), ())| ()) let result = try_join(output_task, input_task).await.map(|_| ());
// deregister player, whether normally or via error
handle.server.lock().await.remove_player(player_id);
result
} }