use bytes::Bytes;
use rumqttc::v5::mqttbytes::valid_topic;
use ruststream::{OutgoingMessage, PairError, PublishPolicy, Publisher};
use crate::broker::{ConnectedMqttBroker, CoreCell};
use crate::error::MqttError;
use crate::filter::Qos;
use crate::message::to_publish_properties;
#[derive(Clone)]
pub struct MqttPublisher {
cell: CoreCell,
qos: Qos,
retain: bool,
}
impl std::fmt::Debug for MqttPublisher {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MqttPublisher")
.field("qos", &self.qos)
.field("retain", &self.retain)
.finish_non_exhaustive()
}
}
impl MqttPublisher {
pub(crate) fn new(cell: CoreCell, qos: Qos, retain: bool) -> Self {
Self { cell, qos, retain }
}
}
impl Publisher for MqttPublisher {
type Error = MqttError;
async fn publish(&self, msg: OutgoingMessage<'_>) -> Result<(), Self::Error> {
let core = self.cell.get().ok_or(MqttError::NotConnected)?;
core.shared.ensure_open()?;
if !valid_topic(msg.name()) {
return Err(MqttError::Publish {
topic: msg.name().to_owned(),
reason: "not a valid MQTT topic (wildcards are subscribe-only)".to_owned(),
});
}
let payload = Bytes::copy_from_slice(msg.payload());
let outcome = match to_publish_properties(&msg) {
Some(properties) => {
core.client
.publish_bytes_with_properties(
msg.name(),
self.qos.to_client(),
self.retain,
payload,
properties,
)
.await
}
None => {
core.client
.publish_bytes(msg.name(), self.qos.to_client(), self.retain, payload)
.await
}
};
outcome.map_err(|_| MqttError::Publish {
topic: msg.name().to_owned(),
reason: "the mqtt connection task has shut down".to_owned(),
})
}
}
#[derive(Debug, Clone, Copy, Default)]
#[must_use]
pub struct MqttPublish {
qos: Qos,
retain: bool,
}
impl MqttPublish {
pub fn qos(mut self, qos: Qos) -> Self {
self.qos = qos;
self
}
pub fn retain(mut self, retain: bool) -> Self {
self.retain = retain;
self
}
}
impl MqttPublish {
pub(crate) fn into_publisher(self, cell: CoreCell) -> MqttPublisher {
MqttPublisher::new(cell, self.qos, self.retain)
}
}
impl PublishPolicy<ConnectedMqttBroker> for MqttPublish {
type Live = MqttPublisher;
async fn pair(self, connected: &ConnectedMqttBroker) -> Result<Self::Live, PairError> {
Ok(connected.publisher_with(self))
}
}