liminal-server 0.25.4

Standalone server for the liminal messaging bus
Documentation
//! Replacement bridges resume the same subscriptions and cumulative observations.
use super::{ExportSubscriptions, LinkBridge, Observation, ServerError, failure, run_worker};
use crate::link_carrier::choice::ChoiceLink as DialedLink;
use crate::server::connection::services::LiminalConnectionServices;
use std::sync::Arc;

impl LinkBridge {
    pub(crate) fn start_named(
        link: impl Into<DialedLink>,
        services: Arc<LiminalConnectionServices>,
        peer: String,
    ) -> Result<Self, ServerError> {
        Self::start_resuming(link, services, peer, super::BridgeCounters::default())
    }

    pub(crate) fn start_resuming(
        link: impl Into<DialedLink>,
        services: Arc<LiminalConnectionServices>,
        peer: String,
        counters: super::BridgeCounters,
    ) -> Result<Self, ServerError> {
        Self::start_observing(link, services, peer, counters, |_| Ok(()))
    }

    pub(super) fn start_observing(
        link: impl Into<DialedLink>,
        services: Arc<LiminalConnectionServices>,
        peer: String,
        counters: super::BridgeCounters,
        prepare: impl FnOnce(&Observation) -> Result<(), ServerError>,
    ) -> Result<Self, ServerError> {
        let mut link = link.into();
        let interrupt = link
            .carrier
            .interrupt_handle()
            .map_err(|error| failure(error.to_string()))?;
        let observation = Observation::resume(
            interrupt
                .try_clone()
                .map_err(|error| failure(error.to_string()))?,
            counters,
        )?;
        prepare(&observation)?;
        let wake = Arc::clone(&observation.wake);
        let feeds = Arc::new(ExportSubscriptions::new(
            &link.link_id,
            &link.exports,
            Arc::clone(&wake),
            Arc::clone(&observation),
        )?);
        services.install_exporter(&feeds)?;
        crate::server::self_streams::cost::install_bridge_reader(&services, &feeds)?;
        observation.install_life(&link, &services)?;
        observation.watch_end(&wake)?;
        let worker_wake = Arc::clone(&wake);
        let worker_observation = Arc::clone(&observation);
        let link_id = link.link_id.clone();
        let dispatcher = tracing::dispatcher::get_default(Clone::clone);
        let worker = std::thread::Builder::new()
            .name("liminal-link-bridge".to_owned())
            .spawn(move || {
                tracing::dispatcher::with_default(&dispatcher, || {
                    run_worker(
                        &mut link,
                        &feeds,
                        &worker_wake,
                        &worker_observation,
                        &services,
                        &peer,
                    )
                })
            })
            .map_err(|error| failure(format!("link bridge worker: {error}")))?;
        Ok(Self {
            link_id,
            observation,
            wake,
            interrupt,
            worker: Some(worker),
        })
    }

    pub(crate) fn notify_end(
        &self,
        notify: Arc<dyn Fn() + Send + Sync>,
    ) -> Result<(), ServerError> {
        let wake = Arc::downgrade(&self.wake);
        self.observation
            .life
            .get()
            .ok_or_else(|| failure("bridge lifecycle absent"))?
            .notify_with(Arc::new(move || {
                if let Some(wake) = wake.upgrade() {
                    wake.notify();
                }
                notify();
            }))
            .map_err(failure)
    }
    pub(crate) fn end_reason(&self) -> Result<Option<String>, ServerError> {
        self.observation.life_reason().map_err(failure)
    }
    pub(crate) fn request_shutdown(&self) -> Result<(), ServerError> {
        self.wake.stop();
        self.observation.end_life(crate::link::LinkEnd::Shutdown)?;
        self.interrupt
            .shutdown(std::net::Shutdown::Both)
            .or_else(|error| {
                if error.kind() == std::io::ErrorKind::NotConnected {
                    Ok(())
                } else {
                    Err(error)
                }
            })
            .map_err(|error| failure(error.to_string()))
    }
    pub(crate) fn finish_retaining(mut self) -> Result<super::BridgeCounters, ServerError> {
        self.stop_worker()?;
        Ok(self.counters())
    }
}