Skip to content

Commit 3b19a55

Browse files
committed
fixes
Signed-off-by: Jess Frazelle <[email protected]>
1 parent f55d3b3 commit 3b19a55

File tree

5 files changed

+65
-34
lines changed

5 files changed

+65
-34
lines changed

bambulabs/src/client.rs

Lines changed: 53 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,61 +13,67 @@ use crate::{
1313
sequence_id::SequenceId,
1414
};
1515

16+
const MQTT_PORT: u16 = 8883;
17+
const MAX_PACKET_SIZE: usize = 1024 * 1024;
18+
1619
/// The Bambu MQTT client.
1720
#[derive(Clone)]
1821
pub struct Client {
19-
/// The MQTT host.
20-
pub host: String,
22+
/// The IP address of the MQTT host.
23+
pub ip: String,
2124
/// The access code.
2225
pub access_code: String,
2326
/// The serial number.
2427
pub serial: String,
2528

26-
client: rumqttc::AsyncClient,
29+
topic_device_request: String,
30+
topic_device_report: String,
31+
32+
client: Arc<rumqttc::AsyncClient>,
2733
event_loop: Arc<Mutex<rumqttc::EventLoop>>,
2834

2935
responses: Arc<DashMap<SequenceId, Message>>,
30-
31-
topic_device_request: String,
32-
topic_device_report: String,
3336
}
3437

35-
const MAX_PACKET_SIZE: usize = 1024 * 1024;
36-
3738
impl Client {
3839
/// Creates a new Bambu printer MQTT client.
3940
pub fn new<S: Into<String> + Clone>(ip: S, access_code: S, serial: S) -> Result<Self> {
4041
let access_code = access_code.into();
42+
let ip = ip.into();
4143
let serial = serial.into();
42-
let host = format!("mqtts://{}:8883", ip.clone().into());
4344

45+
let opts = Self::get_config(&ip, &access_code)?;
46+
let (client, event_loop) = rumqttc::AsyncClient::new(opts, 25);
47+
48+
Ok(Self {
49+
ip,
50+
access_code,
51+
topic_device_request: format!("device/{}/request", &serial),
52+
topic_device_report: format!("device/{}/report", &serial),
53+
serial,
54+
client: Arc::new(client),
55+
event_loop: Arc::new(Mutex::new(event_loop)),
56+
responses: Arc::new(DashMap::new()),
57+
})
58+
}
59+
60+
fn get_config(ip: &str, access_code: &str) -> Result<rumqttc::MqttOptions> {
4461
let client_id = format!("bambu-api-{}", nanoid::nanoid!(8));
4562

4663
let ssl_config = rustls::ClientConfig::builder()
4764
.dangerous()
4865
.with_custom_certificate_verifier(Arc::new(crate::no_auth::NoAuth::new()))
4966
.with_no_client_auth();
5067

51-
let mut opts = rumqttc::MqttOptions::new(client_id, ip, 8883);
68+
let mut opts = rumqttc::MqttOptions::new(client_id, ip, MQTT_PORT);
5269
opts.set_max_packet_size(MAX_PACKET_SIZE, MAX_PACKET_SIZE);
5370
opts.set_keep_alive(Duration::from_secs(5));
54-
opts.set_credentials("bblp", &access_code);
71+
opts.set_credentials("bblp", access_code);
5572
opts.set_transport(rumqttc::Transport::Tls(rumqttc::TlsConfiguration::Rustls(Arc::new(
5673
ssl_config,
5774
))));
5875

59-
let (client, event_loop) = rumqttc::AsyncClient::new(opts, 25);
60-
61-
Ok(Self {
62-
host,
63-
access_code,
64-
topic_device_request: format!("device/{}/request", &serial),
65-
topic_device_report: format!("device/{}/report", &serial),
66-
serial,
67-
client,
68-
event_loop: Arc::new(Mutex::new(event_loop)),
69-
responses: Arc::new(DashMap::new()),
70-
})
76+
Ok(opts)
7177
}
7278

7379
/// Polls for a message from the MQTT event loop.
@@ -81,7 +87,27 @@ impl Client {
8187
///
8288
/// Returns an error if there was a problem polling for a message or parsing the event.
8389
async fn poll(&mut self) -> Result<()> {
84-
let msg_opt = self.event_loop.lock().await.poll().await?;
90+
let mut ep = self.event_loop.lock().await;
91+
let msg_opt = match ep.poll().await {
92+
Ok(msg_opt) => msg_opt,
93+
Err(err) => {
94+
if let rumqttc::ConnectionError::MqttState(rumqttc::StateError::Io(err)) = err {
95+
tracing::error!("Error polling for message: {:?}", err);
96+
tracing::warn!("Reconnecting...");
97+
// We are in a bad state and should reconnect.
98+
let opts = Self::get_config(&self.ip, &self.access_code)?;
99+
let (client, event_loop) = rumqttc::AsyncClient::new(opts, 25);
100+
drop(ep);
101+
self.client = Arc::new(client);
102+
self.event_loop = Arc::new(Mutex::new(event_loop));
103+
tracing::warn!("Reconnected.");
104+
return Ok(());
105+
}
106+
107+
tracing::error!("Error polling for message: {:?}", err);
108+
return Ok(());
109+
}
110+
};
85111

86112
let message = parse_message(&msg_opt);
87113

@@ -163,14 +189,16 @@ impl Client {
163189
if let Some(response) = self.responses.get(sequence_id) {
164190
return Ok(response.value().clone());
165191
}
192+
// This sleep is important since it frees up the thread.
193+
tokio::time::sleep(Duration::from_secs(1)).await;
166194
}
167195

168196
anyhow::bail!("Timeout waiting for response to command: {:?}", command)
169197
}
170198

171199
/// Upload a file.
172200
pub async fn upload_file(&self, path: &std::path::Path) -> Result<()> {
173-
let host_url = url::Url::parse(&self.host)?;
201+
let host_url = url::Url::parse(&format!("mqtts://{}:{}", self.ip, MQTT_PORT))?;
174202
let host = host_url
175203
.host_str()
176204
.ok_or(anyhow::anyhow!("not a valid hostname"))?

src/config.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ pub struct Config {
1616

1717
impl Config {
1818
/// Parse a configuration from a toml file.
19-
pub fn from_file(file: &PathBuf) -> Result<Self> {
20-
let config = std::fs::read_to_string(file)?;
19+
pub async fn from_file(file: &PathBuf) -> Result<Self> {
20+
let config = tokio::fs::read_to_string(file).await?;
2121
Self::from_str(&config)
2222
}
2323

src/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ pub struct Server {
151151
pub address: String,
152152
}
153153

154-
#[tokio::main]
154+
#[tokio::main(flavor = "multi_thread", worker_threads = 128)]
155155
async fn main() -> Result<()> {
156156
let opts: Opts = Opts::parse();
157157

@@ -221,7 +221,7 @@ async fn main() -> Result<()> {
221221
delouse::init()?;
222222
}
223223

224-
let config = config::Config::from_file(&opts.config)?;
224+
let config = config::Config::from_file(&opts.config).await?;
225225

226226
if let Err(err) = run_cmd(&opts, &config).await {
227227
bail!("running cmd `{:?}` failed: {:?}", &opts.subcmd, err);
@@ -244,7 +244,7 @@ async fn run_cmd(opts: &Opts, config: &Config) -> Result<()> {
244244

245245
let machines = api_context.list_machines()?;
246246
for (id, machine) in machines.iter() {
247-
println!("{}: {:?}", id, machine);
247+
println!("{}: {:#?}\n", id, machine);
248248
}
249249
}
250250
SubCommand::PrintFile {

src/server/endpoints.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,16 @@ pub(crate) async fn print_file(
150150
active_jobs.insert(job_id.to_string(), handle);
151151
}
152152
crate::machine::MachineHandle::NetworkPrinter(printer) => {
153-
printer
153+
let result = printer
154154
.client
155155
.slice_and_print(&params.job_name, &filepath)
156156
.await
157157
.map_err(|e| {
158158
tracing::error!("failed to print file: {:?}", e);
159159
HttpError::for_bad_request(None, "failed to print file".to_string())
160160
})?;
161+
162+
tracing::info!("result: {:?}", result);
161163
}
162164
}
163165

src/usb_printer.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,10 @@ impl UsbPrinter {
9696
Ok(gcode)
9797
}
9898

99-
fn print(&mut self, file: &std::path::Path) -> Result<Message> {
99+
async fn print(&mut self, file: &std::path::Path) -> Result<Message> {
100100
// Read the gcode file.
101-
let lines: Vec<String> = std::fs::read_to_string(file)?
101+
let lines: Vec<String> = tokio::fs::read_to_string(file)
102+
.await?
102103
.lines() // split the string into an iterator of string slices
103104
.map(|s| {
104105
let s = String::from(s);
@@ -124,7 +125,7 @@ impl UsbPrinter {
124125

125126
pub async fn slice_and_print(&mut self, file: &std::path::Path) -> Result<Message> {
126127
let gcode = self.slice(file).await?;
127-
self.print(&gcode)
128+
self.print(&gcode).await
128129
}
129130

130131
pub fn status(&self) -> Result<Message> {

0 commit comments

Comments
 (0)