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