pub struct MqttPublisher { /* private fields */ }Expand description
Publishes messages to MQTT topics through the shared connection.
The publish is queued into the client session, so Ok means “owned by the session”, not
“broker confirmed”. For QoS 1/2 the client keeps the message until the broker acknowledges
it, across reconnects: a resumed session retransmits it, and a new session sends it again,
where it may arrive twice. Buildable before connect and usable until shutdown; afterwards
every publish reports MqttError::NotConnected.
Headers are sent as MQTT 5 user properties, so non-Rust peers see plain MQTT messages. The
content-type, reply-to and correlation-id headers take the matching first-class
properties (content type, response topic, correlation data), in both directions, and a
message with no headers carries no properties at all. A textual content type
(application/json, any text/ subtype, any +json vendor type) sets the payload format
indicator to 1, and every other one to 0. A header name or value that is not text an MQTT
string carries refuses the publish with MqttError::Publish; the correlation data is binary
on the wire and takes any bytes.
§Examples
Nothing writes the media type for a service: a reply, a deferred retry copy and a plain publish carry the headers something put on them. A service whose peers read the content type property sets it once at the mount site, through a publish transform over the position:
use ruststream::runtime::{Outgoing, Reads};
use ruststream_rumqttc::prelude::*;
use serde::{Deserialize, Serialize};
/// States the media type of every message this position sends, which is what fills the content
/// type property and decides the payload format indicator. It reads nothing about the delivery,
/// so it is generic over the position and mounts on any of them.
struct Json;
impl<K: ContextKind, Options> PublishTransform<K, Options> for Json {
type Destination = Reads;
fn apply(&self, out: &mut Outgoing<'_>, _options: &mut Option<Options>, _cx: &K::View<'_>) {
out.headers_mut().insert("content-type", "application/json");
}
}
#[derive(Deserialize)]
struct Telemetry {
device: String,
temperature: f64,
}
#[derive(Serialize, Outgoing)]
#[outgoing(name = "devices/state")]
struct DeviceState {
device: String,
hot: bool,
}
#[subscriber(MqttFilter::new("devices/+/telemetry"), reply)]
async fn track(telemetry: &Telemetry) -> DeviceState {
DeviceState { device: telemetry.device.clone(), hot: telemetry.temperature > 30.0 }
}
#[ruststream::app]
fn app() -> impl App {
RustStream::new(AppInfo::new("states", "0.1.0")).with_broker(
MqttBroker::new("mqtt://localhost:1883", "states-svc"),
|b| {
// Every reply now carries the content type property and the payload format
// indicator 1, so a peer reads the body as UTF-8 JSON.
b.include(track)
.out_reply(Publish::default())
.transform(Json)
.out_retry(Publish::default())
.to("devices/retry/telemetry");
},
)
}Trait Implementations§
Source§impl Clone for MqttPublisher
impl Clone for MqttPublisher
Source§impl Debug for MqttPublisher
impl Debug for MqttPublisher
Source§impl Publisher for MqttPublisher
impl Publisher for MqttPublisher
Source§type Payload = Take
type Payload = Take
The client keeps the payload: a PUBLISH packet is queued into the session, which holds
the Bytes until the broker acknowledges it.
Source§type Options = MqttPublishOptions
type Options = MqttPublishOptions
QoS, a priority, an ordering key, whatever this
transport lets one message differ from the next in. Read moreAuto Trait Implementations§
impl !RefUnwindSafe for MqttPublisher
impl !UnwindSafe for MqttPublisher
impl Freeze for MqttPublisher
impl Send for MqttPublisher
impl Sync for MqttPublisher
impl Unpin for MqttPublisher
impl UnsafeUnpin for MqttPublisher
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<P> PublishExt for P
impl<P> PublishExt for P
Source§fn message<'a, T>(
&'a self,
value: &'a T,
) -> PublishBuilder<&'a Self, MessageBody<'a, T>, UnnamedCodec, HeadersUnset, <T as OutgoingDestination>::Form>where
T: OutgoingDestination,
fn message<'a, T>(
&'a self,
value: &'a T,
) -> PublishBuilder<&'a Self, MessageBody<'a, T>, UnnamedCodec, HeadersUnset, <T as OutgoingDestination>::Form>where
T: OutgoingDestination,
#[derive(Outgoing)] value, encoded with the crate’s
default codec (name another one with with_codec(..)). A
Serialized value’s bytes leave as they are instead - the wire is
the type’s own (MessageWire), and no codec runs on it. Read moreSource§fn begin(
&self,
) -> impl Future<Output = Result<TransactionScope<'_, Self, UnnamedCodec, AnyDeclared>, Self::Error>> + Sendwhere
Self: Sized + TransactionalPublisher,
fn begin(
&self,
) -> impl Future<Output = Result<TransactionScope<'_, Self, UnnamedCodec, AnyDeclared>, Self::Error>> + Sendwhere
Self: Sized + TransactionalPublisher,
TransactionScope that
owns it. Read moreSource§fn owned_transaction(
&self,
) -> impl Future<Output = Result<TypedTransaction<Self::Transaction, UnnamedCodec, AnyDeclared>, Self::Error>> + Sendwhere
Self: Sized + OwnedTransactions,
fn owned_transaction(
&self,
) -> impl Future<Output = Result<TypedTransaction<Self::Transaction, UnnamedCodec, AnyDeclared>, Self::Error>> + Sendwhere
Self: Sized + OwnedTransactions,
TypedTransaction that owns it. Read more