use aion_package::{ContractIdentityError, ExtractionLimits, Package};
use aion_store::PackageRecord;
use super::projection;
use super::types::{DeployedDocument, DeployedError, DeployedSchema};
use super::DeployedSignal;
pub(super) fn read_document(
archives: &[PackageRecord],
workflow_type: &str,
content_hash: &str,
) -> Result<DeployedDocument, DeployedError> {
let not_found = || DeployedError::NotFound {
workflow_type: workflow_type.to_owned(),
content_hash: content_hash.to_owned(),
};
let record = archives
.iter()
.find(|record| record.content_hash == content_hash)
.ok_or_else(not_found)?;
let package = Package::load_from_bytes(&record.archive, ExtractionLimits::unbounded())
.map_err(|error| DeployedError::Unreadable {
workflow_type: workflow_type.to_owned(),
content_hash: content_hash.to_owned(),
reason: error.to_string(),
})?;
if !declares_workflow_type(&package, workflow_type) {
return Err(not_found());
}
let awl = package
.awl()
.ok_or_else(|| DeployedError::NoArchivedSource {
workflow_type: workflow_type.to_owned(),
content_hash: content_hash.to_owned(),
})?;
let projection = projection::project(awl.document(), awl.schemas())?;
let (input_schema, signals) = contract_surface(&package, workflow_type);
Ok(DeployedDocument {
workflow_type: workflow_type.to_owned(),
content_hash: content_hash.to_owned(),
document_name: awl.document_name().to_owned(),
source: awl.document().to_owned(),
schemas: awl
.schemas()
.iter()
.map(|(path, bytes)| DeployedSchema {
path: path.clone(),
text: String::from_utf8(bytes.clone()).ok(),
byte_length: bytes.len(),
})
.collect(),
input_schema,
signals,
projection,
})
}
fn contract_surface(
package: &Package,
workflow_type: &str,
) -> (Option<serde_json::Value>, Option<Vec<DeployedSignal>>) {
let contract = match package.contract() {
Ok(contract) => contract,
Err(ContractIdentityError::RedeployRequired { .. }) => return (None, None),
};
if package.manifest().entry_module == workflow_type {
let signals = contract
.signals
.iter()
.map(|signal| DeployedSignal {
name: signal.name.clone(),
input_schema: signal.input_schema.clone(),
})
.collect();
return (Some(contract.input_schema.clone()), Some(signals));
}
let input_schema = contract
.additional_workflows
.iter()
.find(|entry| entry.workflow_type == workflow_type)
.map(|entry| entry.input_schema.clone());
(input_schema, None)
}
pub(super) fn declares_workflow_type(package: &Package, workflow_type: &str) -> bool {
package.manifest().entry_module == workflow_type
|| package
.manifest()
.additional_workflows
.iter()
.any(|entry| entry.workflow_type == workflow_type)
}