Skip to main content

boatramp_core/
lib.rs

1//! Core domain types for boatramp.
2//!
3//! - [`Storage`] — the streaming-first blob backend trait (filesystem, S3, ...).
4//!   No method buffers a whole object in memory.
5//! - [`kv`] — a tiny pluggable [`kv::KvStore`] for small deploy metadata, with
6//!   an LRU [`kv::CachedKv`] wrapper.
7//! - [`deploy`] — content-addressed, atomically-activated deployments built on
8//!   top of a [`Storage`] (blobs) plus a [`kv::KvStore`] (manifests + pointers).
9//! - [`config`] — deploy-scoped configuration (the `routing` section of
10//!   `project.cfg`), folded into the manifest; [`matcher`] — the shared
11//!   path-pattern engine it relies on.
12
13use bytes::Bytes;
14use futures::stream::BoxStream;
15
16pub mod blob_provision;
17pub mod cache_coherence;
18#[cfg(feature = "authz")]
19pub mod cedar;
20pub mod cert;
21pub mod compat;
22#[cfg(feature = "authz")]
23pub mod cose;
24pub mod envelope;
25// `compute` extends the wasm-clean `boatramp_types::compute` (re-exported within)
26// with the native control-plane layer: the `ComputeBackend` trait, the scheduler,
27// and the reconcile logic.
28pub mod compute;
29pub mod deploy;
30pub mod error;
31/// Per-node guest-IP pool shared by the VMM (tap) + container (veth) backends.
32pub mod ipam;
33/// Posture-scaled kernel-trust verification (needs the `authz` signing primitives).
34#[cfg(feature = "authz")]
35pub mod kernel_trust;
36pub mod kv;
37pub mod messaging;
38/// Online, resumable migration of a pre-0.2.0 store to the project-scoped layout.
39pub mod migrate;
40pub mod mode;
41pub mod project;
42pub mod sql;
43/// The one canonical wall-clock read for native crates (`now_unix`/`now_unix_ms`).
44pub mod time;
45
46// The shared wasm-clean layer lives in `boatramp-types`; re-export it so the
47// `boatramp_core::config`/`::route`/`::matcher`/`::domain_verify`/… paths are
48// unchanged. (`compute` is its own module above — it re-exports the types layer.)
49pub use boatramp_types::{
50    access, authz, blob_notify, config, cron, daemon_config, dns_managed, domain_verify, function,
51    gateway, geo, host, logs, matcher, predicate, route, security, site, waf, workflow,
52};
53pub use boatramp_types::{schema_version, SCHEMA_VERSION};
54
55pub use error::{ConfigError, DeployError, KvError, StorageError};
56pub use mode::DeploymentMode;
57
58/// A streaming, owned sequence of byte chunks.
59///
60/// Each chunk is yielded as it becomes available; the full payload is never
61/// collected in memory.
62pub type ByteStream = BoxStream<'static, Result<Bytes, StorageError>>;
63
64/// Metadata describing a stored object.
65#[derive(Debug, Clone, Default, PartialEq, Eq)]
66pub struct ObjectMeta {
67    /// Storage key (path) of the object.
68    pub key: String,
69    /// Size in bytes, when known ahead of streaming.
70    pub size: Option<u64>,
71    /// MIME content type, when known.
72    pub content_type: Option<String>,
73    /// Backend-specific entity tag, when available.
74    pub etag: Option<String>,
75}
76
77/// Metadata supplied when writing an object.
78#[derive(Debug, Clone, Default)]
79pub struct PutMeta {
80    /// MIME content type to record for the object.
81    pub content_type: Option<String>,
82}
83
84/// The result of a streaming read: object metadata plus its byte stream.
85pub struct GetObject {
86    /// Metadata for the object being read.
87    pub meta: ObjectMeta,
88    /// The object's body, streamed chunk by chunk.
89    pub body: ByteStream,
90}
91
92/// How an object under a watched prefix changed (FA-5 blob-change triggers).
93#[derive(Debug, Clone, Copy, PartialEq, Eq)]
94pub enum BlobChangeKind {
95    /// An object was created.
96    Created,
97    /// An existing object's bytes changed.
98    Modified,
99    /// An object was removed.
100    Removed,
101}
102
103/// A single change event under a watched prefix — a backend-native notification
104/// ([`Storage::watch`]), never boatramp's own write path (so the semantics are the
105/// same whoever wrote it).
106#[derive(Debug, Clone, PartialEq, Eq)]
107pub struct BlobChange {
108    /// The full storage key that changed.
109    pub key: String,
110    /// What happened to it.
111    pub kind: BlobChangeKind,
112}
113
114/// A stream of change events under a watched prefix, live until dropped.
115pub type ChangeStream = BoxStream<'static, BlobChange>;
116
117/// A pluggable, streaming object-storage backend.
118///
119/// Implementations MUST stream data without buffering whole objects in memory.
120#[async_trait::async_trait]
121pub trait Storage: Send + Sync {
122    /// Open an object for streaming reads.
123    async fn get(&self, key: &str) -> Result<GetObject, StorageError>;
124
125    /// Open a byte range for streaming reads (for HTTP `Range`). `len == None`
126    /// means "from `offset` to the end".
127    async fn get_range(
128        &self,
129        key: &str,
130        offset: u64,
131        len: Option<u64>,
132    ) -> Result<GetObject, StorageError>;
133
134    /// Stream `body` into the backend at `key`, returning the stored metadata.
135    async fn put(
136        &self,
137        key: &str,
138        body: ByteStream,
139        meta: PutMeta,
140    ) -> Result<ObjectMeta, StorageError>;
141
142    /// Fetch object metadata without reading its body.
143    async fn head(&self, key: &str) -> Result<ObjectMeta, StorageError>;
144
145    /// Delete an object. Deleting a missing object is not an error.
146    async fn delete(&self, key: &str) -> Result<(), StorageError>;
147
148    /// List object metadata under `prefix`.
149    async fn list(&self, prefix: &str) -> Result<Vec<ObjectMeta>, StorageError>;
150
151    /// Whether this backend can natively watch for changes (FA-5 blob-change
152    /// triggers). A cheap, side-effect-free capability probe: a `Blob` trigger is
153    /// **refused at activation** on a backend that returns `false`, so the
154    /// semantics never silently degrade. Defaults to `false`.
155    fn supports_watch(&self) -> bool {
156        false
157    }
158
159    /// Watch for changes under `prefix`, returning a live stream of
160    /// [`BlobChange`]s until dropped (backend-native notification — inotify /
161    /// FSEvents locally, SQS / Pub/Sub / Event Grid for cloud stores). `Ok(None)`
162    /// means this backend does not support watching (the default), matching
163    /// [`supports_watch`](Self::supports_watch).
164    async fn watch(&self, _prefix: &str) -> Result<Option<ChangeStream>, StorageError> {
165        Ok(None)
166    }
167}