use actr_pack::PackageManifest;
use actr_protocol::ServiceSpec;
use actr_service_compat::{ProtoFile, ServiceSpecInput, build_service_spec};
use std::io::Read;
use crate::error::{HyperError, HyperResult};
pub(crate) fn calculate_service_spec_from_package(
package_bytes: &[u8],
manifest: &PackageManifest,
) -> HyperResult<Option<ServiceSpec>> {
if manifest.proto_files.is_empty() {
return Ok(None);
}
let mut archive = zip::ZipArchive::new(std::io::Cursor::new(package_bytes))
.map_err(|e| HyperError::Runtime(format!("open package ZIP: {e}")))?;
let mut proto_files = Vec::with_capacity(manifest.proto_files.len());
for proto_entry in &manifest.proto_files {
let mut file = archive.by_name(&proto_entry.path).map_err(|e| {
HyperError::Runtime(format!(
"proto file {} not found in package: {e}",
proto_entry.path
))
})?;
let mut content = String::new();
file.read_to_string(&mut content)
.map_err(|e| HyperError::Runtime(format!("read proto {}: {e}", proto_entry.path)))?;
proto_files.push(ProtoFile {
name: proto_entry.name.clone(),
content,
path: None,
});
}
let spec = build_service_spec(ServiceSpecInput {
name: &manifest.name,
description: manifest.metadata.description.clone(),
tags: vec![],
proto_files,
})
.map_err(|e| HyperError::Runtime(format!("build service spec: {e}")))?;
Ok(Some(spec))
}