Fix build errors: FTPS AsyncRead bridge, TLS connector type, unsafe env::set_var, dead code

Verified with cargo check + cargo run --example printer_polymorphism.
This commit is contained in:
2026-08-28 17:09:11 +00:00
parent 03bd07fbd7
commit 9b3815fd25
7 changed files with 27 additions and 23 deletions
+7 -2
View File
@@ -3,8 +3,10 @@ use std::time::Duration;
use rumqttc::{AsyncClient, Event, MqttOptions, Packet, QoS, TlsConfiguration, Transport};
use serde::{Deserialize, Serialize};
use suppaftp::async_native_tls::TlsConnector;
use suppaftp::{AsyncNativeTlsConnector, AsyncNativeTlsFtpStream};
use tokio::sync::mpsc;
use tokio_util::compat::TokioAsyncReadCompatExt;
use tracing::{debug, info, warn};
const MQTT_PORT: u16 = 8883;
@@ -127,11 +129,14 @@ pub async fn dispatch_file(printer: &BambuPrinter, local_path: &Path, remote_nam
let ftp = AsyncNativeTlsFtpStream::connect(format!("{}:{FTPS_PORT}", printer.host)).await?;
let mut ftp = ftp
.into_secure(AsyncNativeTlsConnector::from(native_tls::TlsConnector::new()?), &printer.host)
.into_secure(AsyncNativeTlsConnector::from(TlsConnector::new()), &printer.host)
.await?;
ftp.login("bblp", &printer.access_code).await?;
let mut file = tokio::fs::File::open(local_path).await?;
// suppaftp wants a `futures::io::AsyncRead`; tokio::fs::File only
// implements tokio's own AsyncRead, so bridge it with tokio-util's
// `.compat()` adapter rather than pulling in a second async-fs stack.
let mut file = tokio::fs::File::open(local_path).await?.compat();
ftp.put_file(remote_name, &mut file).await?;
ftp.quit().await?;
+3 -15
View File
@@ -111,20 +111,8 @@ async fn main() -> anyhow::Result<()> {
Ok(())
}
/// Loads a `.env` file if present, without pulling in a heavyweight config
/// crate. No-op (and safe to ignore errors) when the file doesn't exist.
/// Loads `.env` if present; a missing file is fine (env vars may already be
/// set by the process supervisor), so the error is deliberately ignored.
fn dotenvy_load() {
if let Ok(contents) = std::fs::read_to_string(".env") {
for line in contents.lines() {
let line = line.trim();
if line.is_empty() || line.starts_with('#') {
continue;
}
if let Some((key, value)) = line.split_once('=') {
if std::env::var(key).is_err() {
std::env::set_var(key, value);
}
}
}
}
let _ = dotenvy::dotenv();
}
-2
View File
@@ -1,8 +1,6 @@
mod gpio;
mod serial;
pub use gpio::SensorState;
use thiserror::Error;
use tracing::{info, warn};
+6 -1
View File
@@ -1,3 +1,5 @@
use std::time::Duration;
use tracing::info;
use super::{Printer, PrinterBase, PrinterError};
@@ -27,7 +29,10 @@ impl Printer for KlipperPrinter {
async fn connect(&mut self) -> Result<(), PrinterError> {
info!(printer = %self.base.id, host = %self.base.host, "probing Moonraker over HTTP");
reqwest::get(format!("http://{}/printer/info", self.base.host))
reqwest::Client::new()
.get(format!("http://{}/printer/info", self.base.host))
.timeout(Duration::from_secs(5))
.send()
.await
.and_then(|resp| resp.error_for_status())
.map_err(|err| PrinterError::Connection(self.base.id.clone(), err.to_string()))?;
+6 -1
View File
@@ -54,7 +54,12 @@ pub trait Printer {
/// REQUIRED, no default body: every printer vendor speaks a different
/// protocol, so there's nothing sensible to share here. Each `impl`
/// below provides a completely different body — that's the "override".
async fn connect(&mut self) -> Result<(), PrinterError>;
///
/// Spelled as `-> impl Future<..> + Send` rather than plain `async fn`
/// so the resulting future is `Send` and can be `.await`ed inside a
/// `tokio::spawn`ed task; each `impl` below still just writes a normal
/// `async fn` body, which satisfies this signature automatically.
fn connect(&mut self) -> impl std::future::Future<Output = Result<(), PrinterError>> + Send;
/// OPTIONAL: a default body every printer gets for free unless it
/// chooses to provide its own. None of ours do, so all three vendors
+3
View File
@@ -1,3 +1,5 @@
use std::time::Duration;
use tracing::info;
use super::{Printer, PrinterBase, PrinterError};
@@ -30,6 +32,7 @@ impl Printer for PrusaPrinter {
reqwest::Client::new()
.get(format!("http://{}/api/v1/status", self.base.host))
.header("X-Api-Key", &self.api_key)
.timeout(Duration::from_secs(5))
.send()
.await
.and_then(|resp| resp.error_for_status())