holger-estate-front/src/sealed.rs
//! **The primary's sealed slot** (feature `metered`): where holger's front keeps what
//! only the estate may hold — its installer material, taken from the ONE monetize
//! (`SoldEstate.TakeMaterial`) — on holger's PRIMARY, over holger's own
//! `RepositoryService` (the client generated from holger's proto, [`crate::certify::proto`]).
//!
//! ONE raw repository on the primary, [`SEALED_REPOSITORY`], that the kit declares with
//! `ron_require_auth: true` and `ron_require_role: Some(Admin)`: every other repository of
//! the estate reads open, this one answers an ADMIN only (the console's bearer). The twin
//! follows it like every other, so a main laid again gets it back from its twin.
//!
//! The credential is the fed console bearer (`holger_console_token`, Admin). The primary is
//! the one the verdict names NOW: a main laid again is found at its new address.
use std::time::Duration;
use nordisk_pairing::join::JoinReply;
use crate::certify::proto;
use proto::repository_service_client::RepositoryServiceClient;
/// **The gated repository the kit declares** (private-holger-ops `install::BACKUP_REPOSITORY`,
/// the same word; the name predates G16, when the front's own monetize backed up there).
pub const SEALED_REPOSITORY: &str = "monetize-backup";
/// The material's name in it.
pub const MATERIAL_OBJECT: &str = "installer-material.json";
const MAX_MESSAGE: usize = 64 << 20;
/// holger's primary as the sealed slot. Blocking: call it from a thread that is not a
/// runtime worker (a jera job, `spawn_blocking`).
pub struct PrimarySlot {
pub handle: tokio::runtime::Handle,
/// `<utility>:50051`.
pub control: String,
pub bearer: String,
pub repository: String,
pub timeout: Duration,
}
/// Pure: **the slot the fed reply names** — the elected primary's control plane and the
/// console's bearer; `None` until both are fed.
pub fn slot_of(reply: &JoinReply, handle: &tokio::runtime::Handle) -> Option<PrimarySlot> {
let control = crate::primary_control(reply)?;
let bearer = crate::console_key::bearers(reply)
.ok()
.flatten()?
.at(&control)?
.to_string();
Some(PrimarySlot {
handle: handle.clone(),
control,
bearer,
repository: SEALED_REPOSITORY.into(),
timeout: Duration::from_secs(60),
})
}
/// Pure: **does a `NotFound` say the REPOSITORY is unknown** (holger's frozen code
/// `holger-server-1`, "no such repository"), not the object?
pub fn repository_unknown(message: &str) -> bool {
message.contains("[holger-server-1]")
}
fn said(s: tonic::Status) -> String {
format!("{:?}: {}", s.code(), s.message())
}
/// Pure: the raw repository's id of an object (the path is the name).
pub fn id_of(name: &str) -> proto::ArtifactId {
proto::ArtifactId {
namespace: String::new(),
name: name.to_string(),
version: String::new(),
}
}
impl PrimarySlot {
fn req<T>(&self, body: T) -> Result<tonic::Request<T>, String> {
let mut r = tonic::Request::new(body);
r.set_timeout(self.timeout);
r.metadata_mut().insert(
"authorization",
format!("Bearer {}", self.bearer)
.parse()
.map_err(|_| "the bearer is not a header value".to_string())?,
);
Ok(r)
}
async fn client(&self) -> Result<RepositoryServiceClient<tonic::transport::Channel>, String> {
// The installer material goes to the primary over wg0 only on an estate (lane E1).
crate::wg_only::check("the primary's sealed slot", &self.control)?;
let ep = tonic::transport::Endpoint::from_shared(format!("http://{}", self.control))
.map_err(|e| format!("{}: {e}", self.control))?
.connect_timeout(self.timeout);
Ok(RepositoryServiceClient::new(
ep.connect()
.await
.map_err(|e| format!("{}: {e}", self.control))?,
)
.max_decoding_message_size(MAX_MESSAGE)
.max_encoding_message_size(MAX_MESSAGE))
}
pub fn describe(&self) -> String {
format!(
"holger's primary {} repository {}",
self.control, self.repository
)
}
/// The object, or `None` when it was never kept. A primary that declares no such
/// repository is an `Err` by name, never "not kept" (lane F9: test3-holger-rs's media
/// declared no `monetize-backup`, so the front read "never kept" for ever and could store
/// nothing).
pub fn get(&self, name: &str) -> Result<Option<Vec<u8>>, String> {
self.handle.block_on(async {
match self
.client()
.await?
.fetch_artifact(self.req(proto::FetchArtifactRequest {
repository: self.repository.clone(),
id: Some(id_of(name)),
})?)
.await
{
Ok(r) => Ok(Some(r.into_inner().data)),
Err(s) if s.code() == tonic::Code::NotFound && repository_unknown(s.message()) => {
Err(format!(
"[sealed-slot-undeclared] {} declares no repository {}: {}",
self.control,
self.repository,
s.message()
))
}
Err(s) if s.code() == tonic::Code::NotFound => Ok(None),
Err(s) => Err(said(s)),
}
})
}
pub fn put(&self, name: &str, bytes: &[u8]) -> Result<(), String> {
self.handle.block_on(async {
let r = self
.client()
.await?
.put_artifact(self.req(proto::PutArtifactRequest {
repository: self.repository.clone(),
id: Some(id_of(name)),
data: bytes.to_vec(),
async_job: false,
})?)
.await
.map_err(said)?
.into_inner();
if r.success {
Ok(())
} else {
Err(format!(
"PutArtifact answered success = false: {}",
r.message
))
}
})
}
}
#[cfg(test)]
mod tests {
use super::*;
/// F9: a primary without the sealed repository is named, never read as "never kept".
#[test]
fn an_undeclared_sealed_repository_is_told_apart_from_a_missing_object() {
assert!(repository_unknown(
"[holger-server-1] Repository 'monetize-backup' not found"
));
assert!(!repository_unknown(
"[holger-server-2] Artifact 'installer-material.json' not found"
));
}
#[test]
fn the_material_is_a_raw_path_with_no_namespace_or_version() {
let id = id_of(MATERIAL_OBJECT);
assert!(id.namespace.is_empty() && id.version.is_empty());
assert_eq!(id.name, "installer-material.json");
}
}