Exemplo n.º 1
0
    def __init__(self, outgoing_publishes):
        self.max_inflight = 1

        assert isinstance(outgoing_publishes, OutgoingPublishesBase)
        self.publishes = outgoing_publishes

        self.packets = deque()
        self.retrial_handles = dict()

        self.future = DummyFuture()
Exemplo n.º 2
0
    def clear(self):
        """
        Clears the in-memory state of the outgoing queue. The data in
        persistence is left as is. If there is any pending `Future`
        waiting for result, it is cancelled.
        """
        for packet_id in self.retrial_handles.keys():
            self.cancel_retrial(packet_id)

        self.packets.clear()
        self.retrial_handles.clear()

        if not self.future.done():
            msg = 'Outgoing queue was cleansed'
            self.future.set_exception(CancelledException(msg))

        self.future = DummyFuture()
Exemplo n.º 3
0
    def __init__(self, outgoing_publishes):
        self.max_inflight = 1

        assert isinstance(outgoing_publishes, OutgoingPublishesBase)
        self.publishes = outgoing_publishes

        self.packets = deque()
        self.retrial_handles = dict()

        self.future = DummyFuture()
Exemplo n.º 4
0
    def clear(self):
        """
        Clears the in-memory state of the outgoing queue. The data in
        persistence is left as is. If there is any pending `Future`
        waiting for result, it is cancelled.
        """
        for packet_id in self.retrial_handles.keys():
            self.cancel_retrial(packet_id)

        self.packets.clear()
        self.retrial_handles.clear()

        if not self.future.done():
            msg = 'Outgoing queue was cleansed'
            self.future.set_exception(CancelledException(msg))

        self.future = DummyFuture()
Exemplo n.º 5
0
    def get(self):
        """
        Gets the next packet to be sent to the remote client.
        :return: a `Future`
        """
        if not self.future.done():
            self.future.set_exception(CancelledException('Only one future supported'))

        self.future = Future()

        # try to start next publish flow first,
        # otherwise the outgoing packets would have to deplete before
        # any publish flows could start
        started = self._start_next_flow()

        if not started and self.packets:
            self.future.set_result(self.packets.popleft())

        return self.future
Exemplo n.º 6
0
    def get(self):
        """
        Gets the next packet to be sent to the remote client.
        :return: a `Future`
        """
        if not self.future.done():
            self.future.set_exception(
                CancelledException('Only one future supported'))

        self.future = Future()

        # try to start next publish flow first,
        # otherwise the outgoing packets would have to deplete before
        # any publish flows could start
        started = self._start_next_flow()

        if not started and self.packets:
            self.future.set_result(self.packets.popleft())

        return self.future
Exemplo n.º 7
0
class OutgoingQueue():
    """
    This class controls packets to be delivered to the remote client.
    It encapsulates the logic to send packets and start new publish flows.
    """
    def __init__(self, outgoing_publishes):
        self.max_inflight = 1

        assert isinstance(outgoing_publishes, OutgoingPublishesBase)
        self.publishes = outgoing_publishes

        self.packets = deque()
        self.retrial_handles = dict()

        self.future = DummyFuture()

    def retry_pending(self):
        for packet in self.publishes.get_all_inflight():
            self.retrial_handles[packet.id] = None
            self.put(packet)

    def put(self, packet):
        """
        Puts a packet to the outgoing queue.
        No checks are done on the provided packets.
        """
        assert isinstance(packet, BaseMQTTMessage)
        if not self.future.done():
            self.future.set_result(packet)
        else:
            self.packets.append(packet)

    def put_publish(self, packet):
        """
        Puts a publish packet to the outgoing queue.
        If the QoS level is 0 it is only placed on the outgoing queue.
        Otherwise the packet is persisted and scheduled for publishing.
        """
        assert isinstance(packet, Publish)

        if packet.qos == 0:
            self.put(packet)
        else:
            self.publishes.insert(packet)
            self._start_next_flow()

    def set_sent(self, packet_id):
        if self.publishes.is_inflight(packet_id):
            self.publishes.set_sent(packet_id)

    def is_sent(self, packet_id):
        return self.publishes.is_inflight(packet_id) and \
               self.publishes.is_sent(packet_id)

    def is_pubconf(self, packet_id):
        return self.publishes.is_inflight(packet_id) and \
               self.publishes.is_pubconf(packet_id)

    def set_pubconf(self, packet_id):
        if self.publishes.is_inflight(packet_id):
            self.publishes.set_pubconf(packet_id)

    def get(self):
        """
        Gets the next packet to be sent to the remote client.
        :return: a `Future`
        """
        if not self.future.done():
            self.future.set_exception(CancelledException('Only one future supported'))

        self.future = Future()

        # try to start next publish flow first,
        # otherwise the outgoing packets would have to deplete before
        # any publish flows could start
        started = self._start_next_flow()

        if not started and self.packets:
            self.future.set_result(self.packets.popleft())

        return self.future

    def clear(self):
        """
        Clears the in-memory state of the outgoing queue. The data in
        persistence is left as is. If there is any pending `Future`
        waiting for result, it is cancelled.
        """
        for packet_id in self.retrial_handles.keys():
            self.cancel_retrial(packet_id)

        self.packets.clear()
        self.retrial_handles.clear()

        if not self.future.done():
            msg = 'Outgoing queue was cleansed'
            self.future.set_exception(CancelledException(msg))

        self.future = DummyFuture()

    def flow_completed(self, packet_id):
        """
        Removes the publish corresponding to the `packet-id` from the inflight
        set and from persistence.
        """
        if packet_id:
            self.publishes.remove(packet_id)
        if packet_id in self.retrial_handles:
            self.cancel_retrial(packet_id)
            del self.retrial_handles[packet_id]

        self._start_next_flow()

    def _start_next_flow(self):
        if self.publishes.inflight_len < self.max_inflight:
            packet = self.publishes.get_next()
            if packet:
                self.retrial_handles[packet.id] = None
                self.put(packet)
                return True

        return False

    def _retry_flow(self, packet_id):
        if self.publishes.is_inflight(packet_id):
            self.retrial_handles[packet_id] = None
            self.put(self.publishes.get_inflight(packet_id))

    def set_retrial(self, packet_id, deadline):
        handle = self.retrial_handles.get(packet_id)

        if handle:
            self.cancel_retrial(packet_id)

        callback = lambda: self._retry(packet_id)
        handle = ioloop.IOLoop.current().add_timeout(deadline, callback)
        self.retrial_handles[packet_id] = handle

    def cancel_retrial(self, packet_id):
        handler = self.retrial_handles.get(packet_id)
        if handler is not None:
            ioloop.IOLoop.current().remove_timeout(handler)
            self.retrial_handles[packet_id] = None

    def _retry(self, packet_id):
        if packet_id in self.retrial_handles:
            self._retry_flow(packet_id)
Exemplo n.º 8
0
class OutgoingQueue():
    """
    This class controls packets to be delivered to the remote client.
    It encapsulates the logic to send packets and start new publish flows.
    """
    def __init__(self, outgoing_publishes):
        self.max_inflight = 1

        assert isinstance(outgoing_publishes, OutgoingPublishesBase)
        self.publishes = outgoing_publishes

        self.packets = deque()
        self.retrial_handles = dict()

        self.future = DummyFuture()

    def retry_pending(self):
        for packet in self.publishes.get_all_inflight():
            self.retrial_handles[packet.id] = None
            self.put(packet)

    def put(self, packet):
        """
        Puts a packet to the outgoing queue.
        No checks are done on the provided packets.
        """
        assert isinstance(packet, BaseMQTTMessage)
        if not self.future.done():
            self.future.set_result(packet)
        else:
            self.packets.append(packet)

    def put_publish(self, packet):
        """
        Puts a publish packet to the outgoing queue.
        If the QoS level is 0 it is only placed on the outgoing queue.
        Otherwise the packet is persisted and scheduled for publishing.
        """
        assert isinstance(packet, Publish)

        if packet.qos == 0:
            self.put(packet)
        else:
            self.publishes.insert(packet)
            self._start_next_flow()

    def set_sent(self, packet_id):
        if self.publishes.is_inflight(packet_id):
            self.publishes.set_sent(packet_id)

    def is_sent(self, packet_id):
        return self.publishes.is_inflight(packet_id) and \
               self.publishes.is_sent(packet_id)

    def is_pubconf(self, packet_id):
        return self.publishes.is_inflight(packet_id) and \
               self.publishes.is_pubconf(packet_id)

    def set_pubconf(self, packet_id):
        if self.publishes.is_inflight(packet_id):
            self.publishes.set_pubconf(packet_id)

    def get(self):
        """
        Gets the next packet to be sent to the remote client.
        :return: a `Future`
        """
        if not self.future.done():
            self.future.set_exception(
                CancelledException('Only one future supported'))

        self.future = Future()

        # try to start next publish flow first,
        # otherwise the outgoing packets would have to deplete before
        # any publish flows could start
        started = self._start_next_flow()

        if not started and self.packets:
            self.future.set_result(self.packets.popleft())

        return self.future

    def clear(self):
        """
        Clears the in-memory state of the outgoing queue. The data in
        persistence is left as is. If there is any pending `Future`
        waiting for result, it is cancelled.
        """
        for packet_id in self.retrial_handles.keys():
            self.cancel_retrial(packet_id)

        self.packets.clear()
        self.retrial_handles.clear()

        if not self.future.done():
            msg = 'Outgoing queue was cleansed'
            self.future.set_exception(CancelledException(msg))

        self.future = DummyFuture()

    def flow_completed(self, packet_id):
        """
        Removes the publish corresponding to the `packet-id` from the inflight
        set and from persistence.
        """
        if packet_id:
            self.publishes.remove(packet_id)
        if packet_id in self.retrial_handles:
            self.cancel_retrial(packet_id)
            del self.retrial_handles[packet_id]

        self._start_next_flow()

    def _start_next_flow(self):
        if self.publishes.inflight_len < self.max_inflight:
            packet = self.publishes.get_next()
            if packet:
                self.retrial_handles[packet.id] = None
                self.put(packet)
                return True

        return False

    def _retry_flow(self, packet_id):
        if self.publishes.is_inflight(packet_id):
            self.retrial_handles[packet_id] = None
            self.put(self.publishes.get_inflight(packet_id))

    def set_retrial(self, packet_id, deadline):
        handle = self.retrial_handles.get(packet_id)

        if handle:
            self.cancel_retrial(packet_id)

        callback = lambda: self._retry(packet_id)
        handle = ioloop.IOLoop.current().add_timeout(deadline, callback)
        self.retrial_handles[packet_id] = handle

    def cancel_retrial(self, packet_id):
        handler = self.retrial_handles.get(packet_id)
        if handler is not None:
            ioloop.IOLoop.current().remove_timeout(handler)
            self.retrial_handles[packet_id] = None

    def _retry(self, packet_id):
        if packet_id in self.retrial_handles:
            self._retry_flow(packet_id)