mirror of
https://github.com/logos-blockchain/logos-blockchain-testing.git
synced 2026-04-01 00:33:40 +00:00
Expand cfgsync rustdoc coverage
This commit is contained in:
parent
5e9b59140d
commit
b90734483b
@ -19,21 +19,29 @@ pub struct ArtifactSet {
|
||||
}
|
||||
|
||||
impl ArtifactSet {
|
||||
/// Creates one logical artifact group.
|
||||
///
|
||||
/// The same type is used for:
|
||||
/// - node-local files that belong to one node only
|
||||
/// - shared files that should be delivered alongside every node
|
||||
#[must_use]
|
||||
pub fn new(files: Vec<ArtifactFile>) -> Self {
|
||||
Self { files }
|
||||
}
|
||||
|
||||
/// Returns the files carried by this artifact group.
|
||||
#[must_use]
|
||||
pub fn files(&self) -> &[ArtifactFile] {
|
||||
&self.files
|
||||
}
|
||||
|
||||
/// Returns `true` when the group contains no files.
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.files.is_empty()
|
||||
}
|
||||
|
||||
/// Consumes the group and returns its files.
|
||||
#[must_use]
|
||||
pub fn into_files(self) -> Vec<ArtifactFile> {
|
||||
self.files
|
||||
@ -49,21 +57,25 @@ pub struct ResolvedNodeArtifacts {
|
||||
}
|
||||
|
||||
impl ResolvedNodeArtifacts {
|
||||
/// Creates the resolved file set for one node.
|
||||
#[must_use]
|
||||
pub fn new(node: ArtifactSet, shared: ArtifactSet) -> Self {
|
||||
Self { node, shared }
|
||||
}
|
||||
|
||||
/// Returns the node-local files.
|
||||
#[must_use]
|
||||
pub fn node(&self) -> &ArtifactSet {
|
||||
&self.node
|
||||
}
|
||||
|
||||
/// Returns the shared files delivered alongside every node.
|
||||
#[must_use]
|
||||
pub fn shared(&self) -> &ArtifactSet {
|
||||
&self.shared
|
||||
}
|
||||
|
||||
/// Returns the full file list that should be written for this node.
|
||||
#[must_use]
|
||||
pub fn files(&self) -> Vec<ArtifactFile> {
|
||||
let mut files = self.node.files().to_vec();
|
||||
@ -79,6 +91,7 @@ pub struct NodeArtifactsCatalog {
|
||||
}
|
||||
|
||||
impl NodeArtifactsCatalog {
|
||||
/// Creates a catalog indexed by stable node identifier.
|
||||
#[must_use]
|
||||
pub fn new(nodes: Vec<NodeArtifacts>) -> Self {
|
||||
let nodes = nodes
|
||||
@ -89,21 +102,25 @@ impl NodeArtifactsCatalog {
|
||||
Self { nodes }
|
||||
}
|
||||
|
||||
/// Resolves one node's local artifacts by identifier.
|
||||
#[must_use]
|
||||
pub fn resolve(&self, identifier: &str) -> Option<&NodeArtifacts> {
|
||||
self.nodes.get(identifier)
|
||||
}
|
||||
|
||||
/// Returns the number of nodes in the catalog.
|
||||
#[must_use]
|
||||
pub fn len(&self) -> usize {
|
||||
self.nodes.len()
|
||||
}
|
||||
|
||||
/// Returns `true` when the catalog is empty.
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.nodes.is_empty()
|
||||
}
|
||||
|
||||
/// Consumes the catalog and returns its node entries.
|
||||
#[must_use]
|
||||
pub fn into_nodes(self) -> Vec<NodeArtifacts> {
|
||||
self.nodes.into_values().collect()
|
||||
@ -118,26 +135,34 @@ pub struct MaterializedArtifacts {
|
||||
}
|
||||
|
||||
impl MaterializedArtifacts {
|
||||
/// Creates a fully materialized cfgsync result.
|
||||
///
|
||||
/// `nodes` contains node-specific files.
|
||||
/// `shared` contains files that should accompany every node.
|
||||
#[must_use]
|
||||
pub fn new(nodes: NodeArtifactsCatalog, shared: ArtifactSet) -> Self {
|
||||
Self { nodes, shared }
|
||||
}
|
||||
|
||||
/// Creates a materialized result without any shared files.
|
||||
#[must_use]
|
||||
pub fn from_catalog(nodes: NodeArtifactsCatalog) -> Self {
|
||||
Self::new(nodes, ArtifactSet::default())
|
||||
}
|
||||
|
||||
/// Returns the node-specific artifact catalog.
|
||||
#[must_use]
|
||||
pub fn nodes(&self) -> &NodeArtifactsCatalog {
|
||||
&self.nodes
|
||||
}
|
||||
|
||||
/// Returns the shared artifact set.
|
||||
#[must_use]
|
||||
pub fn shared(&self) -> &ArtifactSet {
|
||||
&self.shared
|
||||
}
|
||||
|
||||
/// Resolves the full file set for one node.
|
||||
#[must_use]
|
||||
pub fn resolve(&self, identifier: &str) -> Option<ResolvedNodeArtifacts> {
|
||||
self.nodes.resolve(identifier).map(|node| {
|
||||
|
||||
@ -10,6 +10,10 @@ pub type DynCfgsyncError = Box<dyn Error + Send + Sync + 'static>;
|
||||
|
||||
/// Adapter-side materialization contract for a single registered node.
|
||||
pub trait NodeArtifactsMaterializer: Send + Sync {
|
||||
/// Resolves one node from the current registration set.
|
||||
///
|
||||
/// Returning `Ok(None)` means the node is known but its artifacts are not
|
||||
/// ready yet.
|
||||
fn materialize(
|
||||
&self,
|
||||
registration: &NodeRegistration,
|
||||
@ -20,6 +24,13 @@ pub trait NodeArtifactsMaterializer: Send + Sync {
|
||||
/// Adapter contract for materializing a whole registration snapshot into
|
||||
/// per-node cfgsync artifacts.
|
||||
pub trait RegistrationSnapshotMaterializer: Send + Sync {
|
||||
/// Materializes the current registration set.
|
||||
///
|
||||
/// This is the main registration-driven integration point for cfgsync.
|
||||
/// Implementations decide:
|
||||
/// - when the current snapshot is ready to serve
|
||||
/// - which per-node artifacts should be produced
|
||||
/// - which shared artifacts should accompany every node
|
||||
fn materialize_snapshot(
|
||||
&self,
|
||||
registrations: &RegistrationSnapshot,
|
||||
@ -28,6 +39,7 @@ pub trait RegistrationSnapshotMaterializer: Send + Sync {
|
||||
|
||||
/// Optional hook for persisting or publishing materialized cfgsync artifacts.
|
||||
pub trait MaterializedArtifactsSink: Send + Sync {
|
||||
/// Persists or publishes a ready materialization result.
|
||||
fn persist(&self, artifacts: &MaterializedArtifacts) -> Result<(), DynCfgsyncError>;
|
||||
}
|
||||
|
||||
@ -40,11 +52,13 @@ pub enum MaterializationResult {
|
||||
}
|
||||
|
||||
impl MaterializationResult {
|
||||
/// Creates a ready materialization result.
|
||||
#[must_use]
|
||||
pub fn ready(nodes: MaterializedArtifacts) -> Self {
|
||||
Self::Ready(nodes)
|
||||
}
|
||||
|
||||
/// Returns the ready artifacts when materialization succeeded.
|
||||
#[must_use]
|
||||
pub fn artifacts(&self) -> Option<&MaterializedArtifacts> {
|
||||
match self {
|
||||
@ -66,6 +80,8 @@ struct CachedSnapshot {
|
||||
}
|
||||
|
||||
impl<M> CachedSnapshotMaterializer<M> {
|
||||
/// Wraps a snapshot materializer with deterministic snapshot-result
|
||||
/// caching.
|
||||
#[must_use]
|
||||
pub fn new(inner: M) -> Self {
|
||||
Self {
|
||||
@ -126,6 +142,8 @@ pub struct PersistingSnapshotMaterializer<M, S> {
|
||||
}
|
||||
|
||||
impl<M, S> PersistingSnapshotMaterializer<M, S> {
|
||||
/// Wraps a snapshot materializer with one-time persistence for each
|
||||
/// distinct registration snapshot.
|
||||
#[must_use]
|
||||
pub fn new(inner: M, sink: S) -> Self {
|
||||
Self {
|
||||
|
||||
@ -28,16 +28,19 @@ pub struct RegistrationPayload {
|
||||
}
|
||||
|
||||
impl RegistrationPayload {
|
||||
/// Creates an empty adapter-owned payload.
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Returns `true` when no adapter-owned payload was attached.
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.raw_json.is_none()
|
||||
}
|
||||
|
||||
/// Stores one typed adapter payload as opaque JSON.
|
||||
pub fn from_serializable<T>(value: &T) -> Result<Self, serde_json::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
@ -47,6 +50,7 @@ impl RegistrationPayload {
|
||||
})
|
||||
}
|
||||
|
||||
/// Stores a raw JSON payload after validating that it parses.
|
||||
pub fn from_json_str(raw_json: &str) -> Result<Self, serde_json::Error> {
|
||||
let value: Value = serde_json::from_str(raw_json)?;
|
||||
|
||||
@ -55,6 +59,7 @@ impl RegistrationPayload {
|
||||
})
|
||||
}
|
||||
|
||||
/// Deserializes the adapter-owned payload into the requested type.
|
||||
pub fn deserialize<T>(&self) -> Result<Option<T>, serde_json::Error>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
@ -65,6 +70,7 @@ impl RegistrationPayload {
|
||||
.transpose()
|
||||
}
|
||||
|
||||
/// Returns the validated JSON representation stored in this payload.
|
||||
#[must_use]
|
||||
pub fn raw_json(&self) -> Option<&str> {
|
||||
self.raw_json.as_deref()
|
||||
@ -111,6 +117,7 @@ pub struct NodeRegistration {
|
||||
}
|
||||
|
||||
impl NodeRegistration {
|
||||
/// Creates a registration with the generic node identity fields only.
|
||||
#[must_use]
|
||||
pub fn new(identifier: impl Into<String>, ip: Ipv4Addr) -> Self {
|
||||
Self {
|
||||
@ -120,6 +127,7 @@ impl NodeRegistration {
|
||||
}
|
||||
}
|
||||
|
||||
/// Attaches one typed adapter-owned payload to this registration.
|
||||
pub fn with_metadata<T>(mut self, metadata: &T) -> Result<Self, serde_json::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
@ -128,6 +136,7 @@ impl NodeRegistration {
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Attaches a prebuilt registration payload to this registration.
|
||||
#[must_use]
|
||||
pub fn with_payload(mut self, payload: RegistrationPayload) -> Self {
|
||||
self.metadata = payload;
|
||||
@ -136,6 +145,7 @@ impl NodeRegistration {
|
||||
}
|
||||
|
||||
impl NodeArtifactsPayload {
|
||||
/// Creates a payload from the files that should be written for one node.
|
||||
#[must_use]
|
||||
pub fn from_files(files: Vec<NodeArtifactFile>) -> Self {
|
||||
Self {
|
||||
@ -144,11 +154,13 @@ impl NodeArtifactsPayload {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the files carried by this payload.
|
||||
#[must_use]
|
||||
pub fn files(&self) -> &[NodeArtifactFile] {
|
||||
&self.files
|
||||
}
|
||||
|
||||
/// Returns `true` when the payload carries no files.
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.files.is_empty()
|
||||
@ -172,6 +184,7 @@ pub struct CfgsyncErrorResponse {
|
||||
}
|
||||
|
||||
impl CfgsyncErrorResponse {
|
||||
/// Builds a missing-config error for one identifier.
|
||||
#[must_use]
|
||||
pub fn missing_config(identifier: &str) -> Self {
|
||||
Self {
|
||||
@ -180,6 +193,7 @@ impl CfgsyncErrorResponse {
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a not-ready error for one identifier.
|
||||
#[must_use]
|
||||
pub fn not_ready(identifier: &str) -> Self {
|
||||
Self {
|
||||
@ -188,6 +202,7 @@ impl CfgsyncErrorResponse {
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds an internal cfgsync error.
|
||||
#[must_use]
|
||||
pub fn internal(message: impl Into<String>) -> Self {
|
||||
Self {
|
||||
|
||||
@ -17,9 +17,17 @@ use thiserror::Error;
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct CfgsyncServerConfig {
|
||||
pub port: u16,
|
||||
/// Source used by the runtime-managed cfgsync server.
|
||||
pub source: CfgsyncServerSource,
|
||||
}
|
||||
|
||||
/// Runtime cfgsync source loaded from config.
|
||||
///
|
||||
/// This type is intentionally runtime-oriented:
|
||||
/// - `Bundle` serves a static precomputed bundle directly
|
||||
/// - `RegistrationBundle` serves a precomputed bundle through the registration
|
||||
/// protocol, which is useful when the consumer wants clients to register
|
||||
/// before receiving already-materialized artifacts
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
|
||||
#[serde(tag = "kind", rename_all = "snake_case")]
|
||||
pub enum CfgsyncServerSource {
|
||||
@ -189,6 +197,13 @@ pub async fn serve_cfgsync_from_config(config_path: &Path) -> anyhow::Result<()>
|
||||
|
||||
/// Builds a registration-backed cfgsync router directly from a snapshot
|
||||
/// materializer.
|
||||
///
|
||||
/// This is the main code-driven entrypoint for apps that want cfgsync to own:
|
||||
/// - node registration
|
||||
/// - readiness polling
|
||||
/// - artifact serving
|
||||
///
|
||||
/// while the app owns only snapshot materialization logic.
|
||||
pub fn build_snapshot_cfgsync_router<M>(materializer: M) -> Router
|
||||
where
|
||||
M: RegistrationSnapshotMaterializer + 'static,
|
||||
@ -199,6 +214,9 @@ where
|
||||
|
||||
/// Builds a registration-backed cfgsync router with a persistence hook for
|
||||
/// ready materialization results.
|
||||
///
|
||||
/// Use this when the application wants cfgsync to persist or publish shared
|
||||
/// artifacts after a snapshot becomes ready.
|
||||
pub fn build_persisted_snapshot_cfgsync_router<M, S>(materializer: M, sink: S) -> Router
|
||||
where
|
||||
M: RegistrationSnapshotMaterializer + 'static,
|
||||
@ -213,6 +231,9 @@ where
|
||||
|
||||
/// Runs a registration-backed cfgsync server directly from a snapshot
|
||||
/// materializer.
|
||||
///
|
||||
/// This is the simplest runtime entrypoint when the application already has a
|
||||
/// materializer value and does not need to compose extra routes.
|
||||
pub async fn serve_snapshot_cfgsync<M>(port: u16, materializer: M) -> Result<(), RunCfgsyncError>
|
||||
where
|
||||
M: RegistrationSnapshotMaterializer + 'static,
|
||||
@ -223,6 +244,9 @@ where
|
||||
|
||||
/// Runs a registration-backed cfgsync server with a persistence hook for ready
|
||||
/// materialization results.
|
||||
///
|
||||
/// This is the direct serving counterpart to
|
||||
/// [`build_persisted_snapshot_cfgsync_router`].
|
||||
pub async fn serve_persisted_snapshot_cfgsync<M, S>(
|
||||
port: u16,
|
||||
materializer: M,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user