Bambu TLS trust config + finish PrusaLink/PrusaSerial split

Certs:
- Vendor Bambu's shared LAN-mode root CA (certs/bambu_ca2.pem, verified
  self-signed CA:TRUE, see certs/README.md for provenance/fingerprint).
- Config gains bambu_ca_cert_path (per-printer override) and
  bambu_require_valid_cert (the allow/reject flag); printer::bambu::BambuTls
  turns those into BundledCa/Custom/Insecure. connect() doesn't perform a
  real handshake yet (no TLS-capable MQTT client wired in), just reports
  which trust mode it would use.

Also reconciles a rename in flight (Printer -> GenericPrinter trait) and
finishes the PrusaPrinter -> PrusaLinkPrinter/PrusaSerialPrinter split:
added the missing GenericPrinter impl for PrusaSerialPrinter, fixed
PrinterHandle's variant payload types, updated mod.rs's pub use list and
doc comments, and updated the example to the new 5-variant shape.

Verified with cargo check --all-targets (0 errors) and a full run of
cargo run --example printer_polymorphism.
This commit is contained in:
2026-08-28 20:38:10 +00:00
parent d0a17ee50e
commit 9eab5e5a04
8 changed files with 302 additions and 45 deletions
+16 -11
View File
@@ -2,27 +2,31 @@
//!
//! Demonstrates the trait+enum pattern that stands in for inheritance:
//! - `connect()` is called the same way regardless of vendor (polymorphism),
//! but each vendor's `impl Printer` runs completely different code
//! (override).
//! but each variant's `impl GenericPrinter` runs completely different
//! code (override).
//! - `dispatch_gcode()` only exists on `BambuPrinter` (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::{BambuPrinter, KlipperPrinter, Printer, PrinterHandle, PrusaPrinter};
use continuum_proxy::printer::{
BambuPrinter, BambuTls, GenericPrinter, KlipperPrinter, PrinterHandle, PrusaLinkPrinter, PrusaSerialPrinter,
};
#[tokio::main]
async fn main() {
let mut fleet: Vec<PrinterHandle> = vec![
PrinterHandle::Bambu(BambuPrinter::new("p1", "X1 Carbon", "192.168.1.50", "12345678")),
PrinterHandle::Prusa(PrusaPrinter::new("p2", "MK4", "192.168.1.51", "prusa-api-key")),
PrinterHandle::Klipper(KlipperPrinter::new("p3", "Voron 2.4", "192.168.1.52")),
PrinterHandle::BambuV1(BambuPrinter::new("p1", "P1S", "192.168.1.49", "87654321", BambuTls::BundledCa)),
PrinterHandle::BambuV2(BambuPrinter::new("p2", "X1 Carbon", "192.168.1.50", "12345678", 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("p4", "Broken Voron", "")),
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 the three `connect()` bodies
// are unrelated implementations.
// 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()),
@@ -31,9 +35,10 @@ async fn main() {
}
// Vendor-only extension: reachable only after matching the concrete
// variant back out of the enum.
// variant back out of the enum. Both Bambu variants wrap the same
// BambuPrinter struct right now, so both get dispatch_gcode().
for printer in &fleet {
if let PrinterHandle::Bambu(bambu) = printer {
if let PrinterHandle::BambuV1(bambu) | PrinterHandle::BambuV2(bambu) = printer {
bambu.dispatch_gcode("part.gcode.3mf");
}
}