use async_trait::async_trait;
use crate::error::SdkResult;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MqttConnectionState {
Disconnected,
Connecting,
Connected,
Reconnecting,
Disconnecting,
Failed,
}
impl MqttConnectionState {
pub fn can_connect(&self) -> bool {
matches!(self, Self::Disconnected | Self::Failed)
}
pub fn is_connected(&self) -> bool {
matches!(self, Self::Connected)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MqttQoS {
AtMostOnce, AtLeastOnce, ExactlyOnce, }
#[derive(Debug, Clone)]
pub struct MqttMessage {
pub topic: String,
pub payload: Vec<u8>,
pub qos: MqttQoS,
}
impl MqttMessage {
pub fn new(topic: impl Into<String>, payload: Vec<u8>) -> Self {
Self {
topic: topic.into(),
payload,
qos: MqttQoS::AtLeastOnce,
}
}
pub fn with_qos(mut self, qos: MqttQoS) -> Self {
self.qos = qos;
self
}
pub fn payload_string(&self) -> Result<String, std::string::FromUtf8Error> {
String::from_utf8(self.payload.clone())
}
}
#[derive(Debug, Clone)]
pub enum MqttEvent {
Connected,
Disconnected,
Reconnecting { attempt: u32, delay_ms: u64 },
Reconnected,
ConnectionFailed { error: String },
MessageReceived(MqttMessage),
Subscribed { topic: String },
Unsubscribed { topic: String },
Published { topic: String },
Error { error: String },
}
#[derive(Debug, Clone)]
pub struct MqttConfig {
pub broker_url: String,
pub client_id: String,
pub username: Option<String>,
pub password: Option<String>,
pub keep_alive_secs: u64,
pub clean_session: bool,
}
impl Default for MqttConfig {
fn default() -> Self {
Self {
broker_url: "mqtts://localhost:8883".to_string(),
client_id: String::new(),
username: None,
password: None,
keep_alive_secs: 30,
clean_session: true,
}
}
}
#[async_trait]
#[cfg(not(target_arch = "wasm32"))]
pub trait MqttClient: Send + Sync {
async fn connect(&self, config: MqttConfig) -> SdkResult<()>;
async fn disconnect(&self) -> SdkResult<()>;
async fn subscribe(&self, topic: &str, qos: MqttQoS) -> SdkResult<()>;
async fn unsubscribe(&self, topic: &str) -> SdkResult<()>;
async fn publish(&self, message: MqttMessage) -> SdkResult<()>;
fn connection_state(&self) -> MqttConnectionState;
fn is_connected(&self) -> bool {
self.connection_state().is_connected()
}
}
#[async_trait(?Send)]
#[cfg(target_arch = "wasm32")]
pub trait MqttClient {
async fn connect(&self, config: MqttConfig) -> SdkResult<()>;
async fn disconnect(&self) -> SdkResult<()>;
async fn subscribe(&self, topic: &str, qos: MqttQoS) -> SdkResult<()>;
async fn unsubscribe(&self, topic: &str) -> SdkResult<()>;
async fn publish(&self, message: MqttMessage) -> SdkResult<()>;
fn connection_state(&self) -> MqttConnectionState;
fn is_connected(&self) -> bool {
self.connection_state().is_connected()
}
}
#[cfg(not(target_arch = "wasm32"))]
pub trait MqttClientWithEvents: MqttClient {
fn on_event<F>(&self, callback: F)
where
F: Fn(MqttEvent) + Send + Sync + 'static;
}
#[cfg(target_arch = "wasm32")]
pub trait MqttClientWithEvents: MqttClient {
fn on_event<F>(&self, callback: F)
where
F: Fn(MqttEvent) + 'static;
}
#[cfg(not(target_arch = "wasm32"))]
pub trait MqttClientFactory: Send + Sync {
fn create_client(&self) -> Box<dyn MqttClient>;
}
#[cfg(target_arch = "wasm32")]
pub trait MqttClientFactory {
fn create_client(&self) -> Box<dyn MqttClient>;
}