Skip to main content

liminal_server/console/model/
document.rs

1//! The whole topology document, including each live serving subject.
2
3use super::{TopologyModel, WorkerStation};
4use crate::console::error::ConsoleError;
5use crate::console::records::{
6    Connection, Device, DeviceBox, DeviceKind, Link, Station, StationKind, StationState,
7    TopologyDocument,
8};
9use crate::console::wall::WallBase;
10use std::collections::{BTreeMap, BTreeSet};
11
12impl TopologyModel {
13    /// The whole document as it stands, always. This device's start is wall
14    /// time from `wall`, the same whenever the document is built, so a reader
15    /// derives the uptime on its own clock and a document never goes stale.
16    /// When the start falls outside u64 milliseconds since the epoch, the
17    /// document names that fault where the start would be, and the fault
18    /// comes back beside it for the caller to count: one bad reading never
19    /// withholds the topology.
20    #[must_use]
21    pub fn document(&self, wall: &WallBase) -> (TopologyDocument, Option<ConsoleError>) {
22        let this = &self.this.id;
23        let (started, fault) = match wall.unix_ms_of(self.this.started) {
24            Ok(started) => (Some(started), None),
25            Err(error) => (None, Some(error)),
26        };
27        let mut devices = vec![Device {
28            id: this.clone(),
29            name: this.clone(),
30            kind: DeviceKind::Device,
31            liminal: Some(self.this.liminal.clone()),
32            started,
33            started_fault: fault.as_ref().map(ToString::to_string),
34            parent: self.parent.clone(),
35            zone: Some(DeviceBox::THIS),
36        }];
37        let peers: BTreeSet<_> = self
38            .peers
39            .iter()
40            .chain(
41                self.links
42                    .values()
43                    .flat_map(|link| std::iter::once(&link.name).chain(link.relayed.iter())),
44            )
45            .collect();
46        devices.extend(peers.into_iter().map(|peer| Device {
47            id: peer.clone(),
48            name: peer.clone(),
49            kind: DeviceKind::Device,
50            liminal: None,
51            started: None,
52            started_fault: None,
53            parent: None,
54            zone: None,
55        }));
56        // A registered responder is a service; a registered worker that is
57        // not also one is a worker. Neither takes this server's exchange or
58        // depot id: one that would is kept off the map.
59        let depot = self.this.depot.then(|| self.depot_id());
60        let mut stations: BTreeMap<&String, (StationKind, Option<&WorkerStation>)> = self
61            .workers
62            .values()
63            .filter(|worker| self.reserved(&worker.identity).is_none())
64            .map(|worker| (&worker.identity, (StationKind::Worker, Some(worker))))
65            .collect();
66        stations.extend(
67            self.stations
68                .iter()
69                .filter(|subject| self.reserved(subject).is_none())
70                .map(|subject| (subject, (StationKind::Service, None))),
71        );
72        stations.extend(depot.iter().map(|id| (id, (StationKind::Depot, None))));
73        stations.insert(this, (StationKind::Exchange, None));
74        let document = TopologyDocument::new(
75            self.rev,
76            this.clone(),
77            devices,
78            stations
79                .into_iter()
80                .map(|(subject, (kind, worker))| Station {
81                    id: subject.clone(),
82                    name: subject.clone(),
83                    device: this.clone(),
84                    kind,
85                    state: StationState::Live,
86                    subjects: worker.map(|worker| worker.subjects.clone()),
87                    activities: worker.map(|worker| worker.activities.clone()),
88                })
89                .collect(),
90            self.all_lines(),
91            self.peers
92                .iter()
93                .map(|peer| Link::to_peer(this, peer))
94                .chain(self.links.values().cloned())
95                .collect(),
96            self.connections
97                .iter()
98                .map(|(id, (mount, participant))| Connection {
99                    id: id.to_string(),
100                    mount: *mount,
101                    participant: participant.clone(),
102                })
103                .collect(),
104        );
105        (document, fault)
106    }
107}