mithril_client/cardano_database_client/download_unpack/
download_unpack_options.rs1use std::ops::RangeInclusive;
2use std::path::Path;
3
4use anyhow::anyhow;
5
6use mithril_cardano_node_internal_database::{IMMUTABLE_DIR, LEDGER_DIR, VOLATILE_DIR};
7
8use crate::common::ImmutableFileNumber;
9use crate::MithrilResult;
10
11#[derive(Debug, Copy, Clone)]
13pub struct DownloadUnpackOptions {
14 pub allow_override: bool,
16
17 pub include_ancillary: bool,
19
20 pub max_parallel_downloads: usize,
22}
23
24impl Default for DownloadUnpackOptions {
25 fn default() -> Self {
26 Self {
27 allow_override: false,
28 include_ancillary: false,
29 max_parallel_downloads: 20,
30 }
31 }
32}
33
34impl DownloadUnpackOptions {
35 pub fn verify_compatibility(
37 &self,
38 immutable_file_range: &RangeInclusive<ImmutableFileNumber>,
39 last_immutable_file_number: ImmutableFileNumber,
40 ) -> MithrilResult<()> {
41 if self.include_ancillary && !immutable_file_range.contains(&last_immutable_file_number) {
42 return Err(anyhow!(
43 "The last immutable file number {last_immutable_file_number} is outside the range: {immutable_file_range:?}"
44 ));
45 }
46
47 Ok(())
48 }
49
50 pub fn verify_can_write_to_target_directory(&self, target_dir: &Path) -> MithrilResult<()> {
52 fn subdir_should_not_exist(
53 parent: &Path,
54 name_in_error: &str,
55 subdir: &str,
56 ) -> MithrilResult<()> {
57 if parent.join(subdir).exists() {
58 anyhow::bail!("{name_in_error} target directory already exists in: {parent:?}")
59 }
60 Ok(())
61 }
62
63 if !self.allow_override {
64 subdir_should_not_exist(target_dir, "Immutable files", IMMUTABLE_DIR)?;
65 if self.include_ancillary {
66 subdir_should_not_exist(target_dir, "Volatile", VOLATILE_DIR)?;
67 subdir_should_not_exist(target_dir, "Ledger", LEDGER_DIR)?;
68 }
69 }
70
71 Ok(())
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use crate::cardano_database_client::ImmutableFileRange;
78
79 use super::*;
80
81 mod verify_compatibility {
82 use super::*;
83
84 #[test]
85 fn succeeds_if_without_ancillary_download() {
86 let download_options = DownloadUnpackOptions {
87 include_ancillary: false,
88 ..DownloadUnpackOptions::default()
89 };
90 let immutable_file_range = ImmutableFileRange::Range(1, 10);
91 let last_immutable_file_number = 10;
92
93 download_options
94 .verify_compatibility(
95 &immutable_file_range
96 .to_range_inclusive(last_immutable_file_number)
97 .unwrap(),
98 last_immutable_file_number,
99 )
100 .unwrap();
101 }
102
103 #[test]
104 fn succeeds_if_with_ancillary_download_and_compatible_range() {
105 let download_options = DownloadUnpackOptions {
106 include_ancillary: true,
107 ..DownloadUnpackOptions::default()
108 };
109 let immutable_file_range = ImmutableFileRange::Range(7, 10);
110 let last_immutable_file_number = 10;
111
112 download_options
113 .verify_compatibility(
114 &immutable_file_range
115 .to_range_inclusive(last_immutable_file_number)
116 .unwrap(),
117 last_immutable_file_number,
118 )
119 .unwrap();
120 }
121
122 #[test]
123 fn fails_if_with_ancillary_download_and_incompatible_range() {
124 let download_options = DownloadUnpackOptions {
125 include_ancillary: true,
126 ..DownloadUnpackOptions::default()
127 };
128 let immutable_file_range = ImmutableFileRange::Range(7, 10);
129 let last_immutable_file_number = 123;
130
131 download_options
132 .verify_compatibility(
133 &immutable_file_range
134 .to_range_inclusive(last_immutable_file_number)
135 .unwrap(),
136 last_immutable_file_number,
137 )
138 .expect_err("verify_download_options_compatibility should fail as the last immutable file number is outside the range");
139 }
140 }
141
142 mod verify_can_write_to_target_directory {
143 use std::fs;
144
145 use mithril_common::temp_dir_create;
146
147 use super::*;
148
149 #[test]
150 fn always_succeeds_with_allow_overwrite() {
151 let target_dir = temp_dir_create!();
152
153 let download_options = DownloadUnpackOptions {
154 allow_override: true,
155 include_ancillary: false,
156 ..DownloadUnpackOptions::default()
157 };
158
159 download_options
160 .verify_can_write_to_target_directory(&target_dir)
161 .unwrap();
162
163 fs::create_dir_all(target_dir.join(IMMUTABLE_DIR)).unwrap();
164 fs::create_dir_all(target_dir.join(VOLATILE_DIR)).unwrap();
165 fs::create_dir_all(target_dir.join(LEDGER_DIR)).unwrap();
166 download_options
167 .verify_can_write_to_target_directory(&target_dir)
168 .unwrap();
169
170 DownloadUnpackOptions {
171 allow_override: true,
172 include_ancillary: true,
173 ..DownloadUnpackOptions::default()
174 }
175 .verify_can_write_to_target_directory(&target_dir)
176 .unwrap();
177 }
178
179 #[test]
180 fn fails_without_allow_overwrite_and_non_empty_immutable_target_dir() {
181 let target_dir = temp_dir_create!();
182 fs::create_dir_all(target_dir.join(IMMUTABLE_DIR)).unwrap();
183
184 DownloadUnpackOptions {
185 allow_override: false,
186 include_ancillary: false,
187 ..DownloadUnpackOptions::default()
188 }
189 .verify_can_write_to_target_directory(&target_dir)
190 .expect_err("verify_can_write_to_target_directory should fail");
191
192 DownloadUnpackOptions {
193 allow_override: false,
194 include_ancillary: true,
195 ..DownloadUnpackOptions::default()
196 }
197 .verify_can_write_to_target_directory(&target_dir)
198 .expect_err("verify_can_write_to_target_directory should fail");
199 }
200
201 #[test]
202 fn fails_without_allow_overwrite_and_non_empty_ledger_target_dir() {
203 let target_dir = temp_dir_create!();
204 fs::create_dir_all(target_dir.join(LEDGER_DIR)).unwrap();
205
206 DownloadUnpackOptions {
207 allow_override: false,
208 include_ancillary: true,
209 ..DownloadUnpackOptions::default()
210 }
211 .verify_can_write_to_target_directory(&target_dir)
212 .expect_err("verify_can_write_to_target_directory should fail");
213
214 DownloadUnpackOptions {
215 allow_override: false,
216 include_ancillary: false,
217 ..DownloadUnpackOptions::default()
218 }
219 .verify_can_write_to_target_directory(&target_dir)
220 .unwrap();
221 }
222
223 #[test]
224 fn fails_without_allow_overwrite_and_non_empty_volatile_target_dir() {
225 let target_dir = temp_dir_create!();
226 fs::create_dir_all(target_dir.join(VOLATILE_DIR)).unwrap();
227
228 DownloadUnpackOptions {
229 allow_override: false,
230 include_ancillary: true,
231 ..DownloadUnpackOptions::default()
232 }
233 .verify_can_write_to_target_directory(&target_dir)
234 .expect_err("verify_can_write_to_target_directory should fail");
235
236 DownloadUnpackOptions {
237 allow_override: false,
238 include_ancillary: false,
239 ..DownloadUnpackOptions::default()
240 }
241 .verify_can_write_to_target_directory(&target_dir)
242 .unwrap();
243 }
244 }
245}