use crate::UError; use anyhow::Error; use once_cell::sync::OnceCell; use tokio::sync::mpsc::{channel, error::TryRecvError, Receiver, Sender}; use tokio::sync::{Mutex, MutexGuard}; type ChanError = Error; static ERR_CHAN: OnceCell<Mutex<ErrChan>> = OnceCell::new(); pub struct ErrChan { tx: Sender<ChanError>, rx: Receiver<ChanError>, } impl ErrChan { async fn get() -> MutexGuard<'static, Self> { ERR_CHAN .get_or_init(|| { let (tx, rx) = channel(20); Mutex::new(Self { tx, rx }) }) .lock() .await } pub async fn send(err: impl Into<ChanError>, ctx: impl AsRef<str>) { let err = err.into(); error!("Encountered an error at '{}': {:?}", ctx.as_ref(), err); Self::get().await.tx.try_send(err).unwrap(); } pub async fn recv() -> Option<UError> { match Self::get().await.rx.try_recv() { Ok(err) => Some(UError::from(err)), Err(TryRecvError::Disconnected) => panic!("err chan disconnected"), Err(TryRecvError::Empty) => None, } } }