feat: move start_watch into trait definition, to do that use async_traits
Some checks failed
/ build (push) Has been cancelled
Some checks failed
/ build (push) Has been cancelled
This commit is contained in:
parent
8a7c3f5203
commit
750e8dcbf0
5 changed files with 111 additions and 101 deletions
|
|
@ -1,4 +1,7 @@
|
|||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use tokio::{io::AsyncWriteExt, net::TcpStream};
|
||||
use tracing::Instrument;
|
||||
|
||||
use crate::{
|
||||
packets::{
|
||||
|
|
@ -60,13 +63,14 @@ pub async fn send_disconnect(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait MinecraftServerHandle: Clone {
|
||||
async fn start(&self) -> Result<(), OpaqueError>;
|
||||
async fn stop(&self) -> Result<(), OpaqueError>;
|
||||
async fn query_status(&self) -> Result<ServerDeploymentStatus, OpaqueError>;
|
||||
fn get_internal_address(&self) -> &str;
|
||||
fn get_addr(&self) -> Option<String>;
|
||||
fn get_port(&self) -> Option<String>;
|
||||
fn get_addr(&self) -> String;
|
||||
fn get_port(&self) -> String;
|
||||
fn get_motd(&self) -> Option<String>;
|
||||
|
||||
async fn query_server_connectable(&self) -> Result<TcpStream, OpaqueError> {
|
||||
|
|
@ -111,24 +115,82 @@ pub trait MinecraftServerHandle: Clone {
|
|||
tracing::trace!("data exchanged while proxying status: {:?}", data_amount);
|
||||
Ok(())
|
||||
}
|
||||
// TODO: move the implementation to here, but
|
||||
// the async things are *strange* in rust
|
||||
fn query_description(
|
||||
&self,
|
||||
) -> impl std::future::Future<Output = Result<Box<dyn StatusTrait>, OpaqueError>> + Send;
|
||||
async fn query_description(&self) -> Result<Box<dyn StatusTrait>, OpaqueError>;
|
||||
}
|
||||
|
||||
pub trait MinecraftAPI<T> {
|
||||
async fn query_server(&self, addr: &str, port: &str) -> Result<T, OpaqueError>;
|
||||
fn get_map(&self) -> Arc<tokio::sync::Mutex<HashMap<String, tokio::task::JoinHandle<()>>>>;
|
||||
|
||||
// TODO: move the implementation to here, but
|
||||
/// This should be callable even if there is already a watcher,
|
||||
/// and it should handle the collision itself while returning OK().
|
||||
async fn start_watch(
|
||||
self,
|
||||
server: impl MinecraftServerHandle,
|
||||
server: impl MinecraftServerHandle + Send + Sync + 'static,
|
||||
frequency: std::time::Duration,
|
||||
) -> Result<(), OpaqueError>;
|
||||
) -> Result<(), OpaqueError>
|
||||
where
|
||||
Self: Send + Sync + 'static + Clone,
|
||||
{
|
||||
let inter_addr = server.get_internal_address().to_string();
|
||||
|
||||
if let Some(handle) = self.get_map().lock().await.get(&inter_addr) {
|
||||
if !handle.is_finished() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
let span = tracing::span!(parent: None,tracing::Level::INFO, "server_watcher", inter_addr, join_addr = server.get_addr(), join_port = server.get_port());
|
||||
|
||||
let full_addr_clone = inter_addr.clone();
|
||||
let api = self.clone();
|
||||
let handle = tokio::spawn(
|
||||
async move {
|
||||
tracing::info!("starting watcher");
|
||||
loop {
|
||||
tokio::time::sleep(frequency).await;
|
||||
let status_json = match server.query_description().await {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
tracing::error!(
|
||||
err = format!("{}", e.context),
|
||||
"could not query description"
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
if status_json.get_players_online() == 0 {
|
||||
// With this I don't need to specify that StatusTrait
|
||||
// should be send as well.
|
||||
|
||||
// Otherwise I would need to have it be defined as:
|
||||
// trait StatusTrait: Send { ... }
|
||||
drop(status_json);
|
||||
let map = api.get_map();
|
||||
let mut guard = map.lock().await;
|
||||
guard.remove(&full_addr_clone);
|
||||
drop(guard);
|
||||
drop(map);
|
||||
if let Err(err) = server.stop().await {
|
||||
tracing::error!(
|
||||
trace = %err.print_span_trace(),
|
||||
err = err.context,
|
||||
msg = "failed to stop server"
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
.instrument(span),
|
||||
);
|
||||
let map = self.get_map();
|
||||
let mut guard = map.lock().await;
|
||||
guard.insert(inter_addr.clone(), handle);
|
||||
drop(guard);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ServerDeploymentStatus {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue