use crate::{
config::SocketServerConfig,
frontend::{
socket_server::SocketServer,
},
logic::ogre_robot::OgreRobot,
};
use std::{
sync::Arc,
time::{SystemTime,Duration},
ops::DerefMut,
};
use futures::future::BoxFuture;
use log::debug;
use tokio::sync::RwLock;
const TIMEOUT: Duration = Duration::from_secs(3);
const POLL_INTERVAL: Duration = Duration::from_micros(1000);
pub struct Runtime {
pub executable_path: String,
pub tokio_runtime: Option<Arc<tokio::runtime::Runtime>>,
ogre_robot: Option<OgreRobot>,
socket_server: Option<SocketServer<'static>>,
}
macro_rules! impl_runtime {
($field_name_str: literal,
$field_name_ident: ident,
$field_type: ty,
$set_function_name: ident,
$get_function_name: ident,
$opt_get_function_name: ident) => {
impl Runtime {
pub async fn $set_function_name(runtime: &RwLock<Self>, $field_name_ident: $field_type) {
runtime.write().await.$field_name_ident.replace($field_name_ident);
}
pub async fn $get_function_name<ReturnType>
(runtime: &RwLock<Self>,
callback: impl for<'r> FnOnce(&'r mut $field_type) -> BoxFuture<'r, ReturnType> + Send)
-> ReturnType {
let mut start: Option<SystemTime> = None;
loop {
if let Ok(runtime) = &mut runtime.try_write() {
if let Some($field_name_ident) = runtime.deref_mut().$field_name_ident.as_mut() {
if let Some(start) = start {
debug!("Runtime: `{}` became available after a {:?} wait", $field_name_str, start.elapsed().unwrap());
}
break callback($field_name_ident).await
}
}
if let Some(_start) = start {
if _start.elapsed().unwrap() > TIMEOUT {
panic!("Could not retrieve `{}` instance: {}",
$field_name_str,
if let Ok(_runtime) = &runtime.try_read() {
format!("it was not registered in `Runtime` even after {:?}", TIMEOUT)
} else {
format!("`Runtime` seems to be locked elsewhere for the past {:?}", TIMEOUT)
});
}
} else {
start = Some(SystemTime::now());
debug!("Runtime: `{}` is not (yet?) available. Waiting for up to {:?} for main.rs to finish instantiating it and placing it here with `register_{}()`",
$field_name_str, TIMEOUT, $field_name_str);
}
tokio::time::sleep(POLL_INTERVAL).await;
}
}
pub async fn $opt_get_function_name<ReturnType>
(runtime: &RwLock<Self>,
callback: impl for<'r> FnOnce(&'r mut $field_type) -> BoxFuture<'r, ReturnType> + Send)
-> Option<ReturnType> {
{
let locked_runtime = &runtime.write().await;
if let None = &locked_runtime.$field_name_ident {
return None
}
}
Some(Self::$get_function_name(runtime, callback).await)
}
}
}
}
impl Runtime {
pub fn new(executable_path: String) -> Self {
Self {
executable_path,
tokio_runtime: None,
ogre_robot: None,
socket_server: None,
}
}
}
impl_runtime!("ogre_robot", ogre_robot, OgreRobot, register_ogre_robot, do_for_ogre_robot, do_if_ogre_robot_is_present);
impl_runtime!("socket_server", socket_server, SocketServer<'static>, register_socket_server, do_for_socket_server, do_if_socket_server_is_present);