Spawn a heartbeat task while players are connected to the server, aborting it once they're off.

This commit is contained in:
Tangent Wantwight 2020-06-05 16:46:51 -04:00
parent 9239c19cbe
commit d2fe79b55c
1 changed files with 32 additions and 1 deletions

View File

@ -4,7 +4,7 @@ use futures::{channel::mpsc::*, future::try_join, lock::Mutex, prelude::*};
use serde_json::json; use serde_json::json;
use std::sync::Arc; use std::sync::Arc;
use stream::iter; use stream::iter;
use future::abortable; use future::{AbortHandle, abortable};
/// There is a point at which a client falls far enough behind /// There is a point at which a client falls far enough behind
/// that it's probably not worth trying to catch them up; for now, /// that it's probably not worth trying to catch them up; for now,
@ -38,6 +38,7 @@ pub struct PlayerState {
pub struct Server { pub struct Server {
players: Vec<Option<PlayerState>>, players: Vec<Option<PlayerState>>,
heartbeat_task: Option<AbortHandle>,
} }
#[derive(Clone)] #[derive(Clone)]
@ -50,6 +51,7 @@ impl Server {
Handle { Handle {
server: Arc::new(Mutex::new(Server { server: Arc::new(Mutex::new(Server {
players: Vec::new(), players: Vec::new(),
heartbeat_task: None,
})), })),
} }
} }
@ -75,6 +77,10 @@ impl Server {
greet(&mut sender).await?; greet(&mut sender).await?;
self.players[player_id] = Some(PlayerState { sender }); self.players[player_id] = Some(PlayerState { sender });
info!("Client#{} connected", player_id); info!("Client#{} connected", player_id);
// ensure server task is running
self.spinup();
Ok(player_id) Ok(player_id)
} }
@ -85,6 +91,31 @@ impl Server {
} else { } else {
error!("Tried to disconnect Client#{} but there was no record for them", player_id); error!("Tried to disconnect Client#{} but there was no record for them", player_id);
} }
// check if no players left
if self.players.iter().all(Option::is_none) {
self.shutdown();
}
}
/// Start the heartbeat task, if it's not running
fn spinup(&mut self) {
if let None = self.heartbeat_task {
info!("Starting heartbeat task");
let (task, handle) = abortable(async {
info!("Heartbeat task started");
});
self.heartbeat_task = Some(handle);
tokio::spawn(task);
}
}
/// Stop any active heartbeat task
fn shutdown(&mut self) {
if let Some(handle) = self.heartbeat_task.take() {
info!("Stopping heartbeat task");
handle.abort();
}
} }
} }