Wire fleet::load into main.rs; fix request() reply unwrapping
main.rs never actually loaded printers.toml or connected anything -
fleet/printer were only ever exercised by standalone examples. Now
main() loads the fleet (path configurable via CONTINUUM_PRINTERS_PATH,
default "printers.toml") and connects every printer concurrently at
startup, logging success/failure per printer rather than failing
startup over one bad printer.
That surfaced a real bug the instant it ran against a live printer:
complete_pending() was sending the whole {"info": {...}} wrapper through
the pending oneshot, not the unwrapped body - BambuPrinter::get_version
deserializing that into GetVersionResponse failed with "missing field
module" even though module was right there, just one level deeper than
expected. Fixed by unwrapping the single category key before completing
the pending request, symmetric with how a request gets wrapped on the
way out.
Verified live against a real H2C (MQTT v5/BambuMQTT v2): connect,
get_version, and the full pending-request correlation all worked
end-to-end, returning real firmware versions for every module (main
board 01.01.05.00, both AMS units, AMS HT, etc). The other configured
printer (P1P, forced v1) failed with a real, expected TLS error - it
doesn't chain to the bundled CA, matching the already-documented P1P
quirk; needs the ca_cert_path/fetch_bambu_cert workflow, not a code fix.
This commit is contained in:
+42
-6
@@ -1,4 +1,5 @@
|
||||
mod config;
|
||||
mod fleet;
|
||||
mod go2rtc;
|
||||
mod printer;
|
||||
mod uplink;
|
||||
@@ -6,6 +7,7 @@ mod uplink;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::printer::{GenericPrinter, PrinterHandle};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
@@ -18,12 +20,24 @@ async fn main() -> anyhow::Result<()> {
|
||||
|
||||
tracing::info!(gateway_id = %config.gateway_id, farm_id = %config.farm_id, "starting continuum-proxy");
|
||||
|
||||
// Two things run at once for now: the cloud uplink, and the go2rtc
|
||||
// camera-restreaming process. More will join them later - printer
|
||||
// discovery, the plate changer - as you build past src/printer/'s
|
||||
// stubs. `tokio::select!` runs both and stops as soon as either one
|
||||
// returns; both loop forever below, so in practice this runs until the
|
||||
// process is killed.
|
||||
// Loaded and connected here, once, at startup - nothing yet re-reads
|
||||
// printers.toml on a running daemon (adding/removing a printer means
|
||||
// a restart), and nothing yet lets the uplink dispatch a command to
|
||||
// one of these once connected - see PrinterHandle's own doc comment
|
||||
// for what's built and what's still a stub per vendor. Keeping
|
||||
// `fleet` alive as a local variable for the rest of `main` (which
|
||||
// never returns, below) is what keeps every connection open; it's
|
||||
// not otherwise touched yet.
|
||||
let mut fleet = fleet::load(std::path::Path::new(&config.printers_path))?;
|
||||
connect_fleet(&mut fleet).await;
|
||||
|
||||
// Three things run at once for now: the cloud uplink, the go2rtc
|
||||
// camera-restreaming process, and (implicitly, via the connections
|
||||
// opened above) every configured printer's live session. More will
|
||||
// join them later - printer discovery, the plate changer - as you
|
||||
// build past src/printer/'s stubs. `tokio::select!` runs both of the
|
||||
// tasks below and stops as soon as either one returns; both loop
|
||||
// forever, so in practice this runs until the process is killed.
|
||||
tokio::select! {
|
||||
_ = uplink::run(config.clone()) => {}
|
||||
_ = go2rtc::watchdog(config.go2rtc_bin.clone(), config.go2rtc_config.clone()) => {}
|
||||
@@ -31,3 +45,25 @@ async fn main() -> anyhow::Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Connects every configured printer concurrently (not one at a time -
|
||||
/// Bambu's auto-detect fallback alone can take several seconds per
|
||||
/// printer if it has to time out on MQTT v5 before trying v3.1.1;
|
||||
/// serially, a fleet of twenty would take twenty times as long to start).
|
||||
/// Logs success/failure per printer instead of failing startup over one -
|
||||
/// a farm shouldn't refuse to start because one printer is unplugged.
|
||||
async fn connect_fleet(fleet: &mut [PrinterHandle]) {
|
||||
let results =
|
||||
futures_util::future::join_all(fleet.iter_mut().map(|printer| async {
|
||||
let name = printer.display_name();
|
||||
(name, printer.connect().await)
|
||||
}))
|
||||
.await;
|
||||
|
||||
for (name, result) in results {
|
||||
match result {
|
||||
Ok(()) => tracing::info!(printer = %name, "connected"),
|
||||
Err(err) => tracing::warn!(printer = %name, %err, "failed to connect"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user