diff --git a/hbmqtt/mqtt/suback.py b/hbmqtt/mqtt/suback.py new file mode 100644 index 0000000..382a202 --- /dev/null +++ b/hbmqtt/mqtt/suback.py @@ -0,0 +1,53 @@ +# Copyright (c) 2015 Nicolas JOUANIN +# +# See the file license.txt for copying permission. +from hbmqtt.mqtt.packet import MQTTPacket, MQTTFixedHeader, PacketType, PacketIdVariableHeader, MQTTPayload, MQTTVariableHeader +from hbmqtt.errors import HBMQTTException, MQTTException +from hbmqtt.codecs import * + + +class SubackPayload(MQTTPayload): + RETURN_CODE_00 = 0x00 + RETURN_CODE_01 = 0x01 + RETURN_CODE_02 = 0x02 + RETURN_CODE_80 = 0x80 + def __init__(self, return_codes=[]): + super().__init__() + self.return_codes = return_codes + + def to_bytes(self, fixed_header: MQTTFixedHeader, variable_header: MQTTVariableHeader): + out = b'' + for return_code in self.return_codes: + out += int_to_bytes(return_code, 1) + return out + + @classmethod + @asyncio.coroutine + def from_stream(cls, reader: asyncio.StreamReader, fixed_header: MQTTFixedHeader, + variable_header: MQTTVariableHeader): + return_codes = [] + while True: + try: + return_code_byte = yield from read_or_raise(reader, 1) + return_code = bytes_to_int(return_code_byte) + return_codes.append(return_code) + except NoDataException: + break + return cls(return_codes) + + +class SubackPacket(MQTTPacket): + VARIABLE_HEADER = PacketIdVariableHeader + PAYLOAD = SubackPayload + + def __init__(self, fixed: MQTTFixedHeader=None, variable_header: PacketIdVariableHeader=None, payload=None): + if fixed is None: + header = MQTTFixedHeader(PacketType.SUBACK, 0x00) + else: + if fixed.packet_type is not PacketType.SUBACK: + raise HBMQTTException("Invalid fixed packet type %s for SubackPacket init" % fixed.packet_type) + header = fixed + + super().__init__(header) + self.variable_header = variable_header + self.payload = payload diff --git a/tests/mqtt/test_suback.py b/tests/mqtt/test_suback.py new file mode 100644 index 0000000..0c2de76 --- /dev/null +++ b/tests/mqtt/test_suback.py @@ -0,0 +1,32 @@ +# Copyright (c) 2015 Nicolas JOUANIN +# +# See the file license.txt for copying permission. +import unittest + +from hbmqtt.mqtt.suback import SubackPacket, SubackPayload +from hbmqtt.mqtt.packet import PacketIdVariableHeader +from hbmqtt.codecs import * + +class SubscribePacketTest(unittest.TestCase): + def setUp(self): + self.loop = asyncio.new_event_loop() + + def test_from_stream(self): + data = b'\x90\x06\x00\x0a\x00\x01\x02\x80' + stream = asyncio.StreamReader(loop=self.loop) + stream.feed_data(data) + stream.feed_eof() + message = self.loop.run_until_complete(SubackPacket.from_stream(stream)) + self.assertEqual(message.payload.return_codes[0], SubackPayload.RETURN_CODE_00) + self.assertEqual(message.payload.return_codes[1], SubackPayload.RETURN_CODE_01) + self.assertEqual(message.payload.return_codes[2], SubackPayload.RETURN_CODE_02) + self.assertEqual(message.payload.return_codes[3], SubackPayload.RETURN_CODE_80) + + def test_to_stream(self): + variable_header = PacketIdVariableHeader(10) + payload = SubackPayload( + [SubackPayload.RETURN_CODE_00, SubackPayload.RETURN_CODE_01, SubackPayload.RETURN_CODE_02, SubackPayload.RETURN_CODE_80 + ]) + publish = SubackPacket(variable_header=variable_header, payload=payload) + out = publish.to_bytes() + self.assertEqual(out, b'\x90\x06\x00\x0a\x00\x01\x02\x80') \ No newline at end of file