8572d564b1
Completes the GenericPrinter -> BambuGenericPrinter -> BambuV1/V2 chain this project wanted from the start. BambuGenericPrinter holds the fields and behavior every Bambu printer shares (access code, serial number, CA trust, the TLS test/fetch methods); BambuV1Printer and BambuV2Printer each *have* one (composition) and are now genuinely separate types, ready to carry flavour-specific report-schema fields later. Also threads through a new 'sn' (serial number) field the real MQTT topics will need. Adds real 'fetch the CA automatically' capability, verified against a live TLS server (not just compiled): - BambuGenericPrinter::fetch_certificate() does trust-on-first-connect — connects once with verification disabled, captures the certificate the printer actually presents via native_tls's peer_certificate()/to_der(), and returns it as PEM. Deliberately a method you call once by hand (examples/fetch_bambu_cert.rs), not something connect() falls back to silently, since TOFU trusts whoever's on the network the moment you run it. Verified end-to-end against a local openssl s_server: the fetched PEM's SHA-256 fingerprint exactly matched the server's real certificate. - Verified the other direction too: test_bambu_certs (bundled-CA mode) correctly REJECTS that same test server's cert, since it wasn't signed by the real Bambu CA. Splitting BambuV1Printer/BambuV2Printer into distinct types broke the PrinterHandle::BambuV1(x) | PrinterHandle::BambuV2(x) or-pattern in both examples (or-patterns require every alternative to bind the same type) — fixed by giving each variant its own match arm.
66 lines
2.7 KiB
Rust
66 lines
2.7 KiB
Rust
//! Run with: cargo run --example printer_polymorphism
|
|
//!
|
|
//! Demonstrates the trait+enum pattern that stands in for inheritance:
|
|
//! - `connect()` is called the same way regardless of vendor (polymorphism),
|
|
//! but each variant's `impl GenericPrinter` runs completely different
|
|
//! code (override).
|
|
//! - `dispatch_gcode()` only exists on the two Bambu structs (extension) —
|
|
//! you have to `match` the enum back down to the concrete type to reach
|
|
//! it, which is the trade-off for not having implicit downcasting.
|
|
|
|
use continuum_proxy::printer::{
|
|
BambuTls, BambuV1Printer, BambuV2Printer, GenericPrinter, KlipperPrinter, PrinterHandle, PrusaLinkPrinter,
|
|
PrusaSerialPrinter,
|
|
};
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
let mut fleet: Vec<PrinterHandle> = vec![
|
|
PrinterHandle::BambuV1(BambuV1Printer::new(
|
|
"p1",
|
|
"P1S",
|
|
"192.168.1.49",
|
|
"87654321",
|
|
"01P00A000000000",
|
|
BambuTls::BundledCa,
|
|
)),
|
|
PrinterHandle::BambuV2(BambuV2Printer::new(
|
|
"p2",
|
|
"X1 Carbon",
|
|
"192.168.1.50",
|
|
"12345678",
|
|
"00M00A000000000",
|
|
BambuTls::BundledCa,
|
|
)),
|
|
PrinterHandle::PrusaLink(PrusaLinkPrinter::new("p3", "MK4", "192.168.1.51", "prusa-api-key")),
|
|
PrinterHandle::PrusaSerial(PrusaSerialPrinter::new("p4", "MK3S+", 0)),
|
|
PrinterHandle::Klipper(KlipperPrinter::new("p5", "Voron 2.4", "192.168.1.52")),
|
|
// No host configured — this one will hit the Err path.
|
|
PrinterHandle::Klipper(KlipperPrinter::new("p6", "Broken Voron", "")),
|
|
];
|
|
|
|
// Uniform call site: every printer connects the same way from the
|
|
// caller's point of view, even though each variant's `connect()` body
|
|
// is an unrelated implementation.
|
|
for printer in &mut fleet {
|
|
match printer.connect().await {
|
|
Ok(()) => println!(" -> connected: {}\n", printer.display_name()),
|
|
Err(err) => println!(" -> failed: {err}\n"),
|
|
}
|
|
}
|
|
|
|
// Vendor-only extension: reachable only after matching the concrete
|
|
// variant back out of the enum. BambuV1Printer and BambuV2Printer are
|
|
// separate types now (each *has* a BambuGenericPrinter rather than
|
|
// being the same struct), so — unlike before the split — this needs
|
|
// two arms instead of one `A(x) | B(x)` pattern: an or-pattern requires
|
|
// every alternative to bind the same type, and these no longer do.
|
|
for printer in &fleet {
|
|
match printer {
|
|
PrinterHandle::BambuV1(bambu) => bambu.dispatch_gcode("part.gcode.3mf"),
|
|
PrinterHandle::BambuV2(bambu) => bambu.dispatch_gcode("part.gcode.3mf"),
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|