1use daml_grpc::data::package::DamlPackage;
2use daml_grpc::data::{DamlError, DamlResult};
3use daml_grpc::DamlGrpcClient;
4use daml_lf::{DamlLfArchive, DamlLfArchivePayload, DamlLfHashFunction, DarFile, DarManifest};
5use futures::stream::FuturesUnordered;
6use futures::StreamExt;
7use uuid::Uuid;
8
9#[derive(Debug)]
28pub struct DamlPackages {
29 packages: Vec<DamlPackage>,
30}
31
32impl DamlPackages {
33 pub fn new(packages: Vec<DamlPackage>) -> Self {
34 Self {
35 packages,
36 }
37 }
38
39 pub async fn from_ledger(ledger_client: &DamlGrpcClient) -> DamlResult<Self> {
41 let packages = ledger_client.package_service().list_packages().await?;
42 let handles = packages
43 .iter()
44 .map(|pd| async move { ledger_client.package_service().get_package(pd).await })
45 .collect::<FuturesUnordered<_>>();
46 let all_packages =
47 handles.collect::<Vec<DamlResult<_>>>().await.into_iter().collect::<DamlResult<Vec<DamlPackage>>>()?;
48 Ok(Self::new(all_packages))
49 }
50
51 pub async fn find_module(self, module_name: &str) -> DamlResult<String> {
55 self.into_payloads()?
56 .iter()
57 .find(|(_, payload)| payload.contains_module(module_name))
58 .map_or_else(|| Err("package could not be found".into()), |(package_id, _)| Ok((*package_id).to_string()))
59 }
60
61 pub fn into_dar(self, auto_naming_style: ArchiveAutoNamingStyle) -> DamlResult<DarFile> {
68 let all_archives = self.into_archives(auto_naming_style)?;
69 Self::archives_to_dar(all_archives)
70 }
71
72 pub fn into_archives(self, auto_naming_style: ArchiveAutoNamingStyle) -> DamlResult<Vec<DamlLfArchive>> {
76 self.packages
77 .into_iter()
78 .map(|p| {
79 let hash = p.hash().to_owned();
80 let payload = Self::package_into_payload(p)?;
81 let name = match auto_naming_style {
82 ArchiveAutoNamingStyle::Empty => String::default(),
83 ArchiveAutoNamingStyle::Hash => hash.clone(),
84 ArchiveAutoNamingStyle::Uuid => Uuid::new_v4().to_string(),
85 };
86 Ok(DamlLfArchive::new(name, payload, DamlLfHashFunction::Sha256, hash))
87 })
88 .collect()
89 }
90
91 pub fn into_payloads(self) -> DamlResult<Vec<(String, DamlLfArchivePayload)>> {
93 self.packages
94 .into_iter()
95 .map(|p| {
96 let hash = p.hash().to_owned();
97 Self::package_into_payload(p).map(|pl| (hash, pl))
98 })
99 .collect::<DamlResult<Vec<_>>>()
100 }
101
102 fn package_into_payload(package: DamlPackage) -> DamlResult<DamlLfArchivePayload> {
103 DamlLfArchivePayload::from_bytes(package.take_payload()).map_err(|e| DamlError::Other(e.to_string()))
104 }
105
106 fn archives_to_dar(mut all_packages: Vec<DamlLfArchive>) -> DamlResult<DarFile> {
107 if all_packages.is_empty() {
108 Err("expected at least one archive".into())
109 } else {
110 let (first, rest) = all_packages.try_swap_remove(0).map(|removed| (removed, all_packages)).unwrap();
111 let manifest = DarManifest::new_implied(first.name.clone(), rest.iter().map(|n| n.name.clone()).collect());
112 Ok(DarFile::new(manifest, first, rest))
113 }
114 }
115}
116
117#[derive(Clone, Copy, Debug)]
119pub enum ArchiveAutoNamingStyle {
120 Empty,
122 Hash,
124 Uuid,
126}
127
128pub async fn find_module_package_id(ledger_client: &DamlGrpcClient, module_name: &str) -> DamlResult<String> {
132 DamlPackages::from_ledger(ledger_client).await?.find_module(module_name).await
133}
134
135trait TrySwapRemove<T>: Sized {
136 fn try_swap_remove(&mut self, index: usize) -> Option<T>;
137}
138
139impl<T> TrySwapRemove<T> for Vec<T> {
140 fn try_swap_remove(&mut self, index: usize) -> Option<T> {
141 (index < self.len()).then(|| self.swap_remove(index))
142 }
143}