coord
Source: crates/lvcs-net/src/coord/mod.rs.
/// `lvcs.toml` `[coord]` (design §5).
///
/// `wait_ms` is the wait window, `WAIT_WINDOW_MS` by default; the daemon's
/// loader caps it at `WAIT_WINDOW_MAX_MS`, so 0 to that bound is accepted,
/// and the shell sends it to the coord actor as [`CoordinationEvents::Configure`].
/// Owner: `M3.coord`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default)]
pub struct CoordConfig {
/// The wait window, in milliseconds.
pub wait_ms: u64,
}
/// A notification's id.
///
/// It is the `HASH` of its [`Notification`] payload's canonical CBOR
/// encoding ([`NotificationId::of`]), written in `ID_ENCODING` on the API;
/// the last key of the yield order. Owner: `M3.coord`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct NotificationId(#[serde(with = "crate::wire::cbor::fixed")] pub [u8; 32]);
/// A notification's range resolved by this daemon's document actor
/// (`DocEvent::Resolve`) to code points of the document's text at its
/// current heads.
///
/// Overlap between notifications is decided on these spans (chosen at the
/// M3 freeze; the cursor pair itself is opaque to `lvcs-net`). Two spans
/// overlap when each starts before the other ends. A whole-document
/// notification (an empty `Notification::range`) has the span
/// [`Span::WHOLE`], `0..usize::MAX`, which overlaps every span, so it needs
/// no resolution. A span meets another when they overlap or touch (one
/// ends where the other starts): a save is announced again only when no
/// current notification of its author meets its span. Owner: `M3.coord`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Span {
/// Where the span starts, in code points (inclusive).
pub start: usize,
/// Where the span ends, in code points (exclusive).
pub end: usize,
}
/// Whether a response is a `note` or a `hold` (design §5).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ResponseKind {
/// Information only: the notifier proceeds.
Note,
/// An objection: the notifier's edit pauses, and a thread opens on the
/// range (design §9).
Hold,
}
/// One response as the coord actor keeps it.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Responded {
/// Whether it is a `note` or a `hold`.
pub kind: ResponseKind,
/// The response payload.
pub response: Response,
}
/// One head of a document (an Automerge change hash's bytes), opaque to
/// `lvcs-net`. Owner: `M3.coord`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Head(#[serde(with = "crate::wire::cbor::fixed")] pub [u8; 32]);
/// A committed save of a document through a main mirror, by the mirror's
/// author, which holds the message capability on it (decision 165).
///
/// `range` is the canonical CBOR encoding of the anchor the save's touched
/// lines were anchored to at `heads` (empty for a whole document, a
/// removal, or a binary save, whose span is [`Span::WHOLE`]), opaque here
/// like [`Notification::range`]; `span` is that range resolved at `heads`.
/// `op` and `what` are what the notification says. Owner: `M3.coord`.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Saved {
/// The document saved.
pub doc: String,
/// The saving participant's key bytes: the mirror's author.
#[serde(with = "crate::wire::cbor::fixed")]
pub by: [u8; 32],
/// The canonical CBOR encoding of the touched lines' anchor; empty for
/// the whole document.
#[serde(with = "crate::wire::cbor::bytes")]
pub range: Vec<u8>,
/// The touched lines resolved at `heads`.
pub span: Span,
/// The document's heads after the save.
pub heads: Vec<Head>,
/// What the save did to the range.
pub op: NotifyOp,
/// What the save is, in generated plain text.
pub what: String,
}
/// A local participant's save, seen at `now_ms` (decision 165): the event
/// of [`CoordinationEvents::LocalSave`]. Owner: `M3.coord`.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SaveSeen {
/// The save.
pub saved: Saved,
/// The shell's clock.
pub now_ms: i64,
}
/// The coord actor's events, generated by its sml table: its mailbox and
/// journal type (decision 286). `now_ms` is the shell's clock (Unix
/// milliseconds). Owner: `M3.coord`.
///
/// Its events, each the payload type its variant is named for: [`Configure`],
/// [`PresenceSeen`], [`WindowElapsed`], [`BulletinRequest`],
/// [`PresenceRequest`], [`LocalNotification`], [`PeerNotification`],
/// [`ResponseSeen`], [`LocalSave`].
pub use machine::{
BulletinRequest, Configure, CoordinationEvents, LocalNotification, LocalSave, PeerNotification,
PresenceRequest, PresenceSeen, ResponseSeen, WindowElapsed,
};
/// How a local notification's wait ended (design §5, decision 51).
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Verdict {
/// No one else was present, or the window ended with no hold and no
/// earlier overlapping notification: the edit proceeds. `notes` are
/// the notes received meanwhile.
Proceed {
/// The notes received meanwhile.
notes: Vec<Response>,
},
/// At least one `hold` arrived: the edit pauses, and each hold names
/// the thread its holder opened.
Hold {
/// The holds received.
holds: Vec<Response>,
/// The notes received meanwhile.
notes: Vec<Response>,
},
/// An overlapping notification earlier in the yield order was seen
/// during the window: the participant yields and turns its edit into
/// an `ask` to that notification's sender (advisory).
Yield {
/// The earlier overlapping notification.
to: Notification,
/// The notes received meanwhile.
notes: Vec<Response>,
},
}
/// Outputs of the coord actor, which the daemon shell carries out.
/// Owner: `M3.coord`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CoordOutput {
/// Seal `notification` with its participant's key and publish it on
/// the document's topic and every ancestor directory's topic.
Publish(Notification),
/// Seal and publish a local response on the notifier's inbox topic and
/// the document's topic.
Respond(Responded),
/// Publish a local participant's presence on its document's topic and
/// every ancestor directory's topic, with a token from the
/// participant's gossip bucket: its first local presence on the
/// document in this incarnation, then one at least a third of
/// `PRESENCE_TTL_SECS` after the last one published, so other daemons
/// count it present without a gap.
PublishPresence(Presence),
/// Send [`CoordinationEvents::WindowElapsed`] for `notification` at `at_ms`.
Wake {
/// The local notification whose window ends.
notification: NotificationId,
/// When, by the shell's clock.
at_ms: i64,
},
/// Answer the `announce` request `req`.
Decided {
/// The request answered.
req: u64,
/// The notification's id.
notification: NotificationId,
/// How its wait ended.
verdict: Verdict,
},
/// Push a received notification to this daemon's clients.
Announce {
/// The notification's id.
id: NotificationId,
/// The notification.
notification: Notification,
},
/// Push a response to the clients of its notification's sender.
Forward(Responded),
/// Seal `notification`, an automatic announcement of a local save
/// (`auto` true), with its participant's key and publish it like
/// [`CoordOutput::Publish`], with a token from the participant's gossip
/// bucket, since no request took one. `span` is its range resolved at
/// `heads`, the save's heads.
AutoPublish {
/// The automatic notification.
notification: Notification,
/// Its range resolved at `heads`.
span: Span,
/// The document's heads after the save.
heads: Vec<Head>,
},
/// Answer the bulletin request `req`: the document's notifications from
/// the last `BULLETIN_SECS`, oldest first.
Bulletin {
/// The request answered.
req: u64,
/// The document's recent notifications, oldest first.
notifications: Vec<Notification>,
},
/// Answer the presence request `req` (decision 303): every
/// participant present on a document, by document, then participant.
Presences {
/// The request answered.
req: u64,
/// Each presence: the document, the participant, its latest `ts`.
presences: Vec<(String, Signer, i64)>,
},
}