use std::path::Path;
use lean_ctx_protocol::{
EngineContextSourceMaterializationRequestV2, EngineContextSourceMaterializationResponseV2,
EnginePresenterGrantV1, EnginePresenterRequestV1, ProtocolReference,
};
use crate::core::archive::presented::{self, PresenterCapability};
pub const CAPABILITY_REFUSED: &str = "presenter_capability_refused";
pub fn materialize_v2(
root: &Path,
request: &EngineContextSourceMaterializationRequestV2,
shown: Option<PresenterCapability>,
) -> Result<EngineContextSourceMaterializationResponseV2, &'static str> {
request
.validate_payload()
.map_err(|_| "invalid_source_materialization_request")?;
let (capability, expires_at, fresh) = match (request.presenter, shown) {
(EnginePresenterRequestV1::Issue { ttl_seconds }, None) => {
let issued = presented::issue(ttl_seconds).ok_or(CAPABILITY_REFUSED)?;
(issued.capability, issued.expires_at, true)
}
(EnginePresenterRequestV1::Renew, Some(capability)) => {
let expires_at =
presented::issued_lifetime_end(&capability).ok_or(CAPABILITY_REFUSED)?;
(capability, expires_at, false)
}
_ => return Err(CAPABILITY_REFUSED),
};
let response = presented::with_presenter(Some(capability.clone()), || {
super::materialize(root, &request.materialization)
})
.and_then(|materialization| {
let response = EngineContextSourceMaterializationResponseV2 {
schema_version: 2,
materialization,
presenter: EnginePresenterGrantV1 {
presenter_ref: ProtocolReference::new(capability.reference())
.map_err(|_| "internal")?,
expires_at_unix: u64::try_from(expires_at).map_err(|_| "internal")?,
capability: fresh.then(|| String::clone(&capability.expose())),
},
};
response
.validate()
.map_err(|_| "source_materialization_invalid")?;
Ok(response)
});
if response.is_err() && fresh {
presented::revoke(&capability);
}
response
}