1use std::{
2 collections::HashMap,
3 path::{Path, PathBuf},
4 process::ExitStatus,
5};
6
7use configuration::{shared::resources::Resources, types::AssetLocation};
8use serde::{Deserialize, Serialize};
9
10pub type Port = u16;
11
12pub type ExecutionResult = Result<String, (ExitStatus, String)>;
13
14#[derive(Debug, Clone, PartialEq)]
15pub struct ProviderCapabilities {
16 pub requires_image: bool,
19 pub has_resources: bool,
21 pub prefix_with_full_path: bool,
23 pub use_default_ports_in_cmd: bool,
26}
27
28#[derive(Debug, Clone)]
29pub struct SpawnNodeOptions {
30 pub name: String,
32 pub image: Option<String>,
34 pub resources: Option<Resources>,
36 pub program: String,
38 pub args: Vec<String>,
40 pub env: Vec<(String, String)>,
42 pub injected_files: Vec<TransferedFile>,
45 pub created_paths: Vec<PathBuf>,
49 pub db_snapshot: Option<AssetLocation>,
52 pub port_mapping: Option<HashMap<Port, Port>>,
53 pub node_log_path: Option<PathBuf>,
55}
56
57impl SpawnNodeOptions {
58 pub fn new<S>(name: S, program: S) -> Self
59 where
60 S: AsRef<str>,
61 {
62 Self {
63 name: name.as_ref().to_string(),
64 image: None,
65 resources: None,
66 program: program.as_ref().to_string(),
67 args: vec![],
68 env: vec![],
69 injected_files: vec![],
70 created_paths: vec![],
71 db_snapshot: None,
72 port_mapping: None,
73 node_log_path: None,
74 }
75 }
76
77 pub fn image<S>(mut self, image: S) -> Self
78 where
79 S: AsRef<str>,
80 {
81 self.image = Some(image.as_ref().to_string());
82 self
83 }
84
85 pub fn resources(mut self, resources: Resources) -> Self {
86 self.resources = Some(resources);
87 self
88 }
89
90 pub fn db_snapshot(mut self, db_snap: Option<AssetLocation>) -> Self {
91 self.db_snapshot = db_snap;
92 self
93 }
94
95 pub fn args<S, I>(mut self, args: I) -> Self
96 where
97 S: AsRef<str>,
98 I: IntoIterator<Item = S>,
99 {
100 self.args = args.into_iter().map(|s| s.as_ref().to_string()).collect();
101 self
102 }
103
104 pub fn env<S, I>(mut self, env: I) -> Self
105 where
106 S: AsRef<str>,
107 I: IntoIterator<Item = (S, S)>,
108 {
109 self.env = env
110 .into_iter()
111 .map(|(name, value)| (name.as_ref().to_string(), value.as_ref().to_string()))
112 .collect();
113 self
114 }
115
116 pub fn injected_files<I>(mut self, injected_files: I) -> Self
117 where
118 I: IntoIterator<Item = TransferedFile>,
119 {
120 self.injected_files = injected_files.into_iter().collect();
121 self
122 }
123
124 pub fn created_paths<P, I>(mut self, created_paths: I) -> Self
125 where
126 P: AsRef<Path>,
127 I: IntoIterator<Item = P>,
128 {
129 self.created_paths = created_paths
130 .into_iter()
131 .map(|path| path.as_ref().into())
132 .collect();
133 self
134 }
135
136 pub fn port_mapping(mut self, ports: HashMap<Port, Port>) -> Self {
137 self.port_mapping = Some(ports);
138 self
139 }
140
141 pub fn node_log_path(mut self, path: Option<PathBuf>) -> Self {
142 self.node_log_path = path;
143 self
144 }
145}
146
147#[derive(Debug)]
148pub struct GenerateFileCommand {
149 pub program: String,
150 pub args: Vec<String>,
151 pub env: Vec<(String, String)>,
152 pub local_output_path: PathBuf,
153}
154
155impl GenerateFileCommand {
156 pub fn new<S, P>(program: S, local_output_path: P) -> Self
157 where
158 S: AsRef<str>,
159 P: AsRef<Path>,
160 {
161 Self {
162 program: program.as_ref().to_string(),
163 args: vec![],
164 env: vec![],
165 local_output_path: local_output_path.as_ref().into(),
166 }
167 }
168
169 pub fn args<S, I>(mut self, args: I) -> Self
170 where
171 S: AsRef<str>,
172 I: IntoIterator<Item = S>,
173 {
174 self.args = args.into_iter().map(|s| s.as_ref().to_string()).collect();
175 self
176 }
177
178 pub fn env<S, I>(mut self, env: I) -> Self
179 where
180 S: AsRef<str>,
181 I: IntoIterator<Item = (S, S)>,
182 {
183 self.env = env
184 .into_iter()
185 .map(|(name, value)| (name.as_ref().to_string(), value.as_ref().to_string()))
186 .collect();
187 self
188 }
189}
190
191#[derive(Debug)]
192pub struct GenerateFilesOptions {
193 pub commands: Vec<GenerateFileCommand>,
194 pub image: Option<String>,
195 pub injected_files: Vec<TransferedFile>,
196 pub temp_name: Option<String>,
198 pub expected_path: Option<PathBuf>,
199}
200
201impl GenerateFilesOptions {
202 pub fn new<I>(commands: I, image: Option<String>, expected_path: Option<PathBuf>) -> Self
203 where
204 I: IntoIterator<Item = GenerateFileCommand>,
205 {
206 Self {
207 commands: commands.into_iter().collect(),
208 injected_files: vec![],
209 image,
210 temp_name: None,
211 expected_path,
212 }
213 }
214
215 pub fn with_files<I>(
216 commands: I,
217 image: Option<String>,
218 injected_files: &[TransferedFile],
219 expected_path: Option<PathBuf>,
220 ) -> Self
221 where
222 I: IntoIterator<Item = GenerateFileCommand>,
223 {
224 Self {
225 commands: commands.into_iter().collect(),
226 injected_files: injected_files.into(),
227 image,
228 temp_name: None,
229 expected_path,
230 }
231 }
232
233 pub fn image<S>(mut self, image: S) -> Self
234 where
235 S: AsRef<str>,
236 {
237 self.image = Some(image.as_ref().to_string());
238 self
239 }
240
241 pub fn injected_files<I>(mut self, injected_files: I) -> Self
242 where
243 I: IntoIterator<Item = TransferedFile>,
244 {
245 self.injected_files = injected_files.into_iter().collect();
246 self
247 }
248
249 pub fn temp_name(mut self, name: impl Into<String>) -> Self {
250 self.temp_name = Some(name.into());
251 self
252 }
253}
254
255#[derive(Debug)]
256pub struct RunCommandOptions {
257 pub program: String,
258 pub args: Vec<String>,
259 pub env: Vec<(String, String)>,
260}
261
262impl RunCommandOptions {
263 pub fn new<S>(program: S) -> Self
264 where
265 S: AsRef<str>,
266 {
267 Self {
268 program: program.as_ref().to_string(),
269 args: vec![],
270 env: vec![],
271 }
272 }
273
274 pub fn args<S, I>(mut self, args: I) -> Self
275 where
276 S: AsRef<str>,
277 I: IntoIterator<Item = S>,
278 {
279 self.args = args.into_iter().map(|s| s.as_ref().to_string()).collect();
280 self
281 }
282
283 pub fn env<S, I>(mut self, env: I) -> Self
284 where
285 S: AsRef<str>,
286 I: IntoIterator<Item = (S, S)>,
287 {
288 self.env = env
289 .into_iter()
290 .map(|(name, value)| (name.as_ref().to_string(), value.as_ref().to_string()))
291 .collect();
292 self
293 }
294}
295
296pub struct RunScriptOptions {
297 pub local_script_path: PathBuf,
298 pub args: Vec<String>,
299 pub env: Vec<(String, String)>,
300}
301
302impl RunScriptOptions {
303 pub fn new<P>(local_script_path: P) -> Self
304 where
305 P: AsRef<Path>,
306 {
307 Self {
308 local_script_path: local_script_path.as_ref().into(),
309 args: vec![],
310 env: vec![],
311 }
312 }
313
314 pub fn args<S, I>(mut self, args: I) -> Self
315 where
316 S: AsRef<str>,
317 I: IntoIterator<Item = S>,
318 {
319 self.args = args.into_iter().map(|s| s.as_ref().to_string()).collect();
320 self
321 }
322
323 pub fn env<S, I>(mut self, env: I) -> Self
324 where
325 S: AsRef<str>,
326 I: IntoIterator<Item = (S, S)>,
327 {
328 self.env = env
329 .into_iter()
330 .map(|(name, value)| (name.as_ref().to_string(), value.as_ref().to_string()))
331 .collect();
332 self
333 }
334}
335
336#[derive(Debug, Clone, Serialize, Deserialize)]
338pub struct TransferedFile {
339 pub local_path: PathBuf,
340 pub remote_path: PathBuf,
341 pub mode: String,
343}
344
345impl TransferedFile {
346 pub fn new<P>(local_path: P, remote_path: P) -> Self
347 where
348 P: AsRef<Path>,
349 {
350 Self {
351 local_path: local_path.as_ref().into(),
352 remote_path: remote_path.as_ref().into(),
353 mode: "0644".to_string(), }
355 }
356
357 pub fn mode<S>(mut self, mode: S) -> Self
358 where
359 S: AsRef<str>,
360 {
361 self.mode = mode.as_ref().to_string();
362 self
363 }
364}
365
366impl std::fmt::Display for TransferedFile {
367 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
368 write!(
369 f,
370 "File to transfer (local: {}, remote: {})",
371 self.local_path.display(),
372 self.remote_path.display()
373 )
374 }
375}