//! The router's state machine: every routing, queueing and ownership decision, with no I/O. //! //! One `State` sits behind one mutex. Connection tasks call in with a decoded command, get //! their reply queued on the connection's control lane, and do any file I/O (staging //! creation, seal copies, unlinks) only after the lock is released. Writers pull their next //! frame from here, so a delivery is marked dispatched and assigned its delivery id at the //! moment its bytes are about to be written, never earlier. //! //! Ownership: every sealed artifact has a root count. A root is held by each queued delivery, //! each delivery handed to a client and not yet consumed, each explicit hold and each retained //! topic value that references it; a delivery naming the same artifact twice holds one root. //! The last root to go collects the artifact: its bytes leave the quota and its file is //! unlinked. Staging writers are not roots; an unsealed artifact is owned by its writer alone. use std::collections::{HashMap, HashSet, VecDeque}; use std::sync::Arc; use serde_json::{Map, Value}; use tokio::sync::{Notify, watch}; use crate::error::{BusError, Dispatch, ErrorCode}; use crate::limits::Limits; use crate::policy::{Grants, Policy}; use crate::store::{sealed_rel, staging_rel}; use crate::wire::{ ArtifactRef, Attachment, Envelope, Fields, GENERATION, Identity, Kind, MAJOR, MAX_BATCH, MAX_CREDIT, MAX_ENVELOPE_BYTES, MINOR, WireError, id_batch, parse_serial_id, serial_id, }; pub(crate) type ConnKey = u64; type CallKey = u64; /// After this many consecutive control or RPC frames while topic data waits, one topic frame /// goes out, so telemetry is deprioritised but never starved outright. const TOPIC_STARVATION_LIMIT: u32 = 16; /// Placeholder that is as long as any router-issued serial id can be. const MAX_SERIAL: u64 = u64::MAX; /// Signals between a connection's tasks and the state. pub(crate) struct ConnSignals { /// Wakes the writer: something may be ready to send. pub wake: Notify, /// Flips to true when the connection is closed; both tasks watch it. pub shutdown: watch::Sender, /// Serializes synchronous transport polls with connection teardown. It is never held /// across an await. pub write_gate: std::sync::Mutex, /// The last frames to write before closing: a refusal or `connection.closing` notice, /// preceded on router shutdown by `subscription.closed` notices. pub final_frames: std::sync::Mutex>>, } #[derive(Default)] pub(crate) struct WriteGate { closing: bool, frame_len: usize, written: usize, cut_partial: bool, } impl WriteGate { pub(crate) fn begin_frame(&mut self, len: usize) -> bool { if self.closing { return false; } self.frame_len = len; self.written = 0; true } pub(crate) fn wrote(&mut self, len: usize) { self.written += len; debug_assert!(self.written <= self.frame_len); } pub(crate) fn finish_frame(&mut self) { if !self.closing { debug_assert_eq!(self.written, self.frame_len); self.frame_len = 0; self.written = 0; } } fn begin_close(&mut self) { self.closing = true; self.cut_partial = self.written > 0 && self.written < self.frame_len; } pub(crate) fn closing(&self) -> bool { self.closing } pub(crate) fn cut_partial(&self) -> bool { self.cut_partial } } impl ConnSignals { pub(crate) fn new() -> ConnSignals { ConnSignals { wake: Notify::new(), shutdown: watch::Sender::new(false), write_gate: std::sync::Mutex::new(WriteGate::default()), final_frames: std::sync::Mutex::new(Vec::new()), } } } /// What the connection task must do after `handle` returns. pub(crate) enum Outcome { Done, /// Create the staging file, then call `finish_allocate`. Allocate(AllocJob), /// Copy staging into the sealed file (off the routing path), then call `finish_seal`. Seal(SealJob), /// The connection was closed; stop reading. Close, } pub(crate) struct AllocJob { pub conn: ConnKey, pub reply_to: String, pub serial: u64, pub len: u64, pub owner: u64, } pub(crate) struct SealJob { pub conn: ConnKey, pub reply_to: String, pub serial: u64, pub len: u64, pub digest: Option, pub owner: u64, } pub(crate) enum NextFrame { Frame(Vec), Idle, Gone, } pub(crate) struct Outbound { kind: Kind, op: String, reply_to: Option, body: Map, attachments: Vec, /// Conservative encoded size using the longest router envelope id. bytes: usize, } /// Registry counters, for tests and resource measurement. They are logical: an unlinked file /// a process still has open keeps its pages until that process closes it. #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct RouterStats { pub connections: usize, pub services: usize, pub topics: usize, pub subscriptions: usize, /// Call correlation records the router still keeps, detached ones included. pub calls: usize, /// Calls counted against their callers' active-call limits (admitted, not finished, /// not detached). pub active_calls: usize, /// Artifacts in any state: writing, sealing or sealed. pub artifacts: usize, pub sealed_artifacts: usize, /// Sum of root counts over sealed artifacts. pub artifact_roots: u64, /// Live owners (deliveries, holds, writers) over all connections. pub owners: usize, /// Live request reply capabilities. They are independent of delivery credit but share the /// per-client bound. pub reply_capabilities: usize, /// Admitted and not yet dispatched: topic messages in subscription queues, calls in /// service queues and results waiting for their caller. pub queued: usize, /// Staging, sealing-copy and sealed bytes currently charged to the store. pub store_bytes: u64, pub retained_bytes: u64, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] enum OwnerKey { Delivery(u64), Hold(u64), } enum Owner { Writer { artifact: u64, sealing: bool, }, Hold { artifact: u64, }, Delivery { artifacts: Vec, kind: DeliveryKind, }, } impl Owner { /// Counted against the ordinary owner budget (everything but RPC deliveries). fn ordinary(&self) -> bool { !matches!( self, Owner::Delivery { kind: DeliveryKind::Request { .. } | DeliveryKind::Result { .. }, .. } ) } } enum DeliveryKind { Topic { sub: u64, }, Request { call: CallKey, service: String, incarnation: String, }, Result { call: CallKey, }, } struct Hello { identity: Identity, grants: Grants, } struct Conn { signals: Arc, connection_id: String, hello: Option, expected_client_id: Option, last_command: Option, out_serial: u64, delivery_issued: u64, hold_issued: u64, sub_issued: u64, owners: HashMap, ordinary_owners: usize, subs: HashMap, sub_order: Vec, sub_cursor: usize, services: Vec, svc_cursor: usize, /// Request delivery serial -> call, for `rpc.reply` correlation. requests: HashMap, reply_capabilities: usize, call_watermark: Option, /// Admitted calls not yet finished or detached, by call serial. active_calls: HashMap, result_queue: VecDeque, control: VecDeque, control_bytes: usize, streak: u32, queued_bytes: usize, } struct Art { state: ArtState, byte_length: u64, content_type: String, digest: Option, roots: u64, } #[derive(Clone, Copy, PartialEq, Eq)] enum ArtState { Writing, Sealing, Sealed, } struct TopicMsg { topic: String, topic_incarnation: String, sequence: u64, payload: Map, attachments: Vec<(String, ArtifactRef)>, artifacts: Vec, bytes: usize, artifact_bytes: u64, } struct Sub { topic: String, topic_incarnation: String, latest: bool, max_queued: u64, max_in_flight: u64, in_flight: u64, queue: VecDeque>, replaced: u64, } struct Topic { incarnation: String, retain: bool, sequence: u64, retained: Option>, subscribers: Vec<(ConnKey, u64)>, } struct Svc { incarnation: String, conn: ConnKey, max_queued: u64, max_in_flight: u64, in_flight: u64, queue: VecDeque, } struct ResultMsg { responder: Identity, outcome: Map, attachments: Vec<(String, ArtifactRef)>, artifacts: Vec, } enum Phase { Queued, Dispatched { delivery: u64 }, Replied { delivery: u64, result: CallResult }, } enum CallResult { Queued(ResultMsg), Delivered, } struct Call { caller: ConnKey, caller_identity: Identity, call_serial: u64, call_id: String, target: String, service_incarnation: String, service_conn: ConnKey, method: String, payload: Map, attachments: Vec<(String, ArtifactRef)>, artifacts: Vec, phase: Phase, detached: bool, reply_capability: bool, } #[derive(Default)] struct ClientRecord { live: Option, last_incarnation: Option, } pub(crate) struct State { pub router_id: String, pub store_id: String, contract_digest: String, limits: Limits, policy: Policy, closed: bool, conns: HashMap, identities: HashMap, services: HashMap, topics: HashMap, artifacts: HashMap, calls: HashMap, next_conn: u64, next_service: u64, next_topic: u64, next_artifact: u64, next_call: u64, store_bytes: u64, retained_bytes: u64, subscriptions: usize, unlinks: Vec, notices: Vec<(ConnKey, &'static str, Map)>, } fn obj(pairs: Vec<(&str, Value)>) -> Map { pairs.into_iter().map(|(k, v)| (k.to_owned(), v)).collect() } fn err(code: ErrorCode, message: impl Into) -> Result { Err(BusError::new(code, message)) } fn wire(e: WireError) -> BusError { e.into() } fn dedup(serials: Vec) -> Vec { let mut seen = HashSet::new(); serials.into_iter().filter(|s| seen.insert(*s)).collect() } fn attachments_with_owner(list: &[(String, ArtifactRef)], owner: &str) -> Vec { list.iter() .map(|(name, r)| Attachment { name: name.clone(), reference: r.clone(), owner_id: owner.to_owned(), }) .collect() } fn frame_len( kind: Kind, op: &str, body: Map, attachments: Vec, ) -> usize { let mut env = Envelope::new(serial_id("bus", MAX_SERIAL), kind, op, body); env.attachments = attachments; serde_json::to_vec(&env.to_value()) .map(|b| b.len()) .unwrap_or(usize::MAX) } impl Call { fn request_body(&self, delivery_id: &str) -> Map { obj(vec![ ("deliveryId", delivery_id.into()), ("callId", self.call_id.clone().into()), ("caller", self.caller_identity.to_json()), ("target", self.target.clone().into()), ( "serviceIncarnation", self.service_incarnation.clone().into(), ), ("method", self.method.clone().into()), ("payload", Value::Object(self.payload.clone())), ]) } fn result_body(&self, delivery_id: &str, result: &ResultMsg) -> Map { obj(vec![ ("deliveryId", delivery_id.into()), ("callId", self.call_id.clone().into()), ("responder", result.responder.to_json()), ( "serviceIncarnation", self.service_incarnation.clone().into(), ), ("outcome", Value::Object(result.outcome.clone())), ]) } } impl TopicMsg { fn body(&self, delivery_id: &str, subscription_id: &str, replaced: u64) -> Map { obj(vec![ ("deliveryId", delivery_id.into()), ("subscriptionId", subscription_id.into()), ("topic", self.topic.clone().into()), ("topicIncarnation", self.topic_incarnation.clone().into()), ("topicSequence", self.sequence.to_string().into()), ("replaced", replaced.to_string().into()), ("payload", Value::Object(self.payload.clone())), ]) } } impl State { pub(crate) fn new( router_id: String, store_id: String, contract_digest: String, limits: Limits, policy: Policy, ) -> State { State { router_id, store_id, contract_digest, limits, policy, closed: false, conns: HashMap::new(), identities: HashMap::new(), services: HashMap::new(), topics: HashMap::new(), artifacts: HashMap::new(), calls: HashMap::new(), next_conn: 0, next_service: 0, next_topic: 0, next_artifact: 0, next_call: 0, store_bytes: 0, retained_bytes: 0, subscriptions: 0, unlinks: Vec::new(), notices: Vec::new(), } } /// Store files (relative paths) to unlink once the lock is released. pub(crate) fn take_unlinks(&mut self) -> Vec { std::mem::take(&mut self.unlinks) } pub(crate) fn stats(&self) -> RouterStats { RouterStats { connections: self.conns.len(), services: self.services.len(), topics: self.topics.len(), subscriptions: self.subscriptions, calls: self.calls.len(), active_calls: self.conns.values().map(|c| c.active_calls.len()).sum(), artifacts: self.artifacts.len(), sealed_artifacts: self .artifacts .values() .filter(|a| a.state == ArtState::Sealed) .count(), artifact_roots: self.artifacts.values().map(|a| a.roots).sum(), owners: self.conns.values().map(|c| c.owners.len()).sum(), reply_capabilities: self.conns.values().map(|c| c.reply_capabilities).sum(), queued: self .conns .values() .map(|c| { c.subs.values().map(|s| s.queue.len()).sum::() + c.result_queue.len() }) .sum::() + self.services.values().map(|s| s.queue.len()).sum::(), store_bytes: self.store_bytes, retained_bytes: self.retained_bytes, } } // ----------------------------------------------------------------------------------------- // Connections pub(crate) fn add_conn( &mut self, signals: Arc, expected_client_id: Option, ) -> Option { if self.closed || self.conns.len() >= self.limits.max_clients || (expected_client_id.is_none() && !self.policy.permits_unbound_transport()) { return None; } self.next_conn += 1; let key = self.next_conn; self.conns.insert( key, Conn { signals, connection_id: serial_id("conn", key), hello: None, expected_client_id, last_command: None, out_serial: 0, delivery_issued: 0, hold_issued: 0, sub_issued: 0, owners: HashMap::new(), ordinary_owners: 0, subs: HashMap::new(), sub_order: Vec::new(), sub_cursor: 0, services: Vec::new(), svc_cursor: 0, requests: HashMap::new(), reply_capabilities: 0, call_watermark: None, active_calls: HashMap::new(), result_queue: VecDeque::new(), control: VecDeque::new(), control_bytes: 0, streak: 0, queued_bytes: 0, }, ); Some(key) } fn wake(&self, c: ConnKey) { if let Some(conn) = self.conns.get(&c) { conn.signals.wake.notify_one(); } } /// Builds a router-originated item without assigning its envelope id. IDs are assigned only /// after the scheduler selects an item, so fairness cannot reorder numbered envelopes. fn outbound( &self, kind: Kind, op: &str, reply_to: Option, body: Map, attachments: Vec, ) -> Option { let mut env = Envelope::new(serial_id("bus", MAX_SERIAL), kind, op, body.clone()); env.reply_to = reply_to; env.attachments = attachments.clone(); let bytes = env.encode().ok()?.len(); Some(Outbound { kind, op: op.to_owned(), reply_to: env.reply_to, body, attachments, bytes, }) } fn encode_outbound(&mut self, c: ConnKey, item: Outbound) -> Option> { let conn = self.conns.get_mut(&c)?; conn.out_serial += 1; let mut env = Envelope::new( serial_id("bus", conn.out_serial), item.kind, &item.op, item.body, ); env.reply_to = item.reply_to; env.attachments = item.attachments; env.encode().ok() } /// Queues a reply or notice on the control lane; closes the connection if the lane is full. fn push_control(&mut self, c: ConnKey, frame: Outbound) { let (frames, bytes) = ( self.limits.max_control_frames, self.limits.max_control_bytes, ); let Some(conn) = self.conns.get_mut(&c) else { return; }; if conn.control.len() >= frames || conn.control_bytes + frame.bytes > bytes { let body = obj(vec![ ("code", ErrorCode::QuotaExceeded.as_str().into()), ( "message", "control lane exhausted: replies and notices are not being read".into(), ), ]); let last = self.outbound(Kind::Notice, "connection.closing", None, body, Vec::new()); self.close_conn(c, last); return; } conn.control_bytes += frame.bytes; conn.control.push_back(frame); conn.signals.wake.notify_one(); } fn reply( &mut self, c: ConnKey, reply_to: &str, op: &str, result: Result, BusError>, ) { let body = reply_body(result); if let Some(frame) = self.outbound(Kind::Reply, op, Some(reply_to.to_owned()), body, Vec::new()) { self.push_control(c, frame); } } fn notice(&mut self, c: ConnKey, op: &'static str, body: Map) { self.notices.push((c, op, body)); } /// Sends deferred notices. Pushing one may close its connection, whose cleanup may defer /// more, so this loops until none are left. fn flush_notices(&mut self) { while !self.notices.is_empty() { for (c, op, body) in std::mem::take(&mut self.notices) { if let Some(frame) = self.outbound(Kind::Notice, op, None, body, Vec::new()) { self.push_control(c, frame); } } } } /// Closes `c`: records the final frames, signals both tasks and releases everything the /// connection owned. Replies still queued on its control lane are dropped. pub(crate) fn close_conn( &mut self, c: ConnKey, final_frames: impl IntoIterator, ) { let Some(conn) = self.conns.get(&c) else { return; }; let signals = conn.signals.clone(); let final_frames = final_frames .into_iter() .filter_map(|frame| self.encode_outbound(c, frame)); signals .final_frames .lock() .unwrap_or_else(|e| e.into_inner()) .extend(final_frames); // A transport poll that is already in progress finishes before this lock is acquired. // Once acquired, teardown marks the stream closing before reclaiming any owner, and no // later normal-frame poll is allowed through. let mut write_gate = signals.write_gate.lock().unwrap_or_else(|e| e.into_inner()); write_gate.begin_close(); self.disconnect(c); signals.shutdown.send_replace(true); signals.wake.notify_one(); drop(write_gate); self.flush_notices(); } fn violation(&mut self, c: ConnKey, message: String) -> Outcome { let body = obj(vec![ ("code", ErrorCode::InvalidEnvelope.as_str().into()), ("message", message.into()), ]); let last = self.outbound(Kind::Notice, "connection.closing", None, body, Vec::new()); self.close_conn(c, last); Outcome::Close } /// A frame that failed to decode: close with a notice. pub(crate) fn reject_frame(&mut self, c: ConnKey, message: String) { self.violation(c, message); } /// Closes every connection and refuses new ones. pub(crate) fn shutdown(&mut self) { self.closed = true; let keys: Vec = self.conns.keys().copied().collect(); for c in keys { let mut finals = Vec::new(); let subs: Vec<(u64, String, String)> = self.conns[&c] .subs .iter() .map(|(id, s)| (*id, s.topic.clone(), s.topic_incarnation.clone())) .collect(); for (id, topic, inc) in subs { let body = obj(vec![ ("subscriptionId", serial_id("sub", id).into()), ("topic", topic.into()), ("topicIncarnation", inc.into()), ("reason", "router-stopping".into()), ]); finals.extend(self.outbound( Kind::Notice, "subscription.closed", None, body, Vec::new(), )); } let body = obj(vec![ ("code", ErrorCode::RouterLost.as_str().into()), ("message", "router stopping".into()), ]); finals.extend(self.outbound( Kind::Notice, "connection.closing", None, body, Vec::new(), )); self.close_conn(c, finals); } let topics: Vec = self.topics.keys().cloned().collect(); for t in topics { if let Some(msg) = self.topics.get_mut(&t).and_then(|t| t.retained.take()) { self.retained_bytes -= msg.artifact_bytes; self.drop_roots(&msg.artifacts); } } } /// Releases everything `c` owned. Retained topic values stay; they are router-owned. pub(crate) fn disconnect(&mut self, c: ConnKey) { let Some(conn) = self.conns.get(&c) else { return; }; if let Some(h) = &conn.hello && let Some(rec) = self.identities.get_mut(&h.identity.client_id) && rec.live == Some(c) { rec.live = None; } // Services: queued calls fail; dispatched ones are settled with the owners below. for name in conn.services.clone() { self.remove_service(&name, "disconnected"); } // Subscriptions. let conn = self.conns.get_mut(&c).expect("present"); let subs: Vec = conn.sub_order.clone(); for id in subs { self.drop_subscription(c, id); } // Owners. let conn = self.conns.get_mut(&c).expect("present"); let owners: Vec<(OwnerKey, Owner)> = conn.owners.drain().collect(); conn.ordinary_owners = 0; for (_, owner) in owners { self.release_owner(c, owner); } // Calls dispatched to this connection that it never answered, whether or not it still // held the request: the caller learns the call may have executed. let served: Vec = self .calls .iter() .filter(|(_, call)| { call.service_conn == c && matches!(call.phase, Phase::Dispatched { .. }) }) .map(|(k, _)| *k) .collect(); for key in served { let call = &self.calls[&key]; if !call.detached { let body = obj(vec![ ("callId", call.call_id.clone().into()), ("code", ErrorCode::NoService.as_str().into()), ("message", "the service disconnected before replying".into()), ("dispatch", Dispatch::Dispatched.as_str().into()), ]); let caller = call.caller; self.notice(caller, "call.failed", body); } self.remove_call(key); } // Calls this connection made. let mine: Vec = self .calls .iter() .filter(|(_, call)| call.caller == c) .map(|(k, _)| *k) .collect(); for key in mine { let Some(call) = self.calls.get_mut(&key) else { continue; }; match call.phase { Phase::Queued => { let (target, inc) = (call.target.clone(), call.service_incarnation.clone()); if let Some(svc) = self .services .get_mut(&target) .filter(|s| s.incarnation == inc) { svc.queue.retain(|k| *k != key); } self.remove_call(key); } // The service may still reply (it will hear `routed:false`) or consume the // request; the record goes when either happens. Phase::Dispatched { .. } => { call.detached = true; if !call.reply_capability { self.remove_call(key); } } Phase::Replied { .. } => self.remove_call(key), } } if let Some(conn) = self.conns.remove(&c) { debug_assert!(conn.owners.is_empty()); } } // ----------------------------------------------------------------------------------------- // Roots and artifacts fn add_roots(&mut self, serials: &[u64]) { for s in serials { if let Some(a) = self.artifacts.get_mut(s) { a.roots += 1; } } } fn drop_roots(&mut self, serials: &[u64]) { for s in serials { let Some(a) = self.artifacts.get_mut(s) else { continue; }; a.roots -= 1; if a.roots == 0 && a.state == ArtState::Sealed { let a = self.artifacts.remove(s).expect("present"); self.store_bytes -= a.byte_length; self.unlinks.push(sealed_rel(*s)); } } } fn reference(&self, serial: u64) -> Option { let a = self.artifacts.get(&serial)?; Some(ArtifactRef { store_id: self.store_id.clone(), artifact_id: serial_id("a", serial), generation: GENERATION, byte_length: a.byte_length, content_type: a.content_type.clone(), digest: a.digest.clone(), }) } /// Drops an unsealed writer's artifact and its staging reservation. fn abandon_writer(&mut self, serial: u64) { if let Some(a) = self.artifacts.remove(&serial) { self.store_bytes -= a.byte_length; self.unlinks.push(staging_rel(serial)); } } fn take_owner(&mut self, c: ConnKey, key: OwnerKey) -> Option { let conn = self.conns.get_mut(&c)?; let owner = conn.owners.remove(&key)?; if owner.ordinary() { conn.ordinary_owners -= 1; } Some(owner) } fn insert_owner(&mut self, c: ConnKey, key: OwnerKey, owner: Owner) { let conn = self.conns.get_mut(&c).expect("present"); if owner.ordinary() { conn.ordinary_owners += 1; } conn.owners.insert(key, owner); } fn ordinary_budget_left(&self, c: ConnKey) -> bool { let conn = &self.conns[&c]; conn.ordinary_owners < self.limits.max_owners_per_client - self.limits.reserved_owners_per_client && conn.owners.len() < self.limits.max_owners_per_client } /// Releases a removed owner's roots and returns its credit. fn release_owner(&mut self, c: ConnKey, owner: Owner) { match owner { Owner::Hold { artifact } => self.drop_roots(&[artifact]), // A sealing writer's artifact is reclaimed by `finish_seal`, which finds its owner gone. Owner::Writer { artifact, sealing: false, } => self.abandon_writer(artifact), Owner::Writer { sealing: true, .. } => {} Owner::Delivery { artifacts, kind } => { self.drop_roots(&artifacts); match kind { DeliveryKind::Topic { sub } => { if let Some(s) = self .conns .get_mut(&c) .and_then(|conn| conn.subs.get_mut(&sub)) { s.in_flight -= 1; } } DeliveryKind::Request { call, service, incarnation, } => { if let Some(svc) = self .services .get_mut(&service) .filter(|s| s.incarnation == incarnation) { svc.in_flight -= 1; } // A detached call without a remaining reply capability is terminal. if self .calls .get(&call) .is_some_and(|e| e.detached && !e.reply_capability) { self.remove_call(call); } } DeliveryKind::Result { call } => self.remove_call(call), } } } self.wake(c); } /// Checks that `owner_id` is a live owner on `c` holding the sealed artifact `r`. fn check_owned(&self, c: ConnKey, r: &ArtifactRef, owner_id: &str) -> Result { if r.store_id != self.store_id { return err( ErrorCode::ArtifactGone, "reference from another store incarnation", ); } let Some(serial) = parse_serial_id("a", &r.artifact_id) else { return err(ErrorCode::ArtifactGone, "unknown artifact id"); }; let key = if let Some(n) = parse_serial_id("dlv", owner_id) { OwnerKey::Delivery(n) } else if let Some(n) = parse_serial_id("own", owner_id) { OwnerKey::Hold(n) } else { return err(ErrorCode::OwnerInvalid, "not an owner id"); }; let conn = &self.conns[&c]; let holds = match conn.owners.get(&key) { None => { return err( ErrorCode::OwnerInvalid, format!("{owner_id} is not a live owner on this connection"), ); } Some(Owner::Writer { artifact, .. }) if *artifact == serial => { return err(ErrorCode::ArtifactUnsealed, "artifact is not sealed"); } Some(Owner::Writer { .. }) => false, Some(Owner::Hold { artifact }) => *artifact == serial, Some(Owner::Delivery { artifacts, .. }) => artifacts.contains(&serial), }; if !holds { return err( ErrorCode::OwnerInvalid, format!("{owner_id} does not own {}", r.artifact_id), ); } let Some(art) = self.artifacts.get(&serial) else { return err(ErrorCode::ArtifactGone, "artifact was collected"); }; if art.state != ArtState::Sealed { return err(ErrorCode::ArtifactUnsealed, "artifact is not sealed"); } if self.reference(serial).as_ref() != Some(r) { return err( ErrorCode::ArtifactMismatch, "reference does not match the artifact", ); } Ok(serial) } /// Validates every attachment and returns the distinct artifacts, in first-seen order. fn check_attachments(&self, c: ConnKey, list: &[Attachment]) -> Result, BusError> { let mut serials = Vec::with_capacity(list.len()); for a in list { serials.push(self.check_owned(c, &a.reference, &a.owner_id)?); } Ok(dedup(serials)) } // ----------------------------------------------------------------------------------------- // Commands pub(crate) fn handle(&mut self, c: ConnKey, env: Envelope) -> Outcome { let Some(conn) = self.conns.get_mut(&c) else { return Outcome::Close; }; if env.kind != Kind::Command || env.reply_to.is_some() { return self.violation(c, "clients send commands only, with a null replyTo".into()); } let Some(serial) = parse_serial_id("msg", &env.id) else { return self.violation(c, "command ids are msg-".into()); }; if conn.last_command.is_some_and(|last| serial <= last) { return self.violation(c, "command ids must increase".into()); } conn.last_command = Some(serial); if conn.hello.is_none() { if env.op != "bus.hello" { return self.violation(c, "the first command must be bus.hello".into()); } return self.hello(c, env); } if env.op == "bus.hello" { return self.violation(c, "bus.hello was already negotiated".into()); } if env.major != MAJOR || env.minor != MINOR { return self.violation( c, format!("envelopes on this connection are {MAJOR}.{MINOR}"), ); } let op = env.op.clone(); let result = if !env.attachments.is_empty() && !matches!(op.as_str(), "rpc.call" | "rpc.reply" | "publish") { err( ErrorCode::InvalidEnvelope, format!("{op} takes no attachments"), ) } else { match op.as_str() { "service.register" => self.op_register(c, &env), "service.unregister" => self.op_unregister(c, &env), "rpc.call" => self.op_call(c, &env), "rpc.reply" => self.op_reply(c, &env), "rpc.responder.release" => self.op_responder_release(c, &env), "rpc.cancel" => self.op_cancel(c, &env), "topic.declare" => self.op_declare(c, &env), "topic.clear" => self.op_clear(c, &env), "topic.delete" => self.op_delete(c, &env), "subscribe" => self.op_subscribe(c, &env), "unsubscribe" => self.op_unsubscribe(c, &env), "publish" => self.op_publish(c, &env), "delivery.consumed" => self.op_consumed(c, &env), "artifact.release" => self.op_release(c, &env), "artifact.open" => self.op_open(c, &env), "artifact.retain" => self.op_retain(c, &env), "artifact.allocate" => match self.op_allocate(c, &env) { Ok(job) => return Outcome::Allocate(job), Err(e) => Err(e), }, "artifact.seal" => match self.op_seal(c, &env) { Ok(job) => return Outcome::Seal(job), Err(e) => Err(e), }, _ => err( ErrorCode::InvalidEnvelope, format!("unknown operation {op:?}"), ), } }; self.reply(c, &env.id, &op, result); self.flush_notices(); if self.conns.contains_key(&c) { Outcome::Done } else { Outcome::Close } } fn grants(&self, c: ConnKey) -> &Grants { &self.conns[&c].hello.as_ref().expect("after hello").grants } fn identity(&self, c: ConnKey) -> Identity { self.conns[&c] .hello .as_ref() .expect("after hello") .identity .clone() } fn hello(&mut self, c: ConnKey, env: Envelope) -> Outcome { let parsed = (|| -> Result<(String, String, Vec), WireError> { let mut f = Fields::of(&env.body, "bus.hello"); let client_id = f.id("clientId")?; let incarnation = f.id("clientIncarnation")?; let majors = f.array("supportedMajors", 1, 16)?; let mut out = Vec::new(); for m in majors { match m.as_u64() { Some(n) if (1..=MAX_CREDIT).contains(&n) => out.push(n), _ => { return Err(WireError( "bus.hello: supportedMajors holds integers 1..=65535".into(), )); } } } f.finish()?; Ok((client_id, incarnation, out)) })(); let refuse = |s: &mut State, e: BusError| { let body = reply_body(Err(e)); let last = s.outbound( Kind::Reply, "bus.hello", Some(env.id.clone()), body, Vec::new(), ); s.close_conn(c, last); Outcome::Close }; let (client_id, incarnation, majors) = match parsed { Ok(p) => p, Err(e) => return refuse(self, e.into()), }; if !env.attachments.is_empty() { return refuse(self, BusError::invalid("bus.hello takes no attachments")); } if !majors.contains(&MAJOR) { return refuse( self, BusError::new( ErrorCode::VersionMismatch, format!("this router speaks major {MAJOR} only"), ), ); } let Some(grants) = self.policy.grants_for(&client_id) else { return refuse( self, BusError::new(ErrorCode::NotAuthorized, "client id is not configured"), ); }; let rec = self.identities.entry(client_id.clone()).or_default(); if rec.live.is_some() { return refuse( self, BusError::new(ErrorCode::NotAuthorized, "client id is already connected"), ); } if rec.last_incarnation.as_deref() == Some(incarnation.as_str()) { return refuse( self, BusError::new( ErrorCode::NotAuthorized, "client incarnation was already used", ), ); } if let Some(expected) = self.conns[&c].expected_client_id.as_deref() && expected != client_id { return refuse( self, BusError::new( ErrorCode::NotAuthorized, "client id does not match the launcher's transport binding", ), ); } let rec = self.identities.get_mut(&client_id).expect("inserted"); rec.live = Some(c); rec.last_incarnation = Some(incarnation.clone()); let identity = Identity { client_id, client_incarnation: incarnation, }; let conn = self.conns.get_mut(&c).expect("present"); conn.hello = Some(Hello { identity, grants }); let value = obj(vec![ ("routerId", self.router_id.clone().into()), ("connectionId", conn.connection_id.clone().into()), ("selectedMajor", MAJOR.into()), ("selectedMinor", MINOR.into()), ("contractDigest", self.contract_digest.clone().into()), ("limits", self.limits.to_json()), ]); self.reply(c, &env.id, "bus.hello", Ok(value)); if self.conns.contains_key(&c) { Outcome::Done } else { Outcome::Close } } // ---- services and RPC fn op_register(&mut self, c: ConnKey, env: &Envelope) -> Result, BusError> { let mut f = Fields::of(&env.body, "service.register"); let name = f.name("name").map_err(wire)?; let max_queued = f.int("maxQueued", 1, MAX_CREDIT).map_err(wire)?; let max_in_flight = f.int("maxInFlight", 1, MAX_CREDIT).map_err(wire)?; f.finish().map_err(wire)?; if !Grants::allows(&self.grants(c).register, &name) { return err(ErrorCode::NotAuthorized, format!("may not register {name}")); } if max_queued > self.limits.max_service_queued || max_in_flight > self.limits.max_service_in_flight { return err( ErrorCode::QuotaExceeded, "maxQueued or maxInFlight exceeds the configured limit", ); } if self.services.contains_key(&name) { return err(ErrorCode::Conflict, format!("{name} is already registered")); } if self.services.len() >= self.limits.max_services { return err(ErrorCode::QuotaExceeded, "too many services"); } self.next_service += 1; let incarnation = serial_id("svc", self.next_service); self.services.insert( name.clone(), Svc { incarnation: incarnation.clone(), conn: c, max_queued, max_in_flight, in_flight: 0, queue: VecDeque::new(), }, ); self.conns.get_mut(&c).expect("present").services.push(name); Ok(obj(vec![("serviceIncarnation", incarnation.into())])) } fn op_unregister( &mut self, c: ConnKey, env: &Envelope, ) -> Result, BusError> { let mut f = Fields::of(&env.body, "service.unregister"); let name = f.name("name").map_err(wire)?; let incarnation = f.id("serviceIncarnation").map_err(wire)?; f.finish().map_err(wire)?; let mine = self .services .get(&name) .is_some_and(|s| s.conn == c && s.incarnation == incarnation); if mine { self.remove_service(&name, "unregistered"); } Ok(obj(vec![("removed", mine.into())])) } /// Removes a registration. Queued calls fail with `call.failed`; each affected caller also /// hears `route.removed`. Dispatched calls stay correlated: the service may still reply. fn remove_service(&mut self, name: &str, reason: &str) { let Some(svc) = self.services.remove(name) else { return; }; if let Some(conn) = self.conns.get_mut(&svc.conn) { conn.services.retain(|n| n != name); } let mut callers = Vec::new(); for (_, call) in self.calls.iter() { let open = matches!(call.phase, Phase::Queued | Phase::Dispatched { .. }); if call.service_incarnation == svc.incarnation && open && !call.detached && !callers.contains(&call.caller) { callers.push(call.caller); } } for caller in callers { let body = obj(vec![ ("name", name.into()), ("serviceIncarnation", svc.incarnation.clone().into()), ("reason", reason.into()), ]); self.notice(caller, "route.removed", body); } for key in svc.queue { let Some(call) = self.calls.get(&key) else { continue; }; let body = obj(vec![ ("callId", call.call_id.clone().into()), ("code", ErrorCode::NoService.as_str().into()), ( "message", format!("{name} was {reason} before the call was dispatched").into(), ), ("dispatch", Dispatch::NotDispatched.as_str().into()), ]); let caller = call.caller; self.notice(caller, "call.failed", body); self.remove_call(key); } let abandoned: Vec = self .calls .iter() .filter(|(_, call)| { call.service_incarnation == svc.incarnation && matches!(call.phase, Phase::Dispatched { .. }) && !call.reply_capability }) .map(|(key, _)| *key) .collect(); for key in abandoned { let call = &self.calls[&key]; if !call.detached { self.notice( call.caller, "call.failed", obj(vec![ ("callId", call.call_id.clone().into()), ("code", ErrorCode::NoService.as_str().into()), ( "message", format!("{name} was {reason} after dispatch").into(), ), ("dispatch", Dispatch::Dispatched.as_str().into()), ]), ); } self.remove_call(key); } } /// Forgets a call: frees the caller's slot, the reply correlation and any roots the call /// itself still holds (queued request, queued result). fn remove_call(&mut self, key: CallKey) { let Some(call) = self.calls.remove(&key) else { return; }; if let Some(conn) = self.conns.get_mut(&call.caller) { if conn.active_calls.get(&call.call_serial) == Some(&key) { conn.active_calls.remove(&call.call_serial); } conn.result_queue.retain(|k| *k != key); } match call.phase { Phase::Queued => self.drop_roots(&call.artifacts), Phase::Dispatched { delivery } => { if let Some(conn) = self.conns.get_mut(&call.service_conn) { conn.requests.remove(&delivery); if call.reply_capability { conn.reply_capabilities -= 1; } } } Phase::Replied { delivery, result } => { if let Some(conn) = self.conns.get_mut(&call.service_conn) { conn.requests.remove(&delivery); if call.reply_capability { conn.reply_capabilities -= 1; } } if let CallResult::Queued(msg) = result { self.drop_roots(&msg.artifacts); } } } } fn op_call(&mut self, c: ConnKey, env: &Envelope) -> Result, BusError> { let mut f = Fields::of(&env.body, "rpc.call"); let call_id = f.id("callId").map_err(wire)?; let target = f.name("target").map_err(wire)?; let expected = f.nullable_id("expectedIncarnation").map_err(wire)?; let method = f.method("method").map_err(wire)?; let payload = f.object("payload").map_err(wire)?.clone(); f.finish().map_err(wire)?; let Some(call_serial) = parse_serial_id("call", &call_id) else { return err(ErrorCode::InvalidEnvelope, "callId must be call-"); }; if self.conns[&c] .call_watermark .is_some_and(|w| call_serial <= w) { return err( ErrorCode::InvalidEnvelope, "callId was already used or is not increasing", ); } // The issued-id history advances after syntactic validation, before semantic admission. self.conns.get_mut(&c).expect("present").call_watermark = Some(call_serial); if !Grants::allows(&self.grants(c).call, &target) { return err(ErrorCode::NotAuthorized, format!("may not call {target}")); } let conn = &self.conns[&c]; if conn.active_calls.len() >= self.limits.max_active_calls_per_client { return err(ErrorCode::Backpressure, "too many active calls"); } let Some(svc) = self.services.get(&target) else { return err(ErrorCode::NoService, format!("{target} is not registered")); }; if expected.as_ref().is_some_and(|e| *e != svc.incarnation) { return err( ErrorCode::TargetChanged, format!("{target} is now {}", svc.incarnation), ); } if svc.queue.len() as u64 >= svc.max_queued { return err(ErrorCode::Backpressure, format!("{target} queue is full")); } let artifacts = self.check_attachments(c, &env.attachments)?; let call = Call { caller: c, caller_identity: self.identity(c), call_serial, call_id, target: target.clone(), service_incarnation: svc.incarnation.clone(), service_conn: svc.conn, method, payload, attachments: env .attachments .iter() .map(|a| (a.name.clone(), a.reference.clone())) .collect(), artifacts, phase: Phase::Queued, detached: false, reply_capability: false, }; let placeholder = serial_id("dlv", MAX_SERIAL); let size = frame_len( Kind::Delivery, "rpc.request", call.request_body(&placeholder), attachments_with_owner(&call.attachments, &placeholder), ); if size > MAX_ENVELOPE_BYTES { return err( ErrorCode::InvalidEnvelope, "the request delivery would exceed the envelope limit", ); } // Admission: roots first, then the queue entry, then the reply. self.add_roots(&call.artifacts); self.next_call += 1; let key = self.next_call; let incarnation = call.service_incarnation.clone(); let service_conn = call.service_conn; self.calls.insert(key, call); self.services .get_mut(&target) .expect("checked") .queue .push_back(key); let conn = self.conns.get_mut(&c).expect("present"); conn.active_calls.insert(call_serial, key); self.wake(service_conn); Ok(obj(vec![ ("accepted", true.into()), ("serviceIncarnation", incarnation.into()), ])) } fn op_reply(&mut self, c: ConnKey, env: &Envelope) -> Result, BusError> { let mut f = Fields::of(&env.body, "rpc.reply"); let call_id = f.id("callId").map_err(wire)?; let delivery_id = f.id("requestDeliveryId").map_err(wire)?; let outcome = f.object("outcome").map_err(wire)?.clone(); f.finish().map_err(wire)?; let Some(n) = parse_serial_id("dlv", &delivery_id) else { return err( ErrorCode::InvalidEnvelope, "requestDeliveryId must be dlv-", ); }; let conn = &self.conns[&c]; if n > conn.delivery_issued { return err( ErrorCode::OwnerInvalid, "requestDeliveryId was never issued to this connection", ); } let Some(&key) = conn.requests.get(&n) else { return err( ErrorCode::CallGone, "no call awaits a reply for that request", ); }; let call = &self.calls[&key]; if call.call_id != call_id { return err( ErrorCode::InvalidEnvelope, "callId does not match the request", ); } if matches!(call.phase, Phase::Replied { .. }) { return err(ErrorCode::CallGone, "the call was already replied to"); } let artifacts = self.check_attachments(c, &env.attachments)?; let result = ResultMsg { responder: self.identity(c), outcome, attachments: env .attachments .iter() .map(|a| (a.name.clone(), a.reference.clone())) .collect(), artifacts, }; let placeholder = serial_id("dlv", MAX_SERIAL); let size = frame_len( Kind::Delivery, "rpc.result", call.result_body(&placeholder, &result), attachments_with_owner(&result.attachments, &placeholder), ); if size > MAX_ENVELOPE_BYTES { return err( ErrorCode::InvalidEnvelope, "the result delivery would exceed the envelope limit", ); } if call.detached { self.remove_call(key); return Ok(obj(vec![("routed", false.into())])); } let caller = call.caller; self.add_roots(&result.artifacts); let released_capability = self.calls[&key].reply_capability; if released_capability { self.conns .get_mut(&c) .expect("service is connected") .reply_capabilities -= 1; } let call = self.calls.get_mut(&key).expect("present"); call.reply_capability = false; call.phase = Phase::Replied { delivery: n, result: CallResult::Queued(result), }; self.conns .get_mut(&caller) .expect("attached caller is connected") .result_queue .push_back(key); self.wake(caller); Ok(obj(vec![("routed", true.into())])) } fn op_responder_release( &mut self, c: ConnKey, env: &Envelope, ) -> Result, BusError> { let mut f = Fields::of(&env.body, "rpc.responder.release"); let call_id = f.id("callId").map_err(wire)?; let delivery_id = f.id("requestDeliveryId").map_err(wire)?; f.finish().map_err(wire)?; let Some(delivery) = parse_serial_id("dlv", &delivery_id) else { return err( ErrorCode::InvalidEnvelope, "requestDeliveryId must be dlv-", ); }; if delivery > self.conns[&c].delivery_issued { return err( ErrorCode::OwnerInvalid, "requestDeliveryId was never issued to this connection", ); } let Some(&key) = self.conns[&c].requests.get(&delivery) else { return Ok(obj(vec![("released", false.into())])); }; if self.calls[&key].call_id != call_id { return err( ErrorCode::InvalidEnvelope, "callId does not match the request", ); } if !self.calls[&key].reply_capability { return Ok(obj(vec![("released", false.into())])); } let detached = self.calls[&key].detached; let service_live = { let call = &self.calls[&key]; self.services.get(&call.target).is_some_and(|service| { service.conn == call.service_conn && service.incarnation == call.service_incarnation }) }; self.calls .get_mut(&key) .expect("request maps to a call") .reply_capability = false; self.conns .get_mut(&c) .expect("service is connected") .reply_capabilities -= 1; if detached { self.remove_call(key); } else { let call = &self.calls[&key]; let (code, message) = if service_live { ( ErrorCode::CallGone, "the last responder was released without replying", ) } else { ( ErrorCode::NoService, "the service route ended after dispatch without a reply", ) }; self.notice( call.caller, "call.failed", obj(vec![ ("callId", call.call_id.clone().into()), ("code", code.as_str().into()), ("message", message.into()), ("dispatch", Dispatch::Dispatched.as_str().into()), ]), ); self.remove_call(key); } Ok(obj(vec![("released", true.into())])) } fn op_cancel(&mut self, c: ConnKey, env: &Envelope) -> Result, BusError> { let mut f = Fields::of(&env.body, "rpc.cancel"); let call_id = f.id("callId").map_err(wire)?; f.finish().map_err(wire)?; let Some(serial) = parse_serial_id("call", &call_id) else { return err(ErrorCode::InvalidEnvelope, "callId must be call-"); }; let state = match self.conns[&c].active_calls.get(&serial).copied() { None => "call-gone", Some(key) => match self.calls[&key].phase { Phase::Queued => { let call = &self.calls[&key]; let (target, inc) = (call.target.clone(), call.service_incarnation.clone()); if let Some(svc) = self .services .get_mut(&target) .filter(|s| s.incarnation == inc) { svc.queue.retain(|k| *k != key); } self.remove_call(key); "cancelled-before-dispatch" } Phase::Dispatched { .. } => { self.calls.get_mut(&key).expect("present").detached = true; self.conns .get_mut(&c) .expect("present") .active_calls .remove(&serial); if !self.calls[&key].reply_capability { self.remove_call(key); } "execution-unknown" } Phase::Replied { .. } => "completed", }, }; Ok(obj(vec![("state", state.into())])) } // ---- topics fn op_declare(&mut self, c: ConnKey, env: &Envelope) -> Result, BusError> { let mut f = Fields::of(&env.body, "topic.declare"); let name = f.name("name").map_err(wire)?; let retain = match f.string("retained").map_err(wire)? { "none" => false, "latest" => true, _ => { return err( ErrorCode::InvalidEnvelope, "retained is \"none\" or \"latest\"", ); } }; f.finish().map_err(wire)?; if !Grants::allows(&self.grants(c).manage_topics, &name) { return err(ErrorCode::NotAuthorized, format!("may not declare {name}")); } if let Some(t) = self.topics.get(&name) { if t.retain != retain { return err( ErrorCode::Conflict, format!("{name} is declared with other settings"), ); } return Ok(obj(vec![ ("declared", false.into()), ("topicIncarnation", t.incarnation.clone().into()), ])); } if self.topics.len() >= self.limits.max_topics { return err(ErrorCode::QuotaExceeded, "too many topics"); } self.next_topic += 1; let incarnation = serial_id("top", self.next_topic); self.topics.insert( name, Topic { incarnation: incarnation.clone(), retain, sequence: 0, retained: None, subscribers: Vec::new(), }, ); Ok(obj(vec![ ("declared", true.into()), ("topicIncarnation", incarnation.into()), ])) } fn op_clear(&mut self, c: ConnKey, env: &Envelope) -> Result, BusError> { let mut f = Fields::of(&env.body, "topic.clear"); let name = f.name("name").map_err(wire)?; f.finish().map_err(wire)?; if !Grants::allows(&self.grants(c).manage_topics, &name) { return err(ErrorCode::NotAuthorized, format!("may not clear {name}")); } let Some(t) = self.topics.get_mut(&name) else { return err(ErrorCode::NoTopic, format!("{name} is not declared")); }; let old = t.retained.take(); let cleared = old.is_some(); if let Some(msg) = old { self.retained_bytes -= msg.artifact_bytes; self.drop_roots(&msg.artifacts); } Ok(obj(vec![("cleared", cleared.into())])) } fn op_delete(&mut self, c: ConnKey, env: &Envelope) -> Result, BusError> { let mut f = Fields::of(&env.body, "topic.delete"); let name = f.name("name").map_err(wire)?; f.finish().map_err(wire)?; if !Grants::allows(&self.grants(c).manage_topics, &name) { return err(ErrorCode::NotAuthorized, format!("may not delete {name}")); } let Some(t) = self.topics.get(&name) else { return Ok(obj(vec![("deleted", false.into())])); }; if !t.subscribers.is_empty() { return err(ErrorCode::Conflict, format!("{name} still has subscribers")); } let t = self.topics.remove(&name).expect("present"); if let Some(msg) = t.retained { self.retained_bytes -= msg.artifact_bytes; self.drop_roots(&msg.artifacts); } Ok(obj(vec![("deleted", true.into())])) } fn op_subscribe(&mut self, c: ConnKey, env: &Envelope) -> Result, BusError> { let mut f = Fields::of(&env.body, "subscribe"); let topic = f.name("topic").map_err(wire)?; let latest = match f.string("mode").map_err(wire)? { "latest" => true, "bounded" => false, _ => { return err( ErrorCode::InvalidEnvelope, "mode is \"latest\" or \"bounded\"", ); } }; let max_queued = f.int("maxQueued", 1, MAX_CREDIT).map_err(wire)?; let max_in_flight = f.int("maxInFlight", 1, MAX_CREDIT).map_err(wire)?; let replay = f.boolean("replayLatest").map_err(wire)?; f.finish().map_err(wire)?; if !Grants::allows(&self.grants(c).subscribe, &topic) { return err( ErrorCode::NotAuthorized, format!("may not subscribe to {topic}"), ); } if latest && max_queued != 1 { return err( ErrorCode::InvalidEnvelope, "latest subscriptions have maxQueued 1", ); } let (queue_cap, credit_cap) = if latest { (1, self.limits.max_latest_in_flight) } else { ( self.limits.max_bounded_queued, self.limits.max_bounded_in_flight, ) }; if max_queued > queue_cap || max_in_flight > credit_cap { return err( ErrorCode::QuotaExceeded, "maxQueued or maxInFlight exceeds the configured limit", ); } let Some(t) = self.topics.get(&topic) else { return err(ErrorCode::NoTopic, format!("{topic} is not declared")); }; let conn = &self.conns[&c]; if conn.subs.len() >= self.limits.max_subscriptions_per_client || self.subscriptions >= self.limits.max_subscriptions { return err(ErrorCode::QuotaExceeded, "too many subscriptions"); } let incarnation = t.incarnation.clone(); let replayed = if replay { t.retained.clone() } else { None }; if !latest && replayed.as_ref().is_some_and(|msg| { conn.queued_bytes.saturating_add(msg.bytes) > self.limits.max_queued_bytes_per_client }) { return err( ErrorCode::Backpressure, "retained replay exceeds the bounded subscriber's queued-byte limit", ); } let mut sub = Sub { topic: topic.clone(), topic_incarnation: incarnation.clone(), latest, max_queued, max_in_flight, in_flight: 0, queue: VecDeque::new(), replaced: 0, }; let mut bytes = 0; if let Some(msg) = replayed { self.add_roots(&msg.artifacts); if !latest { bytes = msg.bytes; } sub.queue.push_back(msg); } let conn = self.conns.get_mut(&c).expect("present"); conn.sub_issued += 1; let id = conn.sub_issued; conn.queued_bytes += bytes; conn.subs.insert(id, sub); conn.sub_order.push(id); self.subscriptions += 1; self.topics .get_mut(&topic) .expect("present") .subscribers .push((c, id)); self.wake(c); Ok(obj(vec![ ("subscriptionId", serial_id("sub", id).into()), ("topicIncarnation", incarnation.into()), ])) } /// Removes a subscription and releases its queue. Deliveries already handed out keep their /// roots until consumed. fn drop_subscription(&mut self, c: ConnKey, id: u64) -> bool { let Some(conn) = self.conns.get_mut(&c) else { return false; }; let Some(sub) = conn.subs.remove(&id) else { return false; }; conn.sub_order.retain(|s| *s != id); self.subscriptions -= 1; if !sub.latest { conn.queued_bytes -= sub.queue.iter().map(|m| m.bytes).sum::(); } if let Some(t) = self .topics .get_mut(&sub.topic) .filter(|t| t.incarnation == sub.topic_incarnation) { t.subscribers.retain(|s| *s != (c, id)); } for msg in sub.queue { self.drop_roots(&msg.artifacts); } true } fn op_unsubscribe( &mut self, c: ConnKey, env: &Envelope, ) -> Result, BusError> { let mut f = Fields::of(&env.body, "unsubscribe"); let sid = f.id("subscriptionId").map_err(wire)?; f.finish().map_err(wire)?; let removed = parse_serial_id("sub", &sid).is_some_and(|id| self.drop_subscription(c, id)); Ok(obj(vec![("removed", removed.into())])) } fn op_publish(&mut self, c: ConnKey, env: &Envelope) -> Result, BusError> { let mut f = Fields::of(&env.body, "publish"); let topic = f.name("topic").map_err(wire)?; let payload = f.object("payload").map_err(wire)?.clone(); f.finish().map_err(wire)?; if !Grants::allows(&self.grants(c).publish, &topic) { return err( ErrorCode::NotAuthorized, format!("may not publish to {topic}"), ); } let Some(t) = self.topics.get(&topic) else { return err(ErrorCode::NoTopic, format!("{topic} is not declared")); }; let artifacts = self.check_attachments(c, &env.attachments)?; let artifact_bytes: u64 = artifacts .iter() .map(|s| self.artifacts[s].byte_length) .sum(); let mut msg = TopicMsg { topic: topic.clone(), topic_incarnation: t.incarnation.clone(), sequence: t.sequence + 1, payload, attachments: env .attachments .iter() .map(|a| (a.name.clone(), a.reference.clone())) .collect(), artifacts, bytes: 0, artifact_bytes, }; let placeholder = serial_id("dlv", MAX_SERIAL); msg.bytes = frame_len( Kind::Delivery, "topic.message", msg.body(&placeholder, &serial_id("sub", MAX_SERIAL), MAX_SERIAL), attachments_with_owner(&msg.attachments, &placeholder), ); if msg.bytes > MAX_ENVELOPE_BYTES { return err( ErrorCode::InvalidEnvelope, "the delivery would exceed the envelope limit", ); } // Admission is all or nothing: check every subscriber and the retention quota before // touching anything. let mut extra: HashMap = HashMap::new(); for (sc, sid) in &t.subscribers { let conn = &self.conns[sc]; let sub = &conn.subs[sid]; if sub.latest { continue; } if sub.queue.len() as u64 >= sub.max_queued { return err( ErrorCode::Backpressure, "a bounded subscriber's queue is full", ); } let add = extra.entry(*sc).or_default(); *add += msg.bytes; if conn.queued_bytes + *add > self.limits.max_queued_bytes_per_client { return err( ErrorCode::Backpressure, "a bounded subscriber's queued bytes are at the limit", ); } } if t.retain { let old = t.retained.as_ref().map_or(0, |m| m.artifact_bytes); if self.retained_bytes - old + msg.artifact_bytes > self.limits.max_retained_bytes { return err(ErrorCode::QuotaExceeded, "retained bytes are at the limit"); } } // Accept. let msg = Arc::new(msg); let t = self.topics.get_mut(&topic).expect("present"); t.sequence += 1; let subscribers = t.subscribers.clone(); let retain = t.retain; let mut replaced = 0u64; for (sc, sid) in &subscribers { let conn = self.conns.get_mut(sc).expect("subscriber is connected"); let sub = conn.subs.get_mut(sid).expect("subscription is live"); let dropped = if sub.latest { let old = sub.queue.pop_front(); if old.is_some() { sub.replaced += 1; replaced += 1; } old } else { conn.queued_bytes += msg.bytes; None }; sub.queue.push_back(msg.clone()); self.add_roots(&msg.artifacts); if let Some(old) = dropped { self.drop_roots(&old.artifacts); } self.wake(*sc); } if retain { self.add_roots(&msg.artifacts); self.retained_bytes += msg.artifact_bytes; let old = self .topics .get_mut(&topic) .expect("present") .retained .replace(msg.clone()); if let Some(old) = old { self.retained_bytes -= old.artifact_bytes; self.drop_roots(&old.artifacts); } } Ok(obj(vec![ ("topicSequence", msg.sequence.to_string().into()), ("subscribers", subscribers.len().to_string().into()), ("replaced", replaced.to_string().into()), ])) } // ---- ownership fn op_consumed(&mut self, c: ConnKey, env: &Envelope) -> Result, BusError> { let mut f = Fields::of(&env.body, "delivery.consumed"); let ids = id_batch( f.array("deliveryIds", 1, MAX_BATCH).map_err(wire)?, "deliveryIds", ) .map_err(wire)?; f.finish().map_err(wire)?; let issued = self.conns[&c].delivery_issued; let mut serials = Vec::with_capacity(ids.len()); for id in &ids { match parse_serial_id("dlv", id) { Some(n) if n <= issued => serials.push(n), Some(_) => return err(ErrorCode::OwnerInvalid, format!("{id} was never issued")), None => { return err( ErrorCode::OwnerInvalid, format!("{id} is not a delivery id"), ); } } } let mut released = 0u64; for n in serials { if let Some(owner) = self.take_owner(c, OwnerKey::Delivery(n)) { released += 1; self.release_owner(c, owner); } } Ok(obj(vec![("released", released.to_string().into())])) } fn op_release(&mut self, c: ConnKey, env: &Envelope) -> Result, BusError> { let mut f = Fields::of(&env.body, "artifact.release"); let ids = id_batch(f.array("ownerIds", 1, MAX_BATCH).map_err(wire)?, "ownerIds").map_err(wire)?; f.finish().map_err(wire)?; let issued = self.conns[&c].hold_issued; let mut serials = Vec::with_capacity(ids.len()); for id in &ids { match parse_serial_id("own", id) { Some(n) if n <= issued => serials.push(n), Some(_) => return err(ErrorCode::OwnerInvalid, format!("{id} was never issued")), None => { return err( ErrorCode::OwnerInvalid, format!("{id} is not a hold; deliveries end with delivery.consumed"), ); } } } let mut released = 0u64; for n in serials { if let Some(owner) = self.take_owner(c, OwnerKey::Hold(n)) { released += 1; self.release_owner(c, owner); } } Ok(obj(vec![("released", released.to_string().into())])) } fn op_open(&mut self, c: ConnKey, env: &Envelope) -> Result, BusError> { let mut f = Fields::of(&env.body, "artifact.open"); let r = ArtifactRef::from_json(f.value("ref").map_err(wire)?).map_err(wire)?; let owner = f.id("ownerId").map_err(wire)?; f.finish().map_err(wire)?; let serial = self.check_owned(c, &r, &owner)?; let loc = crate::wire::Location { store_id: self.store_id.clone(), relative_path: sealed_rel(serial), }; Ok(obj(vec![("readLocation", loc.to_json())])) } fn op_retain(&mut self, c: ConnKey, env: &Envelope) -> Result, BusError> { let mut f = Fields::of(&env.body, "artifact.retain"); let r = ArtifactRef::from_json(f.value("ref").map_err(wire)?).map_err(wire)?; let owner = f.id("ownerId").map_err(wire)?; f.finish().map_err(wire)?; let serial = self.check_owned(c, &r, &owner)?; if !self.ordinary_budget_left(c) { return err(ErrorCode::QuotaExceeded, "owner budget exhausted"); } let conn = self.conns.get_mut(&c).expect("present"); conn.hold_issued += 1; let n = conn.hold_issued; self.insert_owner(c, OwnerKey::Hold(n), Owner::Hold { artifact: serial }); self.add_roots(&[serial]); Ok(obj(vec![("ownerId", serial_id("own", n).into())])) } fn op_allocate(&mut self, c: ConnKey, env: &Envelope) -> Result { let mut f = Fields::of(&env.body, "artifact.allocate"); let len = f.u64_string("byteLength").map_err(wire)?; let content_type = f.string("contentType").map_err(wire)?.to_owned(); f.finish().map_err(wire)?; if !crate::wire::is_content_type(&content_type) { return err( ErrorCode::InvalidEnvelope, "contentType must be 1..=127 printable ASCII characters", ); } if len > self.limits.max_artifact_bytes { return err( ErrorCode::QuotaExceeded, "byteLength exceeds the per-object limit", ); } if self.store_bytes.saturating_add(len) > self.limits.max_store_bytes { return err(ErrorCode::QuotaExceeded, "the store is full"); } if !self.ordinary_budget_left(c) { return err(ErrorCode::QuotaExceeded, "owner budget exhausted"); } self.next_artifact += 1; let serial = self.next_artifact; self.artifacts.insert( serial, Art { state: ArtState::Writing, byte_length: len, content_type, digest: None, roots: 0, }, ); self.store_bytes += len; let conn = self.conns.get_mut(&c).expect("present"); conn.hold_issued += 1; let owner = conn.hold_issued; self.insert_owner( c, OwnerKey::Hold(owner), Owner::Writer { artifact: serial, sealing: false, }, ); Ok(AllocJob { conn: c, reply_to: env.id.clone(), serial, len, owner, }) } pub(crate) fn finish_allocate(&mut self, job: AllocJob, created: std::io::Result<()>) { let live = self.conns.get(&job.conn).is_some_and(|conn| { matches!( conn.owners.get(&OwnerKey::Hold(job.owner)), Some(Owner::Writer { .. }) ) }); match created { Err(e) => { if live { self.take_owner(job.conn, OwnerKey::Hold(job.owner)); } if let Some(a) = self.artifacts.remove(&job.serial) { self.store_bytes -= a.byte_length; } self.reply( job.conn, &job.reply_to, "artifact.allocate", err(ErrorCode::StoreFailure, format!("staging: {e}")), ); } Ok(()) if !live || !self.artifacts.contains_key(&job.serial) => { // The connection went away while the file was being made. self.unlinks.push(staging_rel(job.serial)); } Ok(()) => { let loc = crate::wire::Location { store_id: self.store_id.clone(), relative_path: staging_rel(job.serial), }; let value = obj(vec![ ("artifactId", serial_id("a", job.serial).into()), ("generation", GENERATION.to_string().into()), ("ownerId", serial_id("own", job.owner).into()), ("writeLocation", loc.to_json()), ]); self.reply(job.conn, &job.reply_to, "artifact.allocate", Ok(value)); } } self.flush_notices(); } fn op_seal(&mut self, c: ConnKey, env: &Envelope) -> Result { let mut f = Fields::of(&env.body, "artifact.seal"); let artifact_id = f.id("artifactId").map_err(wire)?; let generation = f.u64_string("generation").map_err(wire)?; let owner_id = f.id("ownerId").map_err(wire)?; let digest = match f.value("digest").map_err(wire)? { Value::Null => None, Value::String(s) if crate::wire::is_digest(s) => Some(s.clone()), _ => { return err( ErrorCode::InvalidEnvelope, "digest must be null or 64 lowercase hex digits", ); } }; f.finish().map_err(wire)?; let Some(serial) = parse_serial_id("a", &artifact_id) else { return err(ErrorCode::ArtifactGone, "unknown artifact id"); }; let Some(owner) = parse_serial_id("own", &owner_id) else { return err(ErrorCode::OwnerInvalid, "ownerId is not a writer"); }; match self.conns[&c].owners.get(&OwnerKey::Hold(owner)) { Some(Owner::Writer { artifact, sealing: false, }) if *artifact == serial => {} Some(Owner::Writer { artifact, sealing: true, }) if *artifact == serial => { return err(ErrorCode::OwnerInvalid, "a seal is already in progress"); } Some(Owner::Hold { artifact }) if *artifact == serial => { return err(ErrorCode::OwnerInvalid, "the artifact is already sealed"); } _ => { return err( ErrorCode::OwnerInvalid, format!("{owner_id} is not the writer of {artifact_id}"), ); } } if generation != GENERATION { return err(ErrorCode::ArtifactGone, "unknown generation"); } let len = self.artifacts[&serial].byte_length; if self.store_bytes.saturating_add(len) > self.limits.max_store_bytes { self.take_owner(c, OwnerKey::Hold(owner)); self.abandon_writer(serial); return err( ErrorCode::QuotaExceeded, "no room for the sealing copy; the staging object was released", ); } self.store_bytes += len; self.artifacts.get_mut(&serial).expect("present").state = ArtState::Sealing; let conn = self.conns.get_mut(&c).expect("present"); conn.owners.insert( OwnerKey::Hold(owner), Owner::Writer { artifact: serial, sealing: true, }, ); Ok(SealJob { conn: c, reply_to: env.id.clone(), serial, len, digest, owner, }) } pub(crate) fn finish_seal( &mut self, job: SealJob, result: Result<(), crate::store::SealFailure>, ) { let owner_live = self.conns.get(&job.conn).is_some_and(|conn| { matches!(conn.owners.get(&OwnerKey::Hold(job.owner)), Some(Owner::Writer { artifact, sealing: true }) if *artifact == job.serial) }); let reply = match (result, owner_live) { (Ok(()), true) => { let art = self .artifacts .get_mut(&job.serial) .expect("sealing artifact is registered"); art.state = ArtState::Sealed; art.digest = job.digest.clone(); art.roots = 1; // The seal task already unlinked staging; its reservation ends here. self.store_bytes -= job.len; let conn = self.conns.get_mut(&job.conn).expect("present"); conn.owners.insert( OwnerKey::Hold(job.owner), Owner::Hold { artifact: job.serial, }, ); let r = self.reference(job.serial).expect("present"); Ok(obj(vec![ ("ref", r.to_json()), ("ownerId", serial_id("own", job.owner).into()), ])) } (result, _) => { if self.artifacts.remove(&job.serial).is_some() { self.store_bytes -= 2 * job.len; } self.unlinks.push(sealed_rel(job.serial)); if owner_live { self.take_owner(job.conn, OwnerKey::Hold(job.owner)); } match result { Ok(()) => err( ErrorCode::ArtifactGone, "the writer was released during the seal", ), Err(crate::store::SealFailure::Mismatch(m)) => { err(ErrorCode::ArtifactMismatch, m) } Err(crate::store::SealFailure::Io(e)) => { err(ErrorCode::StoreFailure, format!("seal: {e}")) } } } }; self.reply(job.conn, &job.reply_to, "artifact.seal", reply); self.flush_notices(); } // ----------------------------------------------------------------------------------------- // Writers pull frames fn topic_ready(&self, c: ConnKey) -> bool { if !self.ordinary_budget_left(c) { return false; } let conn = &self.conns[&c]; conn.subs .values() .any(|s| s.in_flight < s.max_in_flight && !s.queue.is_empty()) } /// The next frame for `c`: control first, then RPC, then topic data, with topic data /// guaranteed a turn after [`TOPIC_STARVATION_LIMIT`] higher-priority frames. pub(crate) fn next_frame(&mut self, c: ConnKey) -> NextFrame { if !self.conns.contains_key(&c) { return NextFrame::Gone; } let topic_ready = self.topic_ready(c); let starving = topic_ready && self.conns[&c].streak >= TOPIC_STARVATION_LIMIT; if !starving && let Some(f) = self.pop_control(c).or_else(|| self.dispatch_rpc(c)) { if topic_ready { self.conns.get_mut(&c).expect("present").streak += 1; } return self.selected_frame(c, f); } if let Some(f) = self.dispatch_topic(c) { self.conns.get_mut(&c).expect("present").streak = 0; return self.selected_frame(c, f); } match self.pop_control(c).or_else(|| self.dispatch_rpc(c)) { Some(f) => self.selected_frame(c, f), None => NextFrame::Idle, } } fn selected_frame(&mut self, c: ConnKey, frame: Outbound) -> NextFrame { match self.encode_outbound(c, frame) { Some(bytes) => NextFrame::Frame(bytes), None => NextFrame::Gone, } } fn pop_control(&mut self, c: ConnKey) -> Option { let conn = self.conns.get_mut(&c)?; let f = conn.control.pop_front()?; conn.control_bytes -= f.bytes; Some(f) } fn dispatch_rpc(&mut self, c: ConnKey) -> Option { if self.conns[&c].owners.len() + self.conns[&c].reply_capabilities >= self.limits.max_owners_per_client { return None; } // Results for calls this connection made. if let Some(key) = self.conns.get_mut(&c)?.result_queue.pop_front() { let call = self.calls.get_mut(&key)?; let Phase::Replied { delivery, result } = std::mem::replace(&mut call.phase, Phase::Queued) else { unreachable!("queued results belong to replied calls"); }; let CallResult::Queued(msg) = result else { unreachable!("result queued once") }; call.phase = Phase::Replied { delivery, result: CallResult::Delivered, }; let conn = self.conns.get_mut(&c).expect("present"); conn.delivery_issued += 1; let n = conn.delivery_issued; let did = serial_id("dlv", n); let call = &self.calls[&key]; let body = call.result_body(&did, &msg); let atts = attachments_with_owner(&msg.attachments, &did); self.insert_owner( c, OwnerKey::Delivery(n), Owner::Delivery { artifacts: msg.artifacts, kind: DeliveryKind::Result { call: key }, }, ); return self.outbound(Kind::Delivery, "rpc.result", None, body, atts); } // Requests for services this connection registered, round robin. let conn = &self.conns[&c]; let n_svcs = conn.services.len(); for i in 0..n_svcs { let idx = (conn.svc_cursor + i) % n_svcs; let name = conn.services[idx].clone(); let svc = self.services.get_mut(&name)?; if svc.in_flight >= svc.max_in_flight || svc.queue.is_empty() { continue; } if self.conns[&c].owners.len() + self.conns[&c].reply_capabilities + 2 > self.limits.max_owners_per_client { continue; } let key = svc.queue.pop_front().expect("nonempty"); svc.in_flight += 1; let incarnation = svc.incarnation.clone(); let conn = self.conns.get_mut(&c).expect("present"); conn.svc_cursor = idx + 1; conn.delivery_issued += 1; let n = conn.delivery_issued; conn.requests.insert(n, key); conn.reply_capabilities += 1; let call = self.calls.get_mut(&key).expect("queued call is registered"); // Dispatched before a byte of it is written. call.phase = Phase::Dispatched { delivery: n }; call.reply_capability = true; let did = serial_id("dlv", n); let body = call.request_body(&did); let atts = attachments_with_owner(&call.attachments, &did); let artifacts = call.artifacts.clone(); self.insert_owner( c, OwnerKey::Delivery(n), Owner::Delivery { artifacts, kind: DeliveryKind::Request { call: key, service: name, incarnation, }, }, ); return self.outbound(Kind::Delivery, "rpc.request", None, body, atts); } None } fn dispatch_topic(&mut self, c: ConnKey) -> Option { if !self.ordinary_budget_left(c) { return None; } let conn = self.conns.get_mut(&c)?; let n_subs = conn.sub_order.len(); for i in 0..n_subs { let idx = (conn.sub_cursor + i) % n_subs; let id = conn.sub_order[idx]; let sub = conn.subs.get_mut(&id).expect("ordered subscription exists"); if sub.in_flight >= sub.max_in_flight || sub.queue.is_empty() { continue; } let msg = sub.queue.pop_front().expect("nonempty"); sub.in_flight += 1; let replaced = std::mem::take(&mut sub.replaced); if !sub.latest { conn.queued_bytes -= msg.bytes; } conn.sub_cursor = idx + 1; conn.delivery_issued += 1; let n = conn.delivery_issued; let did = serial_id("dlv", n); let body = msg.body(&did, &serial_id("sub", id), replaced); let atts = attachments_with_owner(&msg.attachments, &did); self.insert_owner( c, OwnerKey::Delivery(n), Owner::Delivery { artifacts: msg.artifacts.clone(), kind: DeliveryKind::Topic { sub: id }, }, ); return self.outbound(Kind::Delivery, "topic.message", None, body, atts); } None } } fn reply_body(result: Result, BusError>) -> Map { match result { Ok(value) => obj(vec![("ok", true.into()), ("value", Value::Object(value))]), Err(e) => obj(vec![ ("ok", false.into()), ( "error", Value::Object(obj(vec![ ("code", e.code.as_str().into()), ("message", e.message.into()), ("dispatch", e.dispatch.as_str().into()), ])), ), ]), } }