use crate::mqtt_client::commands::{PublishCommand, SubscribeCommand, UnsubscribeCommand};
use crate::mqtt_client::engine::{MqttEngine, MqttEvent};
use crate::mqtt_client::error::MqttClientError;
use crate::mqtt_client::opts::MqttClientOptions;
use crate::mqtt_serde::mqttv5::common::properties::Property;
use std::time::Instant;
pub struct NoIoMqttClient {
engine: MqttEngine,
}
impl NoIoMqttClient {
pub fn new(options: MqttClientOptions) -> Self {
Self {
engine: MqttEngine::new(options),
}
}
pub fn handle_incoming(&mut self, data: &[u8]) -> Vec<MqttEvent> {
self.engine.handle_incoming(data)
}
pub fn take_outgoing(&mut self) -> Vec<u8> {
self.engine.take_outgoing()
}
pub fn handle_tick(&mut self, now: Instant) -> Vec<MqttEvent> {
self.engine.handle_tick(now)
}
pub fn next_tick_at(&self) -> Option<Instant> {
self.engine.next_tick_at()
}
pub fn take_events(&mut self) -> Vec<MqttEvent> {
self.engine.take_events()
}
pub fn connect(&mut self) {
self.engine.connect();
}
pub fn publish(&mut self, command: PublishCommand) -> Result<Option<u16>, MqttClientError> {
self.engine.publish(command)
}
pub fn subscribe(&mut self, command: SubscribeCommand) -> Result<u16, MqttClientError> {
self.engine.subscribe(command)
}
pub fn unsubscribe(&mut self, command: UnsubscribeCommand) -> Result<u16, MqttClientError> {
self.engine.unsubscribe(command)
}
pub fn ping(&mut self) {
self.engine.send_ping();
}
pub fn disconnect(&mut self) {
self.engine.disconnect();
}
pub fn auth(&mut self, reason_code: u8, properties: Vec<Property>) {
self.engine.auth(reason_code, properties);
}
pub fn is_connected(&self) -> bool {
self.engine.is_connected()
}
pub fn mqtt_version(&self) -> u8 {
self.engine.mqtt_version()
}
pub fn options(&self) -> &MqttClientOptions {
self.engine.options()
}
pub fn handle_connection_lost(&mut self) {
self.engine.handle_connection_lost();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_client() {
let options = MqttClientOptions::builder()
.peer("localhost:1883")
.client_id("test_client")
.build();
let client = NoIoMqttClient::new(options);
assert!(!client.is_connected());
assert_eq!(client.mqtt_version(), 5); }
#[test]
fn test_connect_generates_packet() {
let options = MqttClientOptions::builder()
.peer("localhost:1883")
.client_id("test_client")
.build();
let mut client = NoIoMqttClient::new(options);
client.connect();
let outgoing = client.take_outgoing();
assert!(!outgoing.is_empty());
assert_eq!(outgoing[0] & 0xF0, 0x10);
}
#[test]
fn test_handle_connack() {
let options = MqttClientOptions::builder()
.peer("localhost:1883")
.client_id("test_client")
.build();
let mut client = NoIoMqttClient::new(options);
client.connect();
let _ = client.take_outgoing();
let connack = vec![0x20, 0x03, 0x00, 0x00, 0x00];
let events = client.handle_incoming(&connack);
assert!(!events.is_empty(), "Should have received events");
assert!(
matches!(events[0], MqttEvent::Connected(_)),
"First event should be Connected, got: {:?}",
events[0]
);
assert!(client.is_connected());
}
#[test]
fn test_publish_qos0() {
let options = MqttClientOptions::builder()
.peer("localhost:1883")
.client_id("test_client")
.build();
let mut client = NoIoMqttClient::new(options);
client.connect();
let _ = client.take_outgoing();
let connack = vec![0x20, 0x03, 0x00, 0x00, 0x00];
let _ = client.handle_incoming(&connack);
assert!(client.is_connected());
let cmd = PublishCommand::simple("test/topic", b"payload".to_vec(), 0, false);
let result = client.publish(cmd);
assert!(result.is_ok());
assert_eq!(result.unwrap(), None);
let outgoing = client.take_outgoing();
assert!(!outgoing.is_empty());
}
#[test]
fn test_next_tick_at_when_disconnected() {
let options = MqttClientOptions::builder()
.peer("localhost:1883")
.client_id("test_client")
.build();
let client = NoIoMqttClient::new(options);
assert!(client.next_tick_at().is_none());
}
#[test]
fn test_connection_lost() {
let options = MqttClientOptions::builder()
.peer("localhost:1883")
.client_id("test_client")
.build();
let mut client = NoIoMqttClient::new(options);
client.connect();
let _ = client.take_outgoing();
let connack = vec![0x20, 0x03, 0x00, 0x00, 0x00];
let _ = client.handle_incoming(&connack);
assert!(client.is_connected());
client.handle_connection_lost();
assert!(!client.is_connected());
}
}