blackbull.mqtt.messages¶
blackbull.mqtt.messages
¶
MQTT 5.0 control-packet codec — Sprint 52.
Level-A (pure-data) layer for the blackbull-mqtt broker sidecar: the 15
MQTT 5.0 control packets as frozen dataclasses, a wire encoder/decoder, the
MQTT 5.0 property system, reason codes, and the topic-filter matching
algorithm. No I/O and no broker state live here — that is the job of
:mod:blackbull.mqtt.broker and :mod:blackbull.mqtt.connection.
MQTT Version 5.0, OASIS Standard
https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html
Decoder return contract¶
:func:decode_packet returns the decoded message object. Every message also
unpacks into (message, bytes_consumed) so a caller walking a buffer of
concatenated packets can advance its offset::
msg = decode_packet(buf) # attribute access / isinstance
msg, consumed = decode_packet(buf) # buffer-walking
This dual ergonomics is provided by :meth:MQTTMessage.__iter__; the consumed
count is recorded on the instance during decode.
ConnectFlags
¶
Bases: IntFlag
Single-bit flags in the CONNECT flags byte (§3.1.2.3).
The Will QoS field is the two-bit subfield at :data:WILL_QOS_SHIFT
(mask :data:WILL_QOS_MASK), not a flag here.
IncompletePacket
¶
Bases: Exception
The buffer does not yet hold a complete packet — read more bytes.
MQTTDecodeError
¶
Bases: ValueError
A buffer could not be decoded as a valid MQTT control packet.
MQTTMessage
¶
Base for all MQTT control-packet dataclasses.
Provides the dual decode contract: a decoded message unpacks into
(message, bytes_consumed). The byte count is set by
:func:decode_packet via :meth:_set_consumed; messages built by hand
report 0.
MQTTPacketType
¶
Bases: IntEnum
The 15 MQTT 5.0 control packet types (§2.1.1 Table 2-1).
MQTTReasonCode
¶
Bases: int
An MQTT 5.0 reason code (§2.4).
A thin int subclass so any byte value (0-255) is representable without
raising — undefined codes report name == 'Unknown'. Codes < 0x80
are success/normal; >= 0x80 are errors (§2.4).
PropertyInfo
¶
Bases: NamedTuple
Static description of one MQTT 5.0 property identifier (§2.2.2.2).
ProtocolLevel
¶
Bases: IntEnum
CONNECT Protocol Level (§3.1.2.2). This broker speaks V5_0.
PublishFlagBits
¶
Bases: IntFlag
Single-bit flags in the PUBLISH fixed header (§3.3.1).
QoS is the two-bit subfield at :data:PUBLISH_QOS_SHIFT.
PublishFlags
¶
Bases: NamedTuple
Decoded PUBLISH fixed-header flags (§3.3.1).
ReasonCode
¶
Bases: IntEnum
The subset of §2.4 reason codes the broker references by name.
This is the single definition of these values; their human-readable
names live once in :data:_REASON_CODE_NAMES (the full §2.4 registry used
by :class:MQTTReasonCode). Importers (blackbull.mqtt.broker,
blackbull.mqtt.connection) use these members instead of redeclaring raw
hex, so a code can never drift between modules.
SubscriptionOptions
¶
Bases: IntFlag
Single-bit options in the SUBSCRIBE options byte (§3.8.3.1).
decode_packet(data)
¶
Decode the first MQTT control packet in data.
Returns the message; it also unpacks into (message, bytes_consumed).
Raises :class:IncompletePacket if the buffer is short, or
:class:MQTTDecodeError if the bytes are not a valid packet.
decode_properties(data, offset=0)
¶
§2.2.2 — Decode a properties block; return (props, consumed).
consumed counts the Property Length prefix plus the property bytes.
decode_publish_flags(flags_byte)
¶
§3.3.1 — DUP (bit 3), QoS (bits 2-1), RETAIN (bit 0).
decode_variable_byte_integer(data)
¶
§1.5.5 — Decode a Variable Byte Integer; return (value, consumed).
Trailing bytes beyond the integer are ignored (the caller tracks them).
encode_packet(message)
¶
Serialize an MQTT control packet to its wire representation.
encode_properties(properties)
¶
§2.2.2 — Encode a properties dict to Property Length + body.
encode_variable_byte_integer(value)
¶
§1.5.5 — Encode an int (0..268,435,455) as a Variable Byte Integer.
extract_flags(first_byte)
¶
§2.1.1 — Flags occupy bits 3-0 of the first fixed-header byte.
extract_packet_type(first_byte)
¶
§2.1.1 — Packet type is bits 7-4 of the first fixed-header byte.
Type 0 is Reserved/forbidden (§2.1.1 Table 2-1) and raises ValueError.
get_property_info(identifier)
¶
Return the :class:PropertyInfo for a property identifier, or None.
topic_matches_filter(topic, filter_str)
¶
§4.7 — Return True if topic matches subscription filter_str.
Handles + (single level), # (multi level, terminal), the $
leading-character rule (§4.7.2), and $share/<group>/<filter> shared
subscriptions (§4.8.2).
validate_topic_filter(filter_str)
¶
§4.7.1 — Validate a subscription Topic Filter.
Returns True when valid; raises :class:ValueError describing the first
rule violated. Enforces single-# / terminal-# / whole-level
wildcard rules (§4.7.1.2-3) and the $share share-name rule (§4.8.2).
validate_topic_name(topic)
¶
§4.7.1 — A Topic Name (used in PUBLISH) is literal: non-empty, no
wildcards (+/#) and no null character. Leading/trailing slashes
are permitted (they denote zero-length levels).