crates/gunnar-front/src/clock.rs
//! **The estate's root of time, on vm1** — what `gunnar-clock run` was on the
//! old front OS, now a thread of the front medium's PID 1, and since lane L10
//! (2026-10-21) edda estate-clock's `offer::start` (Gunnar's own copy and the
//! `gunnar-clock` crate are deleted).
//!
//! * the SOURCES are the medium's `clock` parameter (`korp.env.GUNNAR_CLOCK`,
//! read as the alias of `ESTATE_CLOCK`, e.g.
//! `https://api.stripe.com/,https://www.cloudflare.com/`): a site fact, so a
//! parameter and never a default ([`estate_clock::config`] says why);
//! * the KEY is minted here at first boot ([`CLOCK_KEY_REL`], 0600) and
//! OFFERED to the installer as `clock_key` (the whole OpenSSH line);
//! * signed time is served on the UTILITY address, port
//! [`estate_clock::config::DEFAULT_PEER_PORT`], and that spelling is offered
//! as `clock_peer` (`peer://<utility>:50123`) — every gunnar box takes both
//! from the offer (gunnar-server `feed::Fed::from_feed`), so the installer
//! feeds neither;
//! * **both wires are answered**: a box asking in Gunnar's `GUNNAR-TIME/1`
//! (gunnar-clock, the boxes of the release before) is answered in it, a box
//! asking in `ESTATE-TIME/1` in that (`estate_clock::peer::answer`).
use std::net::Ipv4Addr;
use std::path::Path;
#[cfg(feature = "clock-fetch")]
use std::sync::Arc;
pub use estate_clock::offer::{
peer_spelling, ClockOffer, CLOCK_KEY_REL, OFFER_CLOCK_KEY, OFFER_CLOCK_PEER,
};
/// **Start the front's clock** on its own thread: mint (or read) the key,
/// serve signed time on `utility:50123` when there is a utility address, and
/// keep this host's clock from the medium's sources. Returns what to offer.
///
/// An HTTPS source may also be vouched for by the medium's installer CA — the
/// bench's LOCAL clock (owner 2026-09-26: a mock run never asks api.stripe.com
/// or cloudflare for the time). No new trust: that CA already authenticates
/// the installer that feeds this front everything.
#[cfg(feature = "clock-fetch")]
pub fn start(
root: &Path,
utility: Option<Ipv4Addr>,
installer_ca_pem: &str,
) -> Result<ClockOffer, String> {
estate_clock::offer::start(
root,
utility,
installer_ca_pem,
Arc::new(|line: &str| tracing::info!("clock: {line}")),
)
}
/// The refusal a front built without `clock-fetch` answers (AIRGAP, owner rule 2026-10-25).
pub const NOT_BUILT: &str =
"the front's clock is not built: it asks https:// time sources, so it needs gunnar-front's \
`clock-fetch` feature (off by default; every front row names it)";
/// **A front without `clock-fetch` keeps no clock** (the default build): nothing is minted,
/// served or asked, and the caller says the boxes are fed no clock.
#[cfg(not(feature = "clock-fetch"))]
pub fn start(
_root: &Path,
_utility: Option<Ipv4Addr>,
_installer_ca_pem: &str,
) -> Result<ClockOffer, String> {
Err(NOT_BUILT.to_owned())
}