示例#1
0
 def acknowledge_delivery(self):
     try:
         self._ack_waiter.set_result(True)
     except MachineError:
         raise HBMQTTException(
             'Invalid call to method acknowledge_delivery on in-flight messages with QOS=%d, state=%s'
             % (self.qos, self.state))
示例#2
0
文件: __init__.py 项目: phlet/jarvis
def packet_class(fixed_header: MQTTFixedHeader):
    try:
        cls = packet_dict[fixed_header.packet_type]
        return cls
    except KeyError:
        raise HBMQTTException("Unexpected packet Type '%s'" %
                              fixed_header.packet_type)
示例#3
0
    def mqtt_publish(self, topic, data, qos, retain, ack_timeout=None):
        """
        Sends a MQTT publish message and manages messages flows.
        This methods doesn't return until the message has been acknowledged by receiver or timeout occur
        :param topic: MQTT topic to publish
        :param data:  data to send on topic
        :param qos: quality of service to use for message flow. Can be QOS_0, QOS_1 or QOS_2
        :param retain: retain message flag
        :param ack_timeout: acknowledge timeout. If set, this method will return a TimeOut error if the acknowledgment
        is not completed before ack_timeout second
        :return: ApplicationMessage used during inflight operations
        """
        if qos in (QOS_1, QOS_2):
            packet_id = self.session.next_packet_id
            if packet_id in self.session.inflight_out:
                raise HBMQTTException(
                    "A message with the same packet ID '%d' is already in flight"
                    % packet_id)
        else:
            packet_id = None

        message = OutgoingApplicationMessage(packet_id, topic, qos, data,
                                             retain)
        # Handle message flow
        if ack_timeout is not None and ack_timeout > 0:
            yield from asyncio.wait_for(self._handle_message_flow(message),
                                        ack_timeout,
                                        loop=self._loop)
        else:
            yield from self._handle_message_flow(message)

        return message
示例#4
0
 def sent_pubcomp(self):
     try:
         self.complete()
         self.pubcomp_ts = datetime.now()
     except MachineError:
         raise HBMQTTException(
             'Invalid call to method sent_pubrec on in-flight messages with QOS=%d, state=%s'
             % (self.qos, self.state))
示例#5
0
 def received_publish(self):
     try:
         self.publish()
         self.publish_ts = datetime.now()
     except MachineError:
         raise HBMQTTException(
             'Invalid call to method received_publish on in-flight messages with QOS=%d, state=%s'
             % (self.qos, self.state))
示例#6
0
 def received_pubrel(self):
     try:
         self.release()
         self.pubrel_ts = datetime.now()
         self._pubrel_waiter.set_result(True)
     except MachineError:
         raise HBMQTTException(
             'Invalid call to method received_pubcomp on in-flight messages with QOS=%d, state=%s'
             % (self.qos, self.state))
示例#7
0
    def next_packet_id(self):
        self._packet_id += 1
        if self._packet_id > 65535:
            self._packet_id = 1
        while self._packet_id in self.inflight_in or self._packet_id in self.inflight_out:
            self._packet_id += 1
            if self._packet_id > 65535:
                raise HBMQTTException("More than 65525 messages pending. No free packet ID")

        return self._packet_id
示例#8
0
 def received_puback(self):
     try:
         self.acknowledge()
         self.puback_ts = datetime.now()
         self.cancel_ack_timeout()
         self._ack_waiter.set_result(True)
     except MachineError:
         raise HBMQTTException(
             'Invalid call to method received_puback on in-flight messages with QOS=%d, state=%s'
             % (self.qos, self.state))
示例#9
0
文件: pubrel.py 项目: claws/hbmqtt
 def __init__(self, fixed: MQTTFixedHeader=None, variable_header: PacketIdVariableHeader=None):
     if fixed is None:
         header = MQTTFixedHeader(PUBREL, 0x02)  # [MQTT-3.6.1-1]
     else:
         if fixed.packet_type is not PUBREL:
             raise HBMQTTException("Invalid fixed packet type %s for PubrelPacket init" % fixed.packet_type)
         header = fixed
     super().__init__(header)
     self.variable_header = variable_header
     self.payload = None
示例#10
0
 def received_pubrec(self):
     try:
         self.receive()
         self.pubrec_ts = datetime.now()
         self.publish_packet = None  # Discard message
         self.reset_ack_timeout()
     except MachineError:
         raise HBMQTTException(
             'Invalid call to method received_pubrec on in-flight messages with QOS=%d, state=%s'
             % (self.qos, self.state))
示例#11
0
 def __init__(self, fixed: MQTTFixedHeader=None, variable_header: PacketIdVariableHeader=None):
     if fixed is None:
         header = MQTTFixedHeader(PUBCOMP, 0x00)
     else:
         if fixed.packet_type is not PUBCOMP:
             raise HBMQTTException("Invalid fixed packet type %s for PubcompPacket init" % fixed.packet_type)
         header = fixed
     super().__init__(header)
     self.variable_header = variable_header
     self.payload = None
示例#12
0
文件: subscribe.py 项目: phlet/jarvis
    def __init__(self, fixed: MQTTFixedHeader=None, variable_header: PacketIdVariableHeader=None, payload=None):
        if fixed is None:
            header = MQTTFixedHeader(SUBSCRIBE, 0x02) # [MQTT-3.8.1-1]
        else:
            if fixed.packet_type is not SUBSCRIBE:
                raise HBMQTTException("Invalid fixed packet type %s for SubscribePacket init" % fixed.packet_type)
            header = fixed

        super().__init__(header)
        self.variable_header = variable_header
        self.payload = payload
示例#13
0
 def retry_publish(self):
     try:
         self.publish()
         self._ack_waiter = asyncio.Future(loop=self._loop)
         self.nb_retries += 1
         self.publish_ts = datetime.now()
         self.start_ack_timeout()
     except MachineError:
         raise HBMQTTException(
             'Invalid call to method retry_publish on in-flight messages with QOS=%d, state=%s'
             % (self.qos, self.state))
示例#14
0
 def __init__(self, fixed: MQTTFixedHeader = None):
     if fixed is None:
         header = MQTTFixedHeader(PINGREQ, 0x00)
     else:
         if fixed.packet_type is not PINGREQ:
             raise HBMQTTException(
                 "Invalid fixed packet type %s for PingReqPacket init" %
                 fixed.packet_type)
         header = fixed
     super().__init__(header)
     self.variable_header = None
     self.payload = None
示例#15
0
 def __init__(self, fixed: MQTTFixedHeader = None):
     if fixed is None:
         header = MQTTFixedHeader(DISCONNECT, 0x00)
     else:
         if fixed.packet_type is not DISCONNECT:
             raise HBMQTTException(
                 "Invalid fixed packet type %s for DisconnectPacket init" %
                 fixed.packet_type)
         header = fixed
     super().__init__(header)
     self.variable_header = None
     self.payload = None
示例#16
0
 def __init__(self,
              fixed: MQTTFixedHeader = None,
              variable_header: ConnackVariableHeader = None,
              payload=None):
     if fixed is None:
         header = MQTTFixedHeader(CONNACK, 0x00)
     else:
         if fixed.packet_type is not CONNACK:
             raise HBMQTTException(
                 "Invalid fixed packet type %s for ConnackPacket init" %
                 fixed.packet_type)
         header = fixed
     super().__init__(header)
     self.variable_header = variable_header
     self.payload = None
示例#17
0
 def _handle_message_flow(self, app_message):
     """
     Handle protocol flow for incoming and outgoing messages, depending on service level and according to MQTT
     spec. paragraph 4.3-Quality of Service levels and protocol flows
     :param app_message: PublishMessage to handle
     :return: nothing.
     """
     if app_message.qos == QOS_0:
         yield from self._handle_qos0_message_flow(app_message)
     elif app_message.qos == QOS_1:
         yield from self._handle_qos1_message_flow(app_message)
     elif app_message.qos == QOS_2:
         yield from self._handle_qos2_message_flow(app_message)
     else:
         raise HBMQTTException("Unexcepted QOS value '%d" % str(app_message.qos))
示例#18
0
 def __init__(
     self,
     fixed: MQTTFixedHeader = None,
     vh: ConnectVariableHeader = None,
     payload: ConnectPayload = None,
 ):
     if fixed is None:
         header = MQTTFixedHeader(CONNECT, 0x00)
     else:
         if fixed.packet_type is not CONNECT:
             raise HBMQTTException(
                 "Invalid fixed packet type %s for ConnectPacket init" %
                 fixed.packet_type)
         header = fixed
     super().__init__(header)
     self.variable_header = vh
     self.payload = payload
示例#19
0
文件: handler.py 项目: smurfix/hbmqtt
    async def _handle_qos1_message_flow(self, app_message):
        """
        Handle QOS_1 application message acknowledgment
        For incoming messages, this method stores the message and reply with PUBACK
        For outgoing messages, this methods sends PUBLISH and waits for the corresponding PUBACK
        :param app_message:
        :return:
        """
        assert app_message.qos == QOS_1
        if app_message.puback_packet:
            raise HBMQTTException(
                "Message '%d' has already been acknowledged" %
                app_message.packet_id)
        if app_message.direction == OUTGOING:
            if app_message.packet_id not in self.session.inflight_out:
                # Store message in session
                self.session.inflight_out[app_message.packet_id] = app_message
            if app_message.publish_packet is not None:
                # A Publish packet has already been sent, this is a retry
                publish_packet = app_message.build_publish_packet(dup=True)
            else:
                publish_packet = app_message.build_publish_packet()

            # Wait for puback
            waiter = Future()
            self._puback_waiters[app_message.packet_id] = waiter
            # Send PUBLISH packet
            try:
                await self._send_packet(publish_packet)
                app_message.publish_packet = publish_packet
                app_message.puback_packet = await waiter.get()
            finally:
                del self._puback_waiters[app_message.packet_id]

            # Discard inflight message
            del self.session.inflight_out[app_message.packet_id]
        elif app_message.direction == INCOMING:
            # Initiate delivery
            self.logger.debug("Add message to delivery")
            await self.session.put_message(app_message)
            # Send PUBACK
            puback = PubackPacket.build(app_message.packet_id)
            await self._send_packet(puback)
            app_message.puback_packet = puback
示例#20
0
 def _handle_qos2_message_flow(self, app_message):
     """
     Handle QOS_2 application message acknowledgment
     For incoming messages, this method stores the message, sends PUBREC, waits for PUBREL, initiate delivery
     and send PUBCOMP
     For outgoing messages, this methods sends PUBLISH, waits for PUBREC, discards messages and wait for PUBCOMP
     :param app_message:
     :return:
     """
     assert app_message.qos == QOS_2
     if app_message.direction == OUTGOING:
         if app_message.pubrel_packet and app_message.pubcomp_packet:
             raise HBMQTTException(
                 "Message '%d' has already been acknowledged" %
                 app_message.packet_id)
         if not app_message.pubrel_packet:
             # Store message
             if app_message.publish_packet is not None:
                 # This is a retry flow, no need to store just check the message exists in session
                 if app_message.packet_id not in self.session.inflight_out:
                     raise HBMQTTException(
                         "Unknown inflight message '%d' in session" %
                         app_message.packet_id)
                 publish_packet = app_message.build_publish_packet(dup=True)
             else:
                 # Store message in session
                 self.session.inflight_out[
                     app_message.packet_id] = app_message
                 publish_packet = app_message.build_publish_packet()
             # Send PUBLISH packet
             yield from self._send_packet(publish_packet)
             app_message.publish_packet = publish_packet
             # Wait PUBREC
             if app_message.packet_id in self._pubrec_waiters:
                 # PUBREC waiter already exists for this packet ID
                 message = "Can't add PUBREC waiter, a waiter already exists for message Id '%s'" \
                           % app_message.packet_id
                 self.logger.warning(message)
                 raise HBMQTTException(message)
             waiter = asyncio.Future(loop=self._loop)
             self._pubrec_waiters[app_message.packet_id] = waiter
             yield from waiter
             del self._pubrec_waiters[app_message.packet_id]
             app_message.pubrec_packet = waiter.result()
         if not app_message.pubcomp_packet:
             # Send pubrel
             app_message.pubrel_packet = PubrelPacket.build(
                 app_message.packet_id)
             yield from self._send_packet(app_message.pubrel_packet)
             # Wait for PUBCOMP
             waiter = asyncio.Future(loop=self._loop)
             self._pubcomp_waiters[app_message.packet_id] = waiter
             yield from waiter
             del self._pubcomp_waiters[app_message.packet_id]
             app_message.pubcomp_packet = waiter.result()
         # Discard inflight message
         del self.session.inflight_out[app_message.packet_id]
     elif app_message.direction == INCOMING:
         self.session.inflight_in[app_message.packet_id] = app_message
         # Send pubrec
         pubrec_packet = PubrecPacket.build(app_message.packet_id)
         yield from self._send_packet(pubrec_packet)
         app_message.pubrec_packet = pubrec_packet
         # Wait PUBREL
         if app_message.packet_id in self._pubrel_waiters and not self._pubrel_waiters[
                 app_message.packet_id].done():
             # PUBREL waiter already exists for this packet ID
             message = "A waiter already exists for message Id '%s', canceling it" \
                       % app_message.packet_id
             self.logger.warning(message)
             self._pubrel_waiters[app_message.packet_id].cancel()
         try:
             waiter = asyncio.Future(loop=self._loop)
             self._pubrel_waiters[app_message.packet_id] = waiter
             yield from waiter
             del self._pubrel_waiters[app_message.packet_id]
             app_message.pubrel_packet = waiter.result()
             # Initiate delivery and discard message
             yield from self.session.delivered_message_queue.put(
                 app_message)
             del self.session.inflight_in[app_message.packet_id]
             # Send pubcomp
             pubcomp_packet = PubcompPacket.build(app_message.packet_id)
             yield from self._send_packet(pubcomp_packet)
             app_message.pubcomp_packet = pubcomp_packet
         except asyncio.CancelledError:
             self.logger.debug("Message flow cancelled")