use prikk_error::{PrikkError, Result};
#[cfg(test)]
use prikk_object::BlockPayload;
use prikk_object::{BlobKind, BlobPayload, ObjectId, ObjectType};
#[cfg(test)]
use super::BlockParentResolver;
use super::{BlobContentResolver, BlobKindResolver};
use crate::object_store::ObjectReader;
pub(crate) struct StoreBackedResolver<'a, R: ObjectReader> {
reader: &'a R,
require_schema_one: bool,
}
impl<'a, R: ObjectReader> StoreBackedResolver<'a, R> {
pub(crate) fn new(reader: &'a R) -> Self {
Self {
reader,
require_schema_one: false,
}
}
pub(crate) fn new_format2(reader: &'a R) -> Self {
Self {
reader,
require_schema_one: true,
}
}
fn validate_blob_schema(&self, schema_version: u32) -> Result<()> {
if self.require_schema_one {
let accepted = crate::format::admitted_schemas(ObjectType::Blob).unwrap_or(&[]);
if !accepted.contains(&schema_version) {
return Err(PrikkError::Integrity(format!(
"format-2 Blob does not accept envelope schema {schema_version} (accepted: {accepted:?})"
)));
}
}
Ok(())
}
}
#[cfg(test)]
impl<R: ObjectReader> BlockParentResolver for StoreBackedResolver<'_, R> {
fn parent_block_ids(&self, block_id: &ObjectId) -> Result<Vec<ObjectId>> {
let Some(envelope) = self.reader.read_object(*block_id)? else {
return Err(PrikkError::Integrity(format!(
"lifecycle replay: block {block_id} is missing and cannot be treated as genesis"
)));
};
if envelope.object_type != ObjectType::Block {
return Err(PrikkError::Integrity(format!(
"lifecycle replay: object {block_id} is not a Block ({} found)",
envelope.object_type
)));
}
let block = BlockPayload::decode_canonical(&envelope.canonical_payload)?;
Ok(block.parent_block_ids)
}
}
impl<R: ObjectReader> BlobKindResolver for StoreBackedResolver<'_, R> {
fn blob_kind(&self, blob_id: &ObjectId) -> Result<Option<BlobKind>> {
let Some(envelope) = self.reader.read_object(*blob_id)? else {
return Ok(None);
};
if envelope.object_type != ObjectType::Blob {
return Err(PrikkError::Integrity(format!(
"lifecycle replay: object {blob_id} is not a Blob ({} found)",
envelope.object_type
)));
}
self.validate_blob_schema(envelope.schema_version)?;
let blob = BlobPayload::decode_canonical(&envelope.canonical_payload)?;
Ok(Some(blob.blob_kind))
}
}
impl<R: ObjectReader> BlobContentResolver for StoreBackedResolver<'_, R> {
fn blob_content(&self, blob_id: &ObjectId) -> Result<Option<(BlobKind, Vec<u8>)>> {
let Some(envelope) = self.reader.read_object(*blob_id)? else {
return Ok(None);
};
if envelope.object_type != ObjectType::Blob {
return Err(PrikkError::Integrity(format!(
"lifecycle replay: object {blob_id} is not a Blob ({} found)",
envelope.object_type
)));
}
self.validate_blob_schema(envelope.schema_version)?;
let blob = BlobPayload::decode_canonical(&envelope.canonical_payload)?;
Ok(Some((blob.blob_kind, blob.content)))
}
}
#[cfg(test)]
mod tests;