pub struct MeshRuntime { /* private fields */ }Expand description
The runtime: the registry (always there, so a surface can answer before activation) and the active machinery once a declaration switched it on.
Implementations§
Source§impl MeshRuntime
impl MeshRuntime
Sourcepub fn new() -> Self
pub fn new() -> Self
An inactive runtime: an empty registry and the reason “nothing activated it”.
Sourcepub fn decided(&self) -> bool
pub fn decided(&self) -> bool
Whether a shared server activated or declined this runtime. false in every process
that is not a server — the command line, a test — where nothing activates the mesh
and MeshRuntime::status reports an absence, not a decision.
The distinction is what lets mesh doctor judge the server: an enabled declaration
and an inactive mesh is a failure when a server decided it and nothing at all when
nobody did.
use majordomus_cli::mesh::manager::MeshRuntime;
let mesh = MeshRuntime::new();
assert!(!mesh.decided(), "nothing has decided the command line's runtime");
assert!(!mesh.status().active);
// a server that could not activate the mesh says why, and that is a decision
mesh.decline("the node identity did not load");
assert!(mesh.decided());
assert!(mesh.status().reason.unwrap().contains("did not load"));Sourcepub fn attach_cooperation(&self, cooperation: Arc<Cooperation>)
pub fn attach_cooperation(&self, cooperation: Arc<Cooperation>)
Attach the cooperation runtime a server built for this mesh. The runtime is already started; a second attachment replaces nothing.
Discovery and cooperation are built separately — one finds runtimes, the other links to them — and this is where the surfaces find both behind one handle. The first attachment wins, so a second server in one process cannot quietly take over the journal the first one is already writing to.
use majordomus_cli::mesh::manager::MeshRuntime;
let mesh = MeshRuntime::new();
let first = built("0000000000000001");
mesh.attach_cooperation(Arc::clone(&first));
mesh.attach_cooperation(built("0000000000000002"));
let attached = mesh.cooperation().expect("a cooperation runtime");
assert_eq!(attached.runtime_key(), first.runtime_key(), "the first one keeps the slot");Sourcepub fn decline_cooperation(&self, reason: &str)
pub fn decline_cooperation(&self, reason: &str)
Record why cooperation is not running while the mesh is.
A mesh that discovers runtimes and links to none is the confusing case: everything looks switched on and nothing is shared. The server that decided not to start cooperation says so here, so the answer reaches whoever asks rather than living in the log of a process they cannot see.
use majordomus_cli::mesh::manager::MeshRuntime;
let mesh = MeshRuntime::new();
mesh.decline_cooperation("no endpoint to be dialed at");
let status = mesh.cooperation_status();
assert!(!status.active);
assert_eq!(status.reason.as_deref(), Some("no endpoint to be dialed at"));Sourcepub fn cooperation(&self) -> Option<Arc<Cooperation>>
pub fn cooperation(&self) -> Option<Arc<Cooperation>>
The cooperation runtime, while one is still running. A stopped runtime is not
handed out: a caller that got it would write to a journal nobody is replicating and
believe it had told the mesh something. None here means the same to every caller
— do this locally, or say it cannot be done — however cooperation came to be absent.
use majordomus_cli::mesh::manager::MeshRuntime;
let mesh = MeshRuntime::new();
assert!(mesh.cooperation().is_none(), "nothing has attached one");
mesh.attach_cooperation(Arc::clone(&cooperation));
assert!(mesh.cooperation().is_some());
cooperation.stop();
assert!(mesh.cooperation().is_none(), "a stopped runtime is not handed out");Sourcepub fn cooperation_status(&self) -> CooperationStatus
pub fn cooperation_status(&self) -> CooperationStatus
Cooperation’s status, or why there is none: the mesh’s own reason when the mesh is off, cooperation’s reason when only cooperation is.
The two reasons are kept apart because they call for different acts. A mesh that was never switched on is a declaration to write; cooperation declined under a running mesh is something about this server — no endpoint, no trusted key — and the more specific reason is the one worth telling a person, so it wins when both exist.
use majordomus_cli::mesh::manager::MeshRuntime;
let mesh = MeshRuntime::new();
let untouched = mesh.cooperation_status();
assert!(untouched.reason.unwrap().contains("no shared server"), "the mesh's reason");
mesh.decline_cooperation("the declaration enables the mesh but not cooperation");
let declined = mesh.cooperation_status();
assert!(declined.reason.unwrap().contains("not cooperation"), "the nearer reason wins");
assert!(declined.peers.is_empty(), "and the shape is the one a live runtime answers");Sourcepub fn registry(&self) -> &Arc<MeshRegistry> ⓘ
pub fn registry(&self) -> &Arc<MeshRegistry> ⓘ
The registry behind this runtime, for surfaces that project it directly.
Sourcepub fn decline(&self, reason: &str)
pub fn decline(&self, reason: &str)
Record why the mesh is not running, without activating anything: a disabled or
malformed declaration is an answer mesh.status must be able to give.
Sourcepub fn activate(
&self,
config: &MeshConfig,
identity: NodeIdentity,
endpoints: Vec<String>,
repos: Vec<String>,
version: &str,
) -> Result<(), MeshError>
pub fn activate( &self, config: &MeshConfig, identity: NodeIdentity, endpoints: Vec<String>, repos: Vec<String>, version: &str, ) -> Result<(), MeshError>
Activate the mesh from a declaration. Idempotent: a second activation of an active runtime is a no-op. A disabled declaration records the reason and starts nothing. Never blocks: every socket lives on its own thread.
Sourcepub fn activate_as(
&self,
config: &MeshConfig,
identity: Arc<NodeIdentity>,
runtime: &str,
endpoints: Vec<String>,
repos: Vec<String>,
version: &str,
) -> Result<(), MeshError>
pub fn activate_as( &self, config: &MeshConfig, identity: Arc<NodeIdentity>, runtime: &str, endpoints: Vec<String>, repos: Vec<String>, version: &str, ) -> Result<(), MeshError>
MeshRuntime::activate for one runtime slot of the node: what a shared server
does, naming its checkout’s runtime so that two servers of one machine announce,
hear and link to each other as the two runtimes they are.
Without the slot, two worktrees of one repository on one machine would announce under one identity and each would take the other’s announcements for its own echo. The slot is what makes them two peers that cooperate, which is the ordinary case on a developer’s machine and not an exotic one.
use std::sync::Arc;
use majordomus_cli::mesh::config::MeshConfig;
use majordomus_cli::mesh::identity::NodeIdentity;
use majordomus_cli::mesh::manager::MeshRuntime;
// a declaration with every discovery mechanism off: nothing opens a socket
let config: MeshConfig = serde_json::from_value(serde_json::json!({
"schema": "mesh/v1", "kind": "mesh", "id": "majordomus", "enabled": true,
"multicast": { "enabled": false },
})).unwrap();
let mesh = MeshRuntime::new();
let identity = Arc::new(NodeIdentity::ephemeral().unwrap());
// a machine whose key the declaration does not list stays closed (see `closed_to`)
let mut config = config;
config.trust.allow = vec![identity.public.public_key.clone()];
mesh.activate_as(&config, Arc::clone(&identity), "0000000000000001",
vec!["127.0.0.1:8742".into()], vec!["root".into()], "doc").unwrap();
let status = mesh.status();
assert!(status.active);
assert_eq!(status.identity.unwrap().node_id, identity.public.node_id);
// idempotent: the second server of this process does not restart the first's mesh
mesh.activate_as(&config, Arc::clone(&identity), "0000000000000002",
vec!["127.0.0.1:8743".into()], vec!["root".into()], "doc").unwrap();
assert_eq!(mesh.status().started_at, status.started_at);Sourcepub fn attach(&self, provider: Box<dyn MeshProvider>) -> Result<(), MeshError>
pub fn attach(&self, provider: Box<dyn MeshProvider>) -> Result<(), MeshError>
Attach one more provider to an active mesh. This is the entire registration a new discovery mechanism needs: no surface, consumer or registry changes with it.
Sourcepub fn begin_stop(&self)
pub fn begin_stop(&self)
Tell the mesh to stop, without waiting for anything: every loop and handler reads the
flag at once, and the draining that needs locks is left to stop. A
process that is shutting down calls this first, does the work that must not be
delayed — closing its listeners, releasing its lease — and only then drains.
use majordomus_cli::mesh::manager::MeshRuntime;
// a mesh that never activated has nothing to tell, and says so rather than failing:
// a shutdown path must not care whether the thing it is stopping ever started
let mesh = MeshRuntime::new();
mesh.begin_stop();
assert!(!mesh.status().active);Sourcepub fn stop(&self)
pub fn stop(&self)
Stop the mesh. Every provider thread and the manager end at their next bounded wait; the registry keeps what it saw for whoever still asks.
Sourcepub fn status(&self) -> MeshStatus
pub fn status(&self) -> MeshStatus
The status, as every surface answers it.
Sourcepub fn nodes(&self) -> Vec<NodeRecord>
pub fn nodes(&self) -> Vec<NodeRecord>
Every observed node, in the registry’s canonical node-id order.
Sourcepub fn register(&self, envelope: &Value, path: &str) -> RegisterAnswer
pub fn register(&self, envelope: &Value, path: &str) -> RegisterAnswer
Handle one rendezvous registration: verify the presented envelope exactly as a datagram, record it, and answer with this node’s envelope and the candidates the registry holds. Registration grants nothing — the caller becomes a record, not a peer with rights.