1use std::path::Path;
9
10use crate::core::command::{Command, ProjectFile};
11use crate::core::project::PlateInspection;
12
13#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct PrintStartParams {
18 pub file: String,
20 pub plate: u32,
21 pub use_ams: bool,
22 pub ams_map: Vec<i32>,
23 pub bed_type: String,
24 pub timelapse: bool,
25}
26
27impl PrintStartParams {
28 pub fn is_3mf(&self) -> bool {
30 self.file.to_ascii_lowercase().ends_with(".3mf")
31 }
32}
33
34pub fn build_command(params: &PrintStartParams, inspection: Option<&PlateInspection>) -> Command {
40 if !params.is_3mf() {
41 return Command::GcodeFile(params.file.clone());
42 }
43 let name = Path::new(¶ms.file)
44 .file_name()
45 .and_then(|s| s.to_str())
46 .unwrap_or(¶ms.file)
47 .to_string();
48 let mut pf = ProjectFile::new(format!("ftp://{}", params.file), params.plate, name);
49 pf.bed_type = params.bed_type.clone();
50 pf.timelapse = params.timelapse;
51 if params.use_ams {
52 pf.use_ams = true;
53 pf.ams_mapping = params.ams_map.clone();
54 }
55 if let Some(insp) = inspection {
56 pf.md5 = insp.gcode_md5.clone();
57 }
58 Command::ProjectFile(pf)
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 fn params(file: &str) -> PrintStartParams {
66 PrintStartParams {
67 file: file.to_string(),
68 plate: 1,
69 use_ams: false,
70 ams_map: vec![],
71 bed_type: "auto".to_string(),
72 timelapse: false,
73 }
74 }
75
76 fn inspection(md5: &str) -> PlateInspection {
77 PlateInspection {
78 plate: 1,
79 gcode_md5: md5.to_string(),
80 sidecar_md5: None,
81 sidecar_matches: true,
82 bed_type: None,
83 filament_colors: vec![],
84 has_timelapse_blocks: false,
85 }
86 }
87
88 #[test]
89 fn three_mf_builds_a_project_file_with_ftp_url() {
90 let mut p = params("/cache/coin.gcode.3mf");
91 p.plate = 2;
92 p.use_ams = true;
93 p.ams_map = vec![0, 3];
94 p.timelapse = true;
95 match build_command(&p, None) {
96 Command::ProjectFile(pf) => {
97 assert_eq!(pf.url, "ftp:///cache/coin.gcode.3mf");
98 assert_eq!(pf.plate, 2);
99 assert_eq!(pf.subtask_name, "coin.gcode.3mf");
100 assert!(pf.use_ams);
101 assert_eq!(pf.ams_mapping, vec![0, 3]);
102 assert!(pf.timelapse);
103 assert!(pf.md5.is_empty(), "no inspection ⇒ no md5 check");
104 }
105 other => panic!("expected ProjectFile, got {other:?}"),
106 }
107 }
108
109 #[test]
110 fn an_inspection_stamps_the_plate_gcode_md5() {
111 match build_command(¶ms("/x.gcode.3mf"), Some(&inspection("abc123"))) {
112 Command::ProjectFile(pf) => assert_eq!(pf.md5, "abc123"),
113 other => panic!("expected ProjectFile, got {other:?}"),
114 }
115 }
116
117 #[test]
118 fn raw_gcode_builds_a_gcode_file_and_ignores_inspection() {
119 assert!(matches!(
121 build_command(¶ms("/test.gcode"), Some(&inspection("abc"))),
122 Command::GcodeFile(f) if f == "/test.gcode"
123 ));
124 }
125}