use std::{sync::{RwLock}};
use tokio::sync::{broadcast, mpsc, watch};
type CS<T> = RwLock<Option<T>>;
type WsMessage = tungstenite::Message;
lazy_static! {
pub static ref CS_SER_ALIVE_RX: CS<watch::Receiver<bool>> =
RwLock::new(None);
pub static ref CS_CLI_CONN_RX: CS<mpsc::Receiver<String>> =
RwLock::new(None);
pub static ref CS_SER_MSG_TX: CS<broadcast::Sender<Vec<WsMessage>>> =
RwLock::new(None);
pub static ref CS_CLI_MSG_RX: CS<mpsc::Receiver<WsMessage>> =
RwLock::new(None);
pub static ref CS_SER_REQ_SHUTDOWN_TX: CS<watch::Sender<bool>> =
RwLock::new(None);
static ref LAST_ERROR: CS<String> = RwLock::new(None);
}
pub fn weakly_record_error(msg: String) {
let last_err = LAST_ERROR.try_write();
if last_err.is_err() { return; }
let mut last_err = last_err.unwrap();
*last_err = Some(msg);
}
pub fn try_get_last_error() -> Option<String> {
let err_store = LAST_ERROR.read();
if err_store.is_err() { return Some("Couldn't get last error.".to_string()); }
let err_store = err_store.as_deref();
if err_store.is_err() { return Some("Couldn't get last error.".to_string()); }
let err_store = err_store.unwrap().as_ref();
err_store.map_or(None, |s| Some(String::from(s)))
}
pub fn read<T, U, R, F>(lazy_static_item: &R, f: F) -> Option<U>
where
F: FnOnce(&T) -> U,
R: std::ops::Deref<Target = RwLock<Option<T>>>
{
let read_guard = lazy_static_item.read();
if read_guard.is_err() {
weakly_record_error(format!("Failed to get read access to {}.", std::any::type_name::<R>()));
return None;
}
let read_guard = read_guard.unwrap();
let item = read_guard.as_ref();
if item.is_none() {
weakly_record_error(format!("Failed to get read access to {}, as it hasn't been created yet. Is the server running?", std::any::type_name::<R>()));
return None;
}
let item = item.unwrap();
Some(f(item))
}
pub fn mutate<T, U, R, F>(lazy_static_item: &R, f: F) -> Option<U>
where
F: FnOnce(&mut T) -> U,
R: std::ops::Deref<Target = RwLock<Option<T>>>
{
let write_guard = lazy_static_item.write();
if write_guard.is_err() {
weakly_record_error(format!("Failed to get write access to {}.", std::any::type_name::<R>()));
return None;
}
let mut write_guard = write_guard.unwrap();
let state = write_guard.as_mut();
if state.is_none() {
weakly_record_error(format!("Failed to mutable ref for {}, as it hasn't been created yet. Is the server running?", std::any::type_name::<R>()));
return None;
}
let state = state.unwrap();
Some(f(state))
}
pub fn set_value<T, R>(lazy_static_item: &R, new_val: T) -> Result<(), ()>
where
R: std::ops::Deref<Target = RwLock<Option<T>>>
{
let write_guard = lazy_static_item.write();
if write_guard.is_err() {
weakly_record_error(format!("Failed to get write access to {} to set its value.", std::any::type_name::<R>()));
return Err(());
}
let mut write_guard = write_guard.unwrap();
(*write_guard) = Some(new_val);
Ok(())
}