Example #1
0
    def __init__(self, src_router, dest_router, enabled=False,
            loss_func=None, parent=None):
        super(LinkItem, self).__init__(parent)

        self._logger = logging.getLogger(
            "LinkItem.{0}->{1}".format(src_router.name, dest_router.name))

        self.src = src_router
        self.dest = dest_router

        self.src.add_link(self)
        self.dest.add_link(self)

        self.src_point = None
        self.dest_point = None

        # { id: LinkItem.TransmittingPacket }
        self._transmitting_direct_packets = {}
        self._transmitting_reverse_packets = {}

        # Edge color.
        self.color = Qt.black

        self._visual_link_width = 2
        self._visual_route_start_offset = 2.5
        self._visual_route_offset_step = 0.8
        self._visual_route_line_width = 0.5
        self._visual_route_draw_fraction = 2.0 / 3
        self._visual_packet_offset = 5

        # Initial state is disabled.
        self._enabled = False
        self.hide()
        l1, l2 = FullDuplexLink(loss_func=loss_func)
        sft1 = SimpleFrameTransmitter(node=l1)
        sft2 = SimpleFrameTransmitter(node=l2)
        self._src_frame_transmitter = \
            ControllableFrameTransmitter(
                src_name=self.src.name, dest_name=self.dest.name,
                simple_frame_transmitter=sft1,
                debug_src=self.src.name, debug_dest=self.dest.name)
        self._dest_frame_transmitter = \
            ControllableFrameTransmitter(
                src_name=self.dest.name, dest_name=self.src.name,
                simple_frame_transmitter=sft2,
                debug_src=self.dest.name, debug_dest=self.src.name)

        self.enabled = enabled

        self.src_table = self.src.rip_service.dynamic_routing_table().table()
        self.dest_table = self.dest.rip_service.dynamic_routing_table().table()
        self._recalculate_routes()

        update_rate = 10 # frames per second
        self._timer_id = self.startTimer(int(1000.0 / update_rate))
Example #2
0
class LinkItem(QGraphicsObject):
    TransmittingPacket = recordtype('TransmittingPacket',
            'packet start_time end_time packet_item')
            
    def __init__(self, src_router, dest_router, enabled=False,
            loss_func=None, parent=None):
        super(LinkItem, self).__init__(parent)

        self._logger = logging.getLogger(
            "LinkItem.{0}->{1}".format(src_router.name, dest_router.name))

        self.src = src_router
        self.dest = dest_router

        self.src.add_link(self)
        self.dest.add_link(self)

        self.src_point = None
        self.dest_point = None

        # { id: LinkItem.TransmittingPacket }
        self._transmitting_direct_packets = {}
        self._transmitting_reverse_packets = {}

        # Edge color.
        self.color = Qt.black

        self._visual_link_width = 2
        self._visual_route_start_offset = 2.5
        self._visual_route_offset_step = 0.8
        self._visual_route_line_width = 0.5
        self._visual_route_draw_fraction = 2.0 / 3
        self._visual_packet_offset = 5

        # Initial state is disabled.
        self._enabled = False
        self.hide()
        l1, l2 = FullDuplexLink(loss_func=loss_func)
        sft1 = SimpleFrameTransmitter(node=l1)
        sft2 = SimpleFrameTransmitter(node=l2)
        self._src_frame_transmitter = \
            ControllableFrameTransmitter(
                src_name=self.src.name, dest_name=self.dest.name,
                simple_frame_transmitter=sft1,
                debug_src=self.src.name, debug_dest=self.dest.name)
        self._dest_frame_transmitter = \
            ControllableFrameTransmitter(
                src_name=self.dest.name, dest_name=self.src.name,
                simple_frame_transmitter=sft2,
                debug_src=self.dest.name, debug_dest=self.src.name)

        self.enabled = enabled

        self.src_table = self.src.rip_service.dynamic_routing_table().table()
        self.dest_table = self.dest.rip_service.dynamic_routing_table().table()
        self._recalculate_routes()

        update_rate = 10 # frames per second
        self._timer_id = self.startTimer(int(1000.0 / update_rate))

    def __del__(self):
        print self, "__del__()" # DEBUG
        super(LinkItem, self).__del__()
        self.terminate()

    # TODO
    def terminate(self):
        self._src_frame_transmitter.terminate()
        self._dest_frame_transmitter.terminate()

    @property
    def enabled(self):
        return self._enabled

    @enabled.setter
    def enabled(self, value):
        if self._enabled != bool(value):
            self._enabled = bool(value)

            if self._enabled:
                # Link up.
                self._link_up()
            else:
                # Link down.
                self._link_down()
                
    def _link_up(self):
        self._src_frame_transmitter.enabled = True
        self._dest_frame_transmitter.enabled = True

        self.src.link_manager.add_link(self.dest.name,
            self._src_frame_transmitter)
        self.dest.link_manager.add_link(self.src.name,
            self._dest_frame_transmitter)

        self.adjust()
        self.show()

    def _link_down(self):
        self._src_frame_transmitter.enabled = False
        #assert not self._transmitting_direct_packets
        self._dest_frame_transmitter.enabled = False
        #assert not self._transmitting_reverse_packets

        self.src.link_manager.remove_link(self.dest.name)
        self.dest.link_manager.remove_link(self.src.name)

        self.hide()

    def _create_transmitting_packet_scene_item(self, protocol, packet):
        if protocol == RIPService.protocol:
            return RIPPacketItem(packet, self)
        elif protocol == DataSendService.protocol:
            return ImageTransferPacketItem(packet, self)
        else:
            self._logger.warning(
                "Request to create scene item for unknown protocol {0}. "
                "Packet: {1}".format(protocol, packet))

    @pyqtSlot(int, float, float, int, Packet)
    def _on_src_packet_send(self, id_, send_time, deliver_time, protocol,
                            packet):
        # TODO
        self._logger.debug("_on_src_packet_send: {0} {1} {2} {3}".format(
            id_, send_time, deliver_time, packet))

        scene_item = self._create_transmitting_packet_scene_item(
            protocol, packet)
        #scene_item.setParent(self)

        tr_packet = LinkItem.TransmittingPacket(
            packet, send_time, deliver_time, scene_item)
        self._adjust_transmitting_packet(tr_packet)

        self._transmitting_direct_packets[id_] = tr_packet

    @pyqtSlot(int, bool)
    def _on_src_packet_received(self, id_, is_success):
        # TODO
        self._logger.debug("_on_src_packet_received: {0}".format(id_))

        self._transmitting_direct_packets[id_].packet_item.setParent(None)
        del self._transmitting_direct_packets[id_]

    @pyqtSlot(int, float, float, int, Packet)
    def _on_dest_packet_send(self, id_, send_time, deliver_time, protocol,
                            packet):
        # TODO
        self._logger.debug("_on_dest_packet_send: {0} {1} {2} {3}".format(
            id_, send_time, deliver_time, packet))

        scene_item = self._create_transmitting_packet_scene_item(
            protocol, packet)
        #scene_item.setParent(self)

        tr_packet = LinkItem.TransmittingPacket(
            packet, send_time, deliver_time, scene_item)
        self._adjust_transmitting_packet(tr_packet)

        self._transmitting_reverse_packets[id_] = tr_packet

    @pyqtSlot(int, bool)
    def _on_dest_packet_received(self, id_, is_success):
        # TODO
        self._logger.debug("_on_dest_packet_received: {0}".format(id_))

        self._transmitting_reverse_packets[id_].packet_item.setParent(None)
        del self._transmitting_reverse_packets[id_]

    def length(self):
        return QLineF(
            self.mapFromItem(self.src, 0, 0),
            self.mapFromItem(self.dest, 0, 0)).length()

    def adjust(self):
        if self._enabled:
            line = QLineF(
                self.mapFromItem(self.src, 0, 0),
                self.mapFromItem(self.dest, 0, 0))

            self.prepareGeometryChange()

            if line.length() > self.src.radius + self.dest.radius:
                unit = QVector2D(line.p2() - line.p1()).normalized()
                self.src_point  = \
                    line.p1() + (unit * self.src.radius).toPointF()
                self.dest_point = \
                    line.p2() - (unit * self.dest.radius).toPointF()
            else:
                self.src_point  = None
                self.dest_point = None

    def link_end(self, src):
        if self.src == src:
            return self.dest
        else:
            assert self.dest == src
            return self.src

    def link_end_by_name(self, name):
        if self.src.name == name:
            return self.src
        else:
            assert self.dest.name == name
            return self.dest

    def is_singular(self):
        return self.src_point is None or self.dest_point is None

    def boundingRect(self):
        if self.is_singular():
            return QRectF()

        # TODO: Take in account transmitting packets.

        routes_count = max(len(self._routes_through_dest),
            len(self._routes_through_src))
        extra = max(self._visual_link_width,
            self._visual_route_start_offset +
                routes_count * self._visual_route_offset_step +
                    self._visual_route_line_width) * math.sqrt(2) # magic const

        return QRectF(self.src_point,
            QSizeF(self.dest_point.x() - self.src_point.x(),
                   self.dest_point.y() - self.src_point.y())) \
                        .normalized() \
                        .adjusted(-extra, -extra, extra, extra)

    def _paint_next_router(self, painter, line, offset, dest_router, distance):
        unit_vector = line.unitVector().p2() - line.unitVector().p1()
        normal_vector = line.normalVector().unitVector().p1() - \
            line.normalVector().unitVector().p2()

        line_to_draw = QLineF(
            line.unitVector().p1(),
            line.unitVector().p1() + 
                unit_vector * line.length() * self._visual_route_draw_fraction)
        line_to_draw.translate(normal_vector * offset)

        color = palette.palette[dest_router]
        saturation = \
            (1.0 * (RIPService.inf_distance - distance) /
                float(RIPService.inf_distance))
        color.setHsvF(color.hueF(), saturation, color.valueF())

        painter.setPen(QPen(color, self._visual_route_line_width,
            Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
        painter.drawLine(line_to_draw)

    def _paint_next_routers(self, painter):
        # From source to destination.
        line = QLineF(self.src_point, self.dest_point)
        for idx, (dest, route) in enumerate(self._routes_through_dest):
            offset = self._visual_route_start_offset + \
                idx * self._visual_route_offset_step
            self._paint_next_router(painter,
                line, offset, dest, route.distance)

        # From destination to source.
        line = QLineF(line.p2(), line.p1())
        for idx, (dest, route) in enumerate(self._routes_through_src):
            offset = self._visual_route_start_offset + \
                idx * self._visual_route_offset_step
            self._paint_next_router(painter,
                line, offset, dest, route.distance)

    def paint(self, painter, style_option, widget):
        if self.is_singular():
            return

        line = QLineF(self.src_point, self.dest_point)
        assert not qFuzzyCompare(line.length(), 0.)

        painter.setPen(QPen(Qt.black, self._visual_link_width,
            Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
        painter.drawLine(line)

        self._paint_next_routers(painter)

    def _recalculate_routes(self):
        # TODO: may be call prepareGeometryChange()?
        
        through_dest_routers = \
                routing_table.routes_through(self.src_table, self.dest.name)
        through_src_routers = \
            routing_table.routes_through(self.dest_table, self.src.name)

        self._routes_through_dest = [(dest, self.src_table[dest]) \
            for dest in through_dest_routers]
        self._routes_through_src = [(dest, self.dest_table[dest]) \
            for dest in through_src_routers]

        # Sort by destination.
        self._routes_through_dest.sort(cmp=lambda a, b: cmp(a[0], b[0]))
        self._routes_through_src.sort (cmp=lambda a, b: cmp(a[0], b[0]))

    def _adjust_transmitting_packet(self, tr_packet):
        # TODO: may be call prepareGeometryChange()?

        #self._logger.debug("_adjust_transmitting_packet: {0}".format(tr_packet))

        if self.is_singular():
            tr_packet.packet_item.hide()
            return
        else:
            tr_packet.packet_item.show()

        curtime = time.time()
        assert curtime >= tr_packet.start_time
        assert tr_packet.end_time >= tr_packet.start_time
        progress = min(1.0, 
            (curtime - tr_packet.start_time) /
                (tr_packet.end_time - tr_packet.start_time))

        # TODO: Currently packets delivered faster then they poped from queue.
        if progress == 1.0:
            tr_packet.packet_item.hide()
            return

        if tr_packet.packet.delivered_from == self.dest.name:
            line = QLineF(self.src_point, self.dest_point)
        else:
            line = QLineF(self.dest_point, self.src_point)
        assert not qFuzzyCompare(line.length(), 0.)

        unit_vector = line.unitVector().p2() - line.unitVector().p1()
        normal_vector = line.normalVector().unitVector().p1() - \
            line.normalVector().unitVector().p2()

        position = line.p1() + unit_vector * line.length() * progress + \
            normal_vector * self._visual_packet_offset
        tr_packet.packet_item.setPos(position)
        tr_packet.packet_item.setRotation(-line.angle() - 90.0)

        # DEBUG
        #if isinstance(tr_packet.packet_item, ImageTransferPacketItem):
        #    print tr_packet

    def timerEvent(self, event):
        old_src_table = self.src_table
        old_dest_table = self.dest_table

        # TODO
        if self.src.rip_service is None or self.dest.rip_service is None:
            return

        # Update packets.
        while True:
            try:
                msg = self._src_frame_transmitter.send_receive_queue.get_nowait()
            except Queue.Empty:
                break
            # TODO!
            if len(msg) > 2:
                self._on_src_packet_send(*msg)
            else:
                self._on_src_packet_received(*msg)

        while True:
            try:
                msg = self._dest_frame_transmitter.send_receive_queue.get_nowait()
            except Queue.Empty:
                break
            # TODO!
            if len(msg) > 2:
                self._on_dest_packet_send(*msg)
            else:
                self._on_dest_packet_received(*msg)


        self.src_table = self.src.rip_service.dynamic_routing_table().table()
        self.dest_table = self.dest.rip_service.dynamic_routing_table().table()

        if old_src_table != self.src_table or old_dest_table != self.dest_table:
            self._recalculate_routes()
            self.update()

        for tr_packet in self._transmitting_direct_packets.values() + \
                self._transmitting_reverse_packets.values():
            self._adjust_transmitting_packet(tr_packet)