Skip to content

Commit da9184e

Browse files
committed
feat: unified type for received messages, MqttMessage
1 parent 5548368 commit da9184e

6 files changed

Lines changed: 58 additions & 61 deletions

File tree

docs/TOKIO_ASYNC_CLIENT_API_GUIDE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,7 @@ pub trait TokioMqttEventHandler: Send + Sync {
708708
async fn on_unsubscribed(&mut self, result: &UnsubscribeResult) {}
709709

710710
/// Called when message is received from broker
711-
async fn on_message_received(&mut self, publish: &MqttPublish) {}
711+
async fn on_message_received(&mut self, publish: &MqttMessage) {}
712712

713713
/// Called when ping response is received
714714
async fn on_ping_response(&mut self, result: &PingResult) {}
@@ -742,7 +742,7 @@ impl TokioMqttEventHandler for MyHandler {
742742
}
743743
}
744744

745-
async fn on_message_received(&mut self, publish: &MqttPublish) {
745+
async fn on_message_received(&mut self, publish: &MqttMessage) {
746746
let payload = String::from_utf8_lossy(&publish.payload);
747747
println!("📨 [{}] {}", publish.topic_name, payload);
748748
}

examples/tokio_async_mqtt_quic_example.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ async fn run_example(test_mode: bool) -> Result<(), Box<dyn std::error::Error>>
77
ConnectionResult, PingResult, PublishResult, SubscribeResult, UnsubscribeResult,
88
};
99
use flowsdk::mqtt_client::{
10-
MqttClientError, MqttClientOptions, TokioAsyncClientConfig, TokioAsyncMqttClient,
11-
TokioMqttEventHandler,
10+
MqttClientError, MqttClientOptions, MqttMessage, TokioAsyncClientConfig,
11+
TokioAsyncMqttClient, TokioMqttEventHandler,
1212
};
13-
use flowsdk::mqtt_serde::mqttv5::publishv5::MqttPublish;
1413
use tokio::time::{sleep, Duration};
1514

1615
/// Simple event handler for the QUIC async client
@@ -96,7 +95,7 @@ async fn run_example(test_mode: bool) -> Result<(), Box<dyn std::error::Error>>
9695
}
9796
}
9897

99-
async fn on_message_received(&mut self, publish: &MqttPublish) {
98+
async fn on_message_received(&mut self, publish: &MqttMessage) {
10099
let payload_str = String::from_utf8_lossy(&publish.payload);
101100
println!(
102101
"[{}] 📨 Message received on '{}': {}",

examples/tokio_async_mqtt_v3_client_example.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ use flowsdk::mqtt_client::client::{
33
};
44
use flowsdk::mqtt_client::PublishCommand;
55
use flowsdk::mqtt_client::{
6-
MqttClientError, MqttClientOptions, TokioAsyncClientConfig, TokioAsyncMqttClient,
6+
MqttClientError, MqttClientOptions, MqttMessage, TokioAsyncClientConfig, TokioAsyncMqttClient,
77
TokioMqttEventHandler,
88
};
9-
use flowsdk::mqtt_serde::mqttv5::publishv5::MqttPublish;
9+
1010
use std::sync::{Arc, Mutex};
1111
use tokio::time::{sleep, Duration};
1212

@@ -116,7 +116,7 @@ impl TokioMqttEventHandler for TokioV3ExampleHandler {
116116
}
117117
}
118118

119-
async fn on_message_received(&mut self, publish: &MqttPublish) {
119+
async fn on_message_received(&mut self, publish: &MqttMessage) {
120120
let payload_str = String::from_utf8_lossy(&publish.payload);
121121
println!(
122122
"[{}] 📨 Message received on '{}': {}",

src/mqtt_client/engine.rs

Lines changed: 45 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use std::collections::{HashMap, VecDeque};
22
use std::time::{Duration, Instant};
33

44
use crate::mqtt_serde::control_packet::MqttPacket;
5-
use crate::mqtt_serde::mqttv3::{connectv3, disconnectv3, pingreqv3, pubrelv3, unsubscribev3};
5+
use crate::mqtt_serde::mqttv3::{
6+
connectv3, disconnectv3, pingreqv3, pubrelv3, subscribev3, unsubscribev3,
7+
};
68
use crate::mqtt_serde::mqttv5::{
79
authv5, common::properties::Property, connectv5, disconnectv5, pingreqv5, pubackv5::MqttPubAck,
810
pubcompv5::MqttPubComp, publishv5::MqttPublish, pubrecv5::MqttPubRec, pubrelv5::MqttPubRel,
@@ -19,6 +21,13 @@ use super::commands::{PublishCommand, SubscribeCommand, UnsubscribeCommand};
1921
use super::error::MqttClientError;
2022
use super::opts::MqttClientOptions;
2123

24+
/// Alias for `MqttPublish` (v5) to provide a single, unified type for received messages.
25+
///
26+
/// The engine normalizes all incoming PUBLISH packets (whether MQTT v3.1.1 or v5.0) into this structure.
27+
/// This simplifies downstream consumption by providing a consistent API regardless of the protocol version used.
28+
/// For MQTT v3.1.1 messages, the v5-specific fields (Properties) will be empty.
29+
pub type MqttMessage = MqttPublish;
30+
2231
/// Events emitted by the MqttEngine to be handled by the application (I/O layer)
2332
#[derive(Debug)]
2433
pub enum MqttEvent {
@@ -27,7 +36,7 @@ pub enum MqttEvent {
2736
Published(PublishResult),
2837
Subscribed(SubscribeResult),
2938
Unsubscribed(UnsubscribeResult),
30-
MessageReceived(MqttPublish),
39+
MessageReceived(MqttMessage),
3140
PingResponse(PingResult),
3241
Error(MqttClientError),
3342
/// Signal that a reconnection is needed (e.g. after keep-alive timeout)
@@ -74,7 +83,7 @@ pub enum MqttEvent {
7483
pub struct MqttEngine {
7584
options: MqttClientOptions,
7685
session: Option<ClientSession>,
77-
priority_queue: PriorityQueue<u8, PublishCommand>,
86+
priority_queue: PriorityQueue<u8, MqttPacket>,
7887
is_connected: bool,
7988
last_packet_sent: Instant,
8089
last_packet_received: Instant,
@@ -88,7 +97,6 @@ pub struct MqttEngine {
8897
pending_unsubscribes: HashMap<u16, Vec<String>>,
8998
pending_publishes: HashMap<u16, Instant>,
9099

91-
mqtt_version: u8,
92100
events: Vec<MqttEvent>,
93101

94102
// Reconnection state
@@ -132,7 +140,6 @@ impl MqttEngine {
132140
pending_subscribes: HashMap::new(),
133141
pending_unsubscribes: HashMap::new(),
134142
pending_publishes: HashMap::new(),
135-
mqtt_version,
136143
events: Vec::new(),
137144
reconnect_attempts: 0,
138145
next_reconnect_at: None,
@@ -250,7 +257,7 @@ impl MqttEngine {
250257
}
251258

252259
pub fn mqtt_version(&self) -> u8 {
253-
self.mqtt_version
260+
self.options.mqtt_version
254261
}
255262

256263
/// Process time-dependent logic (keep-alive, timeouts, retransmissions).
@@ -306,7 +313,7 @@ impl MqttEngine {
306313

307314
// MQTT v5.0: Client MUST NOT retransmit PUBLISH packets
308315
// Only MQTT v3.1.1 allows client-side retransmission with DUP=1
309-
if self.mqtt_version == 5 {
316+
if self.options.mqtt_version == 5 {
310317
return events;
311318
}
312319

@@ -367,7 +374,7 @@ impl MqttEngine {
367374

368375
// 4. Retransmission timeouts (QoS 1/2 messages)
369376
// Only for MQTT v3.1.1, as v5.0 forbids client-side retransmission
370-
if self.mqtt_version != 5 {
377+
if self.options.mqtt_version != 5 {
371378
for &sent_at in self.pending_publishes.values() {
372379
let resend_at = sent_at + self.retransmission_timeout;
373380
if next.is_none() || resend_at < next.unwrap() {
@@ -406,7 +413,7 @@ impl MqttEngine {
406413
self.session = Some(ClientSession::new());
407414
}
408415

409-
let packet = if self.mqtt_version == 5 {
416+
let packet = if self.options.mqtt_version == 5 {
410417
let connect = connectv5::MqttConnect::new(
411418
self.options.client_id.clone(),
412419
self.options.username.clone(),
@@ -453,7 +460,13 @@ impl MqttEngine {
453460
self.pending_publishes.insert(pid, Instant::now());
454461
}
455462

456-
self.priority_queue.enqueue(command.priority, command);
463+
let packet = if self.options.mqtt_version == 5 {
464+
MqttPacket::Publish5(command.to_mqtt_publish())
465+
} else {
466+
MqttPacket::Publish3(command.to_mqttv3_publish())
467+
};
468+
469+
self.priority_queue.enqueue(command.priority, packet);
457470
self.process_queue();
458471
Ok(pid)
459472
}
@@ -478,11 +491,23 @@ impl MqttEngine {
478491
.collect();
479492
self.pending_subscribes.insert(pid, topics);
480493

481-
let packet = MqttPacket::Subscribe5(subscribev5::MqttSubscribe::new(
482-
pid,
483-
command.subscriptions,
484-
command.properties,
485-
));
494+
let packet = if self.options.mqtt_version == 5 {
495+
MqttPacket::Subscribe5(subscribev5::MqttSubscribe::new(
496+
pid,
497+
command.subscriptions,
498+
command.properties,
499+
))
500+
} else {
501+
let v3_subs = command
502+
.subscriptions
503+
.into_iter()
504+
.map(|s| subscribev3::SubscriptionTopic {
505+
topic_filter: s.topic_filter,
506+
qos: s.qos,
507+
})
508+
.collect();
509+
MqttPacket::Subscribe3(subscribev3::MqttSubscribe::new(pid, v3_subs))
510+
};
486511

487512
self.enqueue_packet(packet)?;
488513
Ok(pid)
@@ -500,7 +525,7 @@ impl MqttEngine {
500525
self.pending_unsubscribes
501526
.insert(pid, command.topics.clone());
502527

503-
let packet = if self.mqtt_version == 5 {
528+
let packet = if self.options.mqtt_version == 5 {
504529
MqttPacket::Unsubscribe5(unsubscribev5::MqttUnsubscribe::new(
505530
pid,
506531
command.topics.clone(),
@@ -520,7 +545,7 @@ impl MqttEngine {
520545
return;
521546
}
522547

523-
let packet = if self.mqtt_version == 5 {
548+
let packet = if self.options.mqtt_version == 5 {
524549
MqttPacket::Disconnect5(disconnectv5::MqttDisconnect::new(0, Vec::new()))
525550
} else {
526551
MqttPacket::Disconnect3(disconnectv3::MqttDisconnect::new())
@@ -531,7 +556,7 @@ impl MqttEngine {
531556
}
532557

533558
pub fn auth(&mut self, reason_code: u8, properties: Vec<Property>) {
534-
if self.mqtt_version == 5 {
559+
if self.options.mqtt_version == 5 {
535560
let auth = authv5::MqttAuth::new(reason_code, properties);
536561
let _ = self.enqueue_packet(MqttPacket::Auth(auth));
537562
}
@@ -715,7 +740,7 @@ impl MqttEngine {
715740
}
716741

717742
pub fn send_ping(&mut self) {
718-
let packet = if self.mqtt_version == 5 {
743+
let packet = if self.options.mqtt_version == 5 {
719744
MqttPacket::PingReq5(pingreqv5::MqttPingReq::new())
720745
} else {
721746
MqttPacket::PingReq3(pingreqv3::MqttPingReq::new())
@@ -744,33 +769,7 @@ impl MqttEngine {
744769
}
745770

746771
while self.outgoing_buffer.len() < self.options.max_outgoing_packet_count {
747-
if let Some((_priority, mut command)) = self.priority_queue.dequeue() {
748-
let _pid = if command.qos > 0 {
749-
if let Some(pid) = command.packet_id {
750-
Some(pid)
751-
} else {
752-
match self.next_packet_id() {
753-
Ok(id) => {
754-
self.pending_publishes.insert(id, Instant::now());
755-
command.packet_id = Some(id);
756-
Some(id)
757-
}
758-
Err(e) => {
759-
self.events.push(MqttEvent::Error(e));
760-
continue;
761-
}
762-
}
763-
}
764-
} else {
765-
None
766-
};
767-
768-
let packet = if self.mqtt_version == 5 {
769-
MqttPacket::Publish5(command.to_mqtt_publish())
770-
} else {
771-
MqttPacket::Publish3(command.to_mqttv3_publish())
772-
};
773-
772+
if let Some((_priority, packet)) = self.priority_queue.dequeue() {
774773
if let Err(e) = self.enqueue_packet(packet) {
775774
self.events.push(MqttEvent::Error(e));
776775
}

src/mqtt_client/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub use commands::{
2020
PublishBuilderError, PublishCommand, PublishCommandBuilder, SubscribeBuilderError,
2121
SubscribeCommand, SubscribeCommandBuilder, UnsubscribeCommand,
2222
};
23-
pub use engine::{MqttEngine, MqttEvent};
23+
pub use engine::{MqttEngine, MqttEvent, MqttMessage};
2424
pub use error::{MqttClientError, MqttClientResult};
2525
pub use no_io_client::NoIoMqttClient;
2626
pub use opts::{MqttClientOptions, MqttClientOptionsBuilder};

src/mqtt_client/tokio_async_client.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,14 @@ use super::transport::{BoxedTransport, TcpTransport, Transport};
1818

1919
use crate::mqtt_serde::control_packet::MqttPacket;
2020
use crate::mqtt_serde::mqttv5::common::properties::Property;
21-
use crate::mqtt_serde::mqttv5::publishv5::MqttPublish;
2221

2322
use crate::mqtt_serde::parser::ParseError;
2423

2524
use super::client::{
2625
AuthResult, ConnectionResult, PingResult, PublishResult, SubscribeResult, UnsubscribeResult,
2726
};
2827
use super::commands::{PublishCommand, SubscribeCommand, UnsubscribeCommand};
29-
use super::engine::{MqttEngine, MqttEvent};
28+
use super::engine::{MqttEngine, MqttEvent, MqttMessage};
3029
use super::error::MqttClientError;
3130
use super::opts::MqttClientOptions;
3231

@@ -44,7 +43,7 @@ pub enum TokioMqttEvent {
4443
/// Unsubscription completed
4544
Unsubscribed(UnsubscribeResult),
4645
/// Incoming message received from broker
47-
MessageReceived(MqttPublish),
46+
MessageReceived(MqttMessage),
4847
/// Ping response received
4948
PingResponse(PingResult),
5049
/// Error occurred during operation (enhanced with MqttClientError)
@@ -99,7 +98,7 @@ pub trait TokioMqttEventHandler: Send + Sync {
9998
}
10099

101100
/// Called when an incoming publish message is received
102-
async fn on_message_received(&mut self, publish: &MqttPublish) {
101+
async fn on_message_received(&mut self, publish: &MqttMessage) {
103102
let _ = publish;
104103
}
105104

@@ -2498,7 +2497,7 @@ mod config_builder_tests {
24982497
async fn on_published(&mut self, _result: &PublishResult) {}
24992498
async fn on_subscribed(&mut self, _result: &SubscribeResult) {}
25002499
async fn on_unsubscribed(&mut self, _result: &UnsubscribeResult) {}
2501-
async fn on_message_received(&mut self, _publish: &MqttPublish) {}
2500+
async fn on_message_received(&mut self, _publish: &MqttMessage) {}
25022501
async fn on_ping_response(&mut self, _result: &PingResult) {}
25032502
async fn on_error(&mut self, _error: &MqttClientError) {}
25042503
async fn on_connection_lost(&mut self) {}

0 commit comments

Comments
 (0)