Client

Struct Client 

pub struct Client<S> {
    state: ConnectionState,
    session: S,
    capabilities: ServerCapabilities,
    keep_alive: u16,
    send_quota: u16,
    recv_quota: u16,
    recv_max: u16,
    next_packet_id: PacketId,
    clean_start: bool,
    inbound_alias_max: Option<NonZeroU16>,
}
Expand description

Sans-io MQTT v5 client state machine.

The caller is responsible for:

  • Encoding outgoing packets and writing them to the transport.
  • Decoding incoming packets and feeding them to handle_packet.
  • Driving timers for keep-alive (see keep_alive).

Fields§

§state: ConnectionState§session: S§capabilities: ServerCapabilities§keep_alive: u16

Keep-alive interval in seconds as negotiated.

§send_quota: u16

Number of QoS > 0 publishes we can still send before hitting the server’s Receive Maximum.

§recv_quota: u16

Number of QoS > 0 messages the client can still accept from the server before the server would violate our Receive Maximum.

§recv_max: u16

The Receive Maximum value we advertise in CONNECT (§3.1.2.11.4). u16::MAX (65 535) means we never sent the property.

§next_packet_id: PacketId

Monotonic packet ID counter (1..=65535, wraps around skipping 0).

§clean_start: bool

Whether the last CONNECT used Clean Start = 1.

§inbound_alias_max: Option<NonZeroU16>

The Topic Alias Maximum we advertise in CONNECT (§3.1.2.11.5). None (the default) means inbound topic aliases are not permitted.

Implementations§

§

impl<S: SessionState> Client<S>

pub fn poll_transmit<B, A>( &mut self, out: &mut PacketWriter<B>, aliases: &mut A, on_event: &mut dyn FnMut(TransmitEvent), )

Drains pending SUBSCRIBE/UNSUBSCRIBE groups, then the outbox and pending PUBRELs, onto out: the single outbound transmit path. Subscriptions go first so they precede publishes accepted together with them.

Resolves topic aliases via aliases, enforces the server’s Maximum Packet Size (§3.1.2.11.6), and stays within the send quota. Every outcome is reported through on_event; an over-large packet (or whole group) is dropped as TooLarge. If out cannot accept a packet (fixed-capacity buffer full) the drain stops and retries on the next call.

fn drain_subscription_groups<B>( &mut self, out: &mut PacketWriter<B>, max_packet_size: Option<u32>, on_event: &mut dyn FnMut(TransmitEvent), )
where B: ByteBuffer,

Sends every pending SUBSCRIBE/UNSUBSCRIBE group not already in flight, oldest first, marking each in flight once written. A group exceeding max_packet_size can never be sent: it is removed and reported as TooLarge so it cannot wedge the queue.

§

impl<S: SessionState> Client<S>

pub fn new(session: S) -> Self

Creates a new client with the given session state backend.

pub const fn connection_state(&self) -> ConnectionState

Current connection state.

pub const fn capabilities(&self) -> &ServerCapabilities

Server capabilities from the most recent CONNACK.

pub const fn keep_alive(&self) -> u16

Effective keep-alive interval in seconds.

pub const fn send_quota(&self) -> u16

Remaining send quota for QoS > 0 publishes.

pub const fn session(&self) -> &S

Shared reference to the session state backend.

pub const fn session_mut(&mut self) -> &mut S

Mutable reference to the session state backend.

pub fn connect_sent(&mut self, connect: &Connect<'_>) -> Result<(), ClientError>

Records that connect has been sent.

Mirrors the Clean Start flag, keep-alive, Receive Maximum (§3.1.2.11.3), and Topic Alias Maximum (§3.1.2.11.5) from the packet that actually went on the wire.

§Errors

Returns ClientError::InvalidState if the client is not disconnected.

pub fn connection_lost(&mut self)

Notifies the state machine that the transport has been lost.

Resets connection-level state (quotas, capabilities) while preserving session state for reconnection. In-flight SUBSCRIBE/UNSUBSCRIBE entries are kept and re-sent on the next connect: the per-connection in-flight markers are cleared by reset_in_flight when the next CONNACK arrives.

pub fn session_lost(&mut self, on_failed_pubrel: &mut dyn FnMut(PacketId))

Discards the session state the server forgot (§4.1).

Removes every PUBREL-pending QoS 2 flow (reporting each id through on_failed_pubrel so the driver can fail its future), resets outbox was_sent flags (DUP = 0), and clears incoming QoS 2 tracking. Confirmed subscriptions are preserved; re-issuing them is the driver’s policy.

The I/O driver must call this on a CONNACK with session_present: false, before draining the session onto the new connection.

pub fn handle_packet<'a>( &mut self, packet: &Packet<'a>, ) -> Result<HandleOutcome<'a>, ClientError>

Processes an incoming decoded packet from the server.

Protocol violations by the server are reported as a Response::Disconnect to send (§4.13), not as an error.

§Errors

Returns ClientError::InvalidState if the packet is not valid in the current connection state (e.g. a CONNACK while not connecting).

fn handle_connack<'a>( &mut self, connack: &Connack<'a>, ) -> Result<HandleOutcome<'a>, ClientError>

fn parse_capabilities(props: &ConnackProperties) -> ServerCapabilities

fn handle_publish<'a>( &mut self, publish: &Publish<'a>, ) -> Result<HandleOutcome<'a>, ClientError>

fn require_connected(&self) -> Result<(), ClientError>

Errors with ClientError::InvalidState unless the client is currently connected.

fn handle_puback<'a>( &mut self, ack: Ack<'_>, ) -> Result<HandleOutcome<'a>, ClientError>

fn handle_pubrec<'a>( &mut self, ack: Ack<'_>, ) -> Result<HandleOutcome<'a>, ClientError>

fn handle_pubrel<'a>( &mut self, ack: Ack<'_>, ) -> Result<HandleOutcome<'a>, ClientError>

fn handle_pubcomp<'a>( &mut self, ack: Ack<'_>, ) -> Result<HandleOutcome<'a>, ClientError>

fn handle_suback<'a>( &mut self, suback: &Suback<'a>, ) -> Result<HandleOutcome<'a>, ClientError>

fn handle_unsuback<'a>( &mut self, unsuback: &Unsuback<'a>, ) -> Result<HandleOutcome<'a>, ClientError>

fn handle_pingresp<'a>(&self) -> Result<HandleOutcome<'a>, ClientError>

const fn handle_disconnect<'a>( &mut self, disconnect: &Disconnect<'a>, ) -> Result<HandleOutcome<'a>, ClientError>

const fn handle_auth<'a>(&mut self) -> Result<HandleOutcome<'a>, ClientError>

pub fn prepare_publish( &mut self, qos: QoS, topic: &Topic, payload: &[u8], retain: bool, properties: &PublishProperties, ) -> Result<PacketId, ClientError>

Allocates a packet identifier and stores an outgoing QoS 1 or QoS 2 publish in the session for potential retransmission.

Returns the allocated packet_id. The caller must construct and send the PUBLISH packet using this ID. The packet_id doubles as the stable handle the driver uses to correlate the eventual PUBACK/PUBCOMP with the user-facing completion future (§4.4).

§Errors

Returns ClientError::InvalidState if not connected, ClientError::InvalidQoS if qos is QoS::AtMostOnce, ClientError::QoSNotSupported or ClientError::RetainNotAvailable if the server forbids the request, or ClientError::PacketIdExhausted if all packet identifiers are in use.

This does not consume send quota: the message is stored in the outbox and the send quota is consumed only when it is drained onto the wire by poll_transmit, so the Receive Maximum bounds in-flight messages rather than how many may be queued.

pub fn store_offline_publish( &mut self, qos: QoS, topic: &Topic, payload: &[u8], retain: bool, properties: &PublishProperties, ) -> Result<PacketId, ClientError>

Stores an outgoing QoS 1 or QoS 2 publish while not connected, so it can be drained when a connection is next established.

Unlike prepare_publish, this works in any connection state and applies no capability checks (the server’s are unknown while offline); the message is recorded as durable session state immediately. qos must be QoS::AtLeastOnce or QoS::ExactlyOnce.

§Errors

Returns ClientError::InvalidQoS if qos is QoS::AtMostOnce, or ClientError::PacketIdExhausted if all packet identifiers are in use.

fn store_publish_entry( &mut self, qos: QoS, topic: &Topic, payload: &[u8], retain: bool, properties: &PublishProperties, ) -> Result<PacketId, ClientError>

Allocates a packet id and records an outbox entry, the shared core of the connected and offline publish-store paths.

pub fn prepare_subscribe<'a>( &mut self, filters: impl IntoIterator<Item = (&'a TopicFilter, SubscriptionOptions)>, subscription_id: Option<u32>, ) -> Result<PacketId, ClientError>

Allocates a packet identifier for a SUBSCRIBE and records each filter as an in-flight subscription under it.

filters are the topic filters and their options; subscription_id is the optional SUBSCRIBE-level identifier. The caller builds and sends the SUBSCRIBE using the returned id; the entries resolve when handle_packet sees the matching SUBACK.

§Errors

Returns ClientError::InvalidState if not connected, or ClientError::PacketIdExhausted if all identifiers are in use.

pub fn store_offline_subscribe<'a>( &mut self, filters: impl IntoIterator<Item = (&'a TopicFilter, SubscriptionOptions)>, subscription_id: Option<u32>, ) -> Result<PacketId, ClientError>

Records an in-flight SUBSCRIBE while not connected, so it is sent when a connection is next established.

Like prepare_subscribe but works in any connection state and applies no capability checks (the server’s are unknown while offline).

§Errors

Returns ClientError::PacketIdExhausted if all identifiers are in use.

fn record_subscribe<'a>( &mut self, require_connected: bool, filters: impl IntoIterator<Item = (&'a TopicFilter, SubscriptionOptions)>, subscription_id: Option<u32>, ) -> Result<PacketId, ClientError>

Allocates a packet id and records each filter as an in-flight SUBSCRIBE, the shared core of the connected (prepare_subscribe) and offline (store_offline_subscribe) paths; require_connected gates the connected variant on ConnectionState::Connected.

pub fn prepare_unsubscribe<'a>( &mut self, filters: impl IntoIterator<Item = &'a TopicFilter>, ) -> Result<PacketId, ClientError>

Allocates a packet identifier for an UNSUBSCRIBE and records each filter as in-flight unsubscribing under it.

The entries resolve when handle_packet sees the matching UNSUBACK.

§Errors

Returns ClientError::InvalidState if not connected, or ClientError::PacketIdExhausted if all identifiers are in use.

pub fn store_offline_unsubscribe<'a>( &mut self, filters: impl IntoIterator<Item = &'a TopicFilter>, ) -> Result<PacketId, ClientError>

Records an in-flight UNSUBSCRIBE while not connected.

§Errors

Returns ClientError::PacketIdExhausted if all identifiers are in use.

fn record_unsubscribe<'a>( &mut self, require_connected: bool, filters: impl IntoIterator<Item = &'a TopicFilter>, ) -> Result<PacketId, ClientError>

Allocates a packet id and records each filter as an in-flight UNSUBSCRIBE, the shared core of the connected (prepare_unsubscribe) and offline (store_offline_unsubscribe) paths.

pub fn cancel_outgoing_qos1(&mut self, packet_id: PacketId)

Cancels a QoS 1 publish previously prepared by prepare_publish.

Removes the session entry. Send quota is restored only if the entry had already been put on the wire, since a prepared-but-never-drained publish consumed no slot; crediting it would let the in-flight window exceed the server’s Receive Maximum (§4.9). Use when the publish failed to be enqueued/transmitted and the driver wants to release the reservation without going through the wire/PUBACK round trip.

pub fn cancel_outgoing_qos2(&mut self, packet_id: PacketId)

Cancels a QoS 2 publish previously prepared by prepare_publish.

Removes the session entry. As with cancel_outgoing_qos1, send quota is restored only if the entry had already been put on the wire.

pub const fn check_subscribe_capabilities( &self, has_wildcard: bool, has_sub_id: bool, has_shared: bool, ) -> Result<(), ClientError>

Checks whether a subscribe operation is compatible with server capabilities.

§Errors

Returns an error if the subscribe would violate a server capability.

pub fn drain_outbox<F>(&mut self, send: F)

Drains every outbox publish not yet on the wire this connection through send, in packet-id order, consuming one unit of send quota per DrainAction::Sent and stopping when the quota is exhausted (§4.9).

This is the lower-level primitive behind poll_transmit: fresh publishes, retransmits after a resume, and the post-reconnect flush all funnel through it, so the in-flight window can never exceed the server’s Receive Maximum. The caller’s send does the wire work and returns a DrainAction: Sent consumes quota and marks the entry in flight, Discard drops it (the caller has failed its future), and Stop leaves it for a later drain (e.g. the output buffer is full). The client owns the quota, the DUP flag, and the in-flight marker.

pub fn drain_pubrel<F>(&mut self, send: F)
where F: FnMut(PacketId) -> DrainAction,

Resends PUBREL for every QoS 2 publish awaiting PUBCOMP that has not gone out this connection (only relevant after a session resume), through send, consuming send quota like drain_outbox.

fn alloc_packet_id(&mut self) -> Result<PacketId, ClientError>

const fn increment_send_quota(&mut self)

Auto Trait Implementations§

§

impl<S> Freeze for Client<S>
where S: Freeze,

§

impl<S> RefUnwindSafe for Client<S>
where S: RefUnwindSafe,

§

impl<S> Send for Client<S>
where S: Send,

§

impl<S> Sync for Client<S>
where S: Sync,

§

impl<S> Unpin for Client<S>
where S: Unpin,

§

impl<S> UnwindSafe for Client<S>
where S: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.