//! Run with: cargo run --example bambu_cache_list -- [dir] //! //! `dir` defaults to `cache`; pass `/` to see the SD card root, which is //! how to find out what a file's real absolute path is. //! //! **Read-only.** Connects, reads one `print.push_status`, and lists the //! printer's `cache/` directory over FTPS. It sends no commands that change //! anything - the `pushall` it issues is a request for a status report, which //! is the one write-shaped thing a read-only tool has to do on a v1 printer //! to learn anything at all. //! //! The point of it: `start_uploaded_file` can only print a file that is //! already in `cache/`, so this answers "is there anything there, and what is //! it called?" before any print command is sent. It is also how to find a //! real slicer-produced `.3mf` to test that command against, which is worth //! a great deal more than a hand-built one - if a hand-built file fails there //! is no way to tell whether the command was wrong or the file was. use std::time::Duration; use continuum_proxy::fleet; use continuum_proxy::printer::{GenericPrinter, PrinterHandle}; const CONNECT_TIMEOUT: Duration = Duration::from_secs(20); const STATUS_TIMEOUT: Duration = Duration::from_secs(15); #[tokio::main] async fn main() -> anyhow::Result<()> { let Some(target) = std::env::args().nth(1) else { anyhow::bail!("usage: cargo run --example bambu_cache_list -- [dir]"); }; let dir = std::env::args().nth(2).unwrap_or_else(|| "cache".to_string()); let mut printers = fleet::load(std::path::Path::new("printers.toml"))?; let printer = printers .iter_mut() .find(|p| p.base().id == target) .ok_or_else(|| anyhow::anyhow!("no printer with id '{target}' in printers.toml"))?; let PrinterHandle::Bambu(bambu) = printer else { anyhow::bail!("'{target}' is not a Bambu printer - this example is Bambu-specific"); }; println!("=== {} ===", bambu.display_name()); match tokio::time::timeout(CONNECT_TIMEOUT, bambu.connect()).await { Ok(Ok(())) => {} Ok(Err(err)) => anyhow::bail!("connect failed: {err}"), Err(_) => anyhow::bail!("connect timed out - printer off or unreachable?"), } bambu.pushall().await.ok(); let deadline = tokio::time::Instant::now() + STATUS_TIMEOUT; loop { if let Some(report) = bambu.print_status().await { if let Some(state) = report.gcode_state.clone() { println!(" gcode_state: {state}"); println!(" subtask_name: {}", report.subtask_name.clone().unwrap_or_default()); println!( " layer: {}/{}", report.layer_num.unwrap_or_default(), report.total_layer_num.unwrap_or_default() ); println!(" percent: {}", report.mc_percent.unwrap_or_default()); break; } } if tokio::time::Instant::now() >= deadline { println!(" (no gcode_state within {STATUS_TIMEOUT:?} - listing cache/ anyway)"); break; } tokio::time::sleep(Duration::from_millis(500)).await; } println!("\n {dir} over FTPS:"); match bambu.list_dir(&dir).await { Ok(entries) if entries.is_empty() => println!(" (empty)"), Ok(entries) => { for entry in &entries { println!(" {entry}"); } println!("\n {} entr(ies)", entries.len()); } Err(err) => println!(" FAILED: {err}"), } Ok(()) }