2015-06-17 20:06:11 +00:00
|
|
|
# Copyright (c) 2015 Nicolas JOUANIN
|
|
|
|
#
|
|
|
|
# See the file license.txt for copying permission.
|
2017-08-06 22:46:15 +00:00
|
|
|
import asyncio
|
|
|
|
|
2021-03-14 20:44:41 +00:00
|
|
|
from hbmqtt.mqtt.packet import (
|
|
|
|
MQTTPacket,
|
|
|
|
MQTTFixedHeader,
|
|
|
|
SUBSCRIBE,
|
|
|
|
PacketIdVariableHeader,
|
|
|
|
MQTTPayload,
|
|
|
|
MQTTVariableHeader,
|
|
|
|
)
|
2017-08-06 22:46:15 +00:00
|
|
|
from hbmqtt.errors import HBMQTTException, NoDataException
|
2021-03-14 20:44:41 +00:00
|
|
|
from hbmqtt.codecs import (
|
|
|
|
bytes_to_int,
|
|
|
|
decode_string,
|
|
|
|
encode_string,
|
|
|
|
int_to_bytes,
|
|
|
|
read_or_raise,
|
|
|
|
)
|
2015-06-17 20:06:11 +00:00
|
|
|
|
|
|
|
|
|
|
|
class SubscribePayload(MQTTPayload):
|
2017-10-10 14:09:55 +00:00
|
|
|
|
2021-03-14 20:44:41 +00:00
|
|
|
__slots__ = ("topics",)
|
2017-10-10 14:09:55 +00:00
|
|
|
|
2021-03-15 09:59:13 +00:00
|
|
|
def __init__(self, topics=None):
|
2015-06-17 20:06:11 +00:00
|
|
|
super().__init__()
|
2021-03-15 09:59:13 +00:00
|
|
|
self.topics = topics or []
|
2015-06-17 20:06:11 +00:00
|
|
|
|
2021-03-14 21:16:51 +00:00
|
|
|
def to_bytes(
|
|
|
|
self, fixed_header: MQTTFixedHeader, variable_header: MQTTVariableHeader
|
|
|
|
):
|
2021-03-14 20:44:41 +00:00
|
|
|
out = b""
|
2015-06-17 20:06:11 +00:00
|
|
|
for topic in self.topics:
|
2015-09-01 20:42:23 +00:00
|
|
|
out += encode_string(topic[0])
|
|
|
|
out += int_to_bytes(topic[1], 1)
|
2015-06-17 20:06:11 +00:00
|
|
|
return out
|
|
|
|
|
|
|
|
@classmethod
|
2021-03-14 20:44:41 +00:00
|
|
|
async def from_stream(
|
|
|
|
cls,
|
|
|
|
reader: asyncio.StreamReader,
|
|
|
|
fixed_header: MQTTFixedHeader,
|
|
|
|
variable_header: MQTTVariableHeader,
|
|
|
|
):
|
2015-06-17 20:06:11 +00:00
|
|
|
topics = []
|
2015-07-11 20:17:46 +00:00
|
|
|
payload_length = fixed_header.remaining_length - variable_header.bytes_length
|
|
|
|
read_bytes = 0
|
|
|
|
while read_bytes < payload_length:
|
2015-06-17 20:06:11 +00:00
|
|
|
try:
|
2020-12-31 00:16:45 +00:00
|
|
|
topic = await decode_string(reader)
|
|
|
|
qos_byte = await read_or_raise(reader, 1)
|
2015-06-17 20:06:11 +00:00
|
|
|
qos = bytes_to_int(qos_byte)
|
2015-09-01 20:42:23 +00:00
|
|
|
topics.append((topic, qos))
|
2021-03-14 20:44:41 +00:00
|
|
|
read_bytes += 2 + len(topic.encode("utf-8")) + 1
|
2021-03-15 09:59:13 +00:00
|
|
|
except NoDataException:
|
2015-06-17 20:06:11 +00:00
|
|
|
break
|
|
|
|
return cls(topics)
|
|
|
|
|
2015-07-12 12:40:31 +00:00
|
|
|
def __repr__(self):
|
2021-03-14 20:44:41 +00:00
|
|
|
return type(self).__name__ + "(topics={0!r})".format(self.topics)
|
2015-07-12 12:40:31 +00:00
|
|
|
|
2015-06-17 20:06:11 +00:00
|
|
|
|
|
|
|
class SubscribePacket(MQTTPacket):
|
|
|
|
VARIABLE_HEADER = PacketIdVariableHeader
|
|
|
|
PAYLOAD = SubscribePayload
|
|
|
|
|
2021-03-14 20:44:41 +00:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
fixed: MQTTFixedHeader = None,
|
|
|
|
variable_header: PacketIdVariableHeader = None,
|
|
|
|
payload=None,
|
|
|
|
):
|
2015-06-17 20:06:11 +00:00
|
|
|
if fixed is None:
|
2017-08-06 22:05:06 +00:00
|
|
|
header = MQTTFixedHeader(SUBSCRIBE, 0x02) # [MQTT-3.8.1-1]
|
2015-06-17 20:06:11 +00:00
|
|
|
else:
|
2015-07-31 21:01:32 +00:00
|
|
|
if fixed.packet_type is not SUBSCRIBE:
|
2021-03-14 20:44:41 +00:00
|
|
|
raise HBMQTTException(
|
2021-03-14 21:16:51 +00:00
|
|
|
"Invalid fixed packet type %s for SubscribePacket init"
|
|
|
|
% fixed.packet_type
|
2021-03-14 20:44:41 +00:00
|
|
|
)
|
2015-06-17 20:06:11 +00:00
|
|
|
header = fixed
|
|
|
|
|
|
|
|
super().__init__(header)
|
|
|
|
self.variable_header = variable_header
|
|
|
|
self.payload = payload
|
2015-06-21 20:17:41 +00:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def build(cls, topics, packet_id):
|
|
|
|
v_header = PacketIdVariableHeader(packet_id)
|
|
|
|
payload = SubscribePayload(topics)
|
2017-08-06 22:05:06 +00:00
|
|
|
return SubscribePacket(variable_header=v_header, payload=payload)
|