Example #1
0
    def __init__(self, ip, port, tracker_url):
        """
        Inits the Peer application.

        :param ip: The IP address of the peer.
        :param port: The port to listen.
        :param tracker_url: The URL of the tracker.
        """

        self.port = port
        self.ip = ip

        self.peer_id = self._generate_peer_id()
        self.tracker_peers = PeerDatabase()

        self.piece_manager = None
        self.connection_manager = None
        self.tracker_manager = None
        self.joiner = None
        self.stream_server = None

        self._create_piece_manager()
        self._create_utility_manager()
        self._create_connection_manager()
        self._create_tracker_manager(tracker_url)
        self._create_joiner()

        # FIXME: seconds hardcoded
        self.logic_repeater = TwistedRepeater(self._peer_logic, 2)
        self.logic_repeater.start_later()
Example #2
0
class PeerService(object):
    """
    Controls every aspect of the peer application.
    """

    # TODO: Refactor this. Use specific methods.
    def __init__(self, ip, port, tracker_url):
        """
        Inits the Peer application.

        :param ip: The IP address of the peer.
        :param port: The port to listen.
        :param tracker_url: The URL of the tracker.
        """

        self.port = port
        self.ip = ip

        self.peer_id = self._generate_peer_id()
        self.tracker_peers = PeerDatabase()

        self.piece_manager = None
        self.connection_manager = None
        self.tracker_manager = None
        self.joiner = None
        self.stream_server = None

        self._create_piece_manager()
        self._create_utility_manager()
        self._create_connection_manager()
        self._create_tracker_manager(tracker_url)
        self._create_joiner()

        # FIXME: seconds hardcoded
        self.logic_repeater = TwistedRepeater(self._peer_logic, 2)
        self.logic_repeater.start_later()

    @property
    def pieces(self):
        return self.piece_manager.own_sequences

    def partner_got_piece(self, partner_id, piece):
        self.piece_manager.partner_got_piece(partner_id, piece)

    def partner_bitset(self, partner_id, pieces):
        self.piece_manager.partner_got_pieces(partner_id, pieces)

    def receive_request(self, partner_id, sequence):
        self.piece_manager.partner_requested_piece(partner_id, sequence)

    def receive_packet(self, packet, sender_id):
        self.joiner.push_packet(packet)
        self.piece_manager.add_new_piece(packet.sequence, packet.data)
        if sender_id is not None:
            self.utility_manager.add_peer_utility(sender_id, len(packet.data))

        for connection in self.connection_manager.all_connections:
            connection.send_got_piece(packet.sequence)

    def _peer_logic(self):
        logging.info('Executing Peer Logic')
        self._refresh_connections()
        self._contact_peers(self.tracker_peers)
        self._request_needed_pieces()
        self._send_requested_pieces()

        utility = self.utility_manager.utility_by_peer
        self.tracker_manager.utility_by_peer.update(utility)

    def _request_needed_pieces(self):

        missing_pieces = self.piece_manager.get_pieces_to_request()

        for piece in missing_pieces:
            partner_id = self.piece_manager.best_partner_for_piece(piece)
            if partner_id is None:
                logging.error('No partner for {0}'.format(piece))
                continue
            connection = self.connection_manager.get_connection(partner_id)
            if connection is None:
                logging.error('No connection for {0}'.format(partner_id))
                continue

            if self.piece_manager.can_request_piece(partner_id, piece):
                connection.send_request_packet(piece)
                self.piece_manager.mark_piece_as_requested(partner_id, piece)

    def _send_requested_pieces(self):
        for partner_id, sequence in self.piece_manager.get_pieces_to_send():
            data = self.piece_manager.get_piece_data(sequence)
            if data is None:
                logging.error('Dont have piece {0}'.format(sequence))
                return
            connection = self.connection_manager.get_connection(partner_id)
            if connection == None:
                logging.error('Dont have connection {0}'.format(partner_id))
                return
            connection.send_data_packet(sequence, data)
            self.piece_manager.mark_piece_as_sent(partner_id, sequence)
            logging.info('Sending data {0} to {1}'.format(sequence, partner_id))

    def _update_peers(self, sender, peer_list):
        self.tracker_peers.update_peers(peer_list)
        self.tracker_peers.remove_peer(self.peer_id)

        peers = '|'.join(str(p) for p in self.tracker_manager.peer_list)
        logging.debug('Tracker updated: {0}'.format(peers))

    def _contact_peers(self, peers):
        self.connection_manager.connect_to_peers(peers)

    def _refresh_connections(self):
        self.connection_manager.heartbeat()
        self.connection_manager.check_heartbeats()

    def _data_joined(self, joiner):
        if self.stream_server:
            self.stream_server.send_stream(joiner.pop_stream())
        else:
            logging.debug('Data joined without stream_server')

    def _create_piece_manager(self):
        self.piece_manager = PieceManager()

    def _create_connection_manager(self):
        self.connection_manager = ConnectionManager(self)

    def _create_tracker_manager(self, tracker_url):
        peer = Peer(self.peer_id, self.ip, self.port)
        self.tracker_manager = TrackerManager(tracker_url, peer)

        self.tracker_manager.on_updated.add_handler(self._update_peers)

    def _create_joiner(self):
        self.joiner = Joiner()
        self.joiner.on_data_joined.add_handler(self._data_joined)

    def _create_utility_manager(self):
        self.utility_manager = UtilityManager()

    def _generate_peer_id(self):
        id = uuid.uuid4().hex
        id = id[:14]
        ## TESTING
        id = format(self.port, '014d')
        ## END TESTING
        peer_id = 'PX0001' +  id
        logging.debug('Generated Peer ID: "{0}"'.format(peer_id))
        return peer_id