liminal-server 0.24.1

Standalone server for the liminal messaging bus
Documentation
//! The only timed wait belongs to retry scheduling; shutdown and carrier ends interrupt it.
use super::{Instant, ServerError, failure};
use std::sync::{Condvar, Mutex};
#[derive(Debug, Default)]
struct State {
    stopping: bool,
    ready: bool,
}
#[derive(Debug, Default)]
pub(super) struct Wake {
    state: Mutex<State>,
    changed: Condvar,
}
impl Wake {
    pub(super) fn stopping(&self) -> Result<bool, ServerError> {
        Ok(self
            .state
            .lock()
            .map_err(|_| failure("configured retry wake poisoned"))?
            .stopping)
    }
    pub(super) fn stop(&self) -> Result<(), ServerError> {
        let stopped = self
            .state
            .lock()
            .map(|mut state| state.stopping = true)
            .map_err(|_| failure("configured retry stop poisoned"));
        self.changed.notify_all();
        stopped
    }
    pub(super) fn notify(&self) {
        if let Ok(mut state) = self.state.lock() {
            state.ready = true;
            drop(state);
            self.changed.notify_all();
        } else {
            self.changed.notify_all();
            tracing::error!("configured retry notification poisoned");
        }
    }
    pub(super) fn wait(&self, deadline: Option<Instant>) -> Result<(), ServerError> {
        let mut state = self
            .state
            .lock()
            .map_err(|_| failure("configured retry wait poisoned"))?;
        while !state.ready && !state.stopping {
            if let Some(deadline) = deadline {
                let remaining = deadline.saturating_duration_since(Instant::now());
                if remaining.is_zero() {
                    break;
                }
                let (next, timeout) = self
                    .changed
                    .wait_timeout(state, remaining)
                    .map_err(|_| failure("configured retry timed wait poisoned"))?;
                state = next;
                if timeout.timed_out() {
                    break;
                }
            } else {
                state = self
                    .changed
                    .wait(state)
                    .map_err(|_| failure("configured retry wait poisoned"))?;
            }
        }
        state.ready = false;
        drop(state);
        Ok(())
    }
}