liminal-server 0.24.5

Standalone server for the liminal messaging bus
Documentation
//! The whole topology document, including each live serving subject.

use super::{TopologyModel, WorkerStation};
use crate::console::error::ConsoleError;
use crate::console::records::{
    Connection, Device, DeviceBox, DeviceKind, Link, Station, StationKind, StationState,
    TopologyDocument,
};
use crate::console::wall::WallBase;
use std::collections::{BTreeMap, BTreeSet};

impl TopologyModel {
    /// The whole document as it stands, always. This device's start is wall
    /// time from `wall`, the same whenever the document is built, so a reader
    /// derives the uptime on its own clock and a document never goes stale.
    /// When the start falls outside u64 milliseconds since the epoch, the
    /// document names that fault where the start would be, and the fault
    /// comes back beside it for the caller to count: one bad reading never
    /// withholds the topology.
    #[must_use]
    pub fn document(&self, wall: &WallBase) -> (TopologyDocument, Option<ConsoleError>) {
        let this = &self.this.id;
        let (started, fault) = match wall.unix_ms_of(self.this.started) {
            Ok(started) => (Some(started), None),
            Err(error) => (None, Some(error)),
        };
        let mut devices = vec![Device {
            id: this.clone(),
            name: this.clone(),
            kind: DeviceKind::Device,
            liminal: Some(self.this.liminal.clone()),
            started,
            started_fault: fault.as_ref().map(ToString::to_string),
            parent: self.parent.clone(),
            zone: Some(DeviceBox::THIS),
        }];
        let peers: BTreeSet<_> = self
            .peers
            .iter()
            .chain(
                self.links
                    .values()
                    .flat_map(|link| std::iter::once(&link.name).chain(link.relayed.iter())),
            )
            .collect();
        devices.extend(peers.into_iter().map(|peer| Device {
            id: peer.clone(),
            name: peer.clone(),
            kind: DeviceKind::Device,
            liminal: None,
            started: None,
            started_fault: None,
            parent: None,
            zone: None,
        }));
        // A registered responder is a service; a registered worker that is
        // not also one is a worker. Neither takes this server's exchange or
        // depot id: one that would is kept off the map.
        let depot = self.this.depot.then(|| self.depot_id());
        let mut stations: BTreeMap<&String, (StationKind, Option<&WorkerStation>)> = self
            .workers
            .values()
            .filter(|worker| self.reserved(&worker.identity).is_none())
            .map(|worker| (&worker.identity, (StationKind::Worker, Some(worker))))
            .collect();
        stations.extend(
            self.stations
                .iter()
                .filter(|subject| self.reserved(subject).is_none())
                .map(|subject| (subject, (StationKind::Service, None))),
        );
        stations.extend(depot.iter().map(|id| (id, (StationKind::Depot, None))));
        stations.insert(this, (StationKind::Exchange, None));
        let document = TopologyDocument::new(
            self.rev,
            this.clone(),
            devices,
            stations
                .into_iter()
                .map(|(subject, (kind, worker))| Station {
                    id: subject.clone(),
                    name: subject.clone(),
                    device: this.clone(),
                    kind,
                    state: StationState::Live,
                    subjects: worker.map(|worker| worker.subjects.clone()),
                    activities: worker.map(|worker| worker.activities.clone()),
                })
                .collect(),
            self.all_lines(),
            self.peers
                .iter()
                .map(|peer| Link::to_peer(this, peer))
                .chain(self.links.values().cloned())
                .collect(),
            self.connections
                .iter()
                .map(|(id, (mount, participant))| Connection {
                    id: id.to_string(),
                    mount: *mount,
                    participant: participant.clone(),
                })
                .collect(),
        );
        (document, fault)
    }
}