class FileStreamClient(StreamClient): # TODO change this to a config file BUFFER = 1000000 INTERVAL = 1 def __init__(self): super(FileStreamClient, self).__init__() self.stream = None self.reader = None def open_file(self, filename): self.stream = open(filename, 'rb') self.reader = TwistedRepeater(self._read_file, self.INTERVAL) self.reader.start_later() def _stop_reader(self): if self.reader is not None: self.reader.stop() def _read_file(self): if not self.stream: self._stop_reader() return data = self.stream.read(self.BUFFER) if len(data) > 0: self.on_stream_received.call(data) else: self.on_stream_end.call() self.stream.close() self._stop_reader()
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()
def __init__(self, tracker_url, peer): """ Initializes the manager. """ self._announce_repeater = TwistedRepeater(self.announce, self.DEFAULT_ANNOUNCE) self._utility_repeater = TwistedRepeater(self.report_utility, self.DEFAULT_ANNOUNCE) self.tracker_url = tracker_url self.peer = peer self.utility_by_peer = {} self.peer_list = [] self.status = TrackerStatus(TrackerStatus.STANDBY, 'Ready to connect') self.on_updated = Event() self.on_status_changed = Event()
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
class TrackerManager(object): """ Manages the connection with the tracker """ DEFAULT_ANNOUNCE = 30 #TODO: Eliminate tracker_url parameter def __init__(self, tracker_url, peer): """ Initializes the manager. """ self._announce_repeater = TwistedRepeater(self.announce, self.DEFAULT_ANNOUNCE) self._utility_repeater = TwistedRepeater(self.report_utility, self.DEFAULT_ANNOUNCE) self.tracker_url = tracker_url self.peer = peer self.utility_by_peer = {} self.peer_list = [] self.status = TrackerStatus(TrackerStatus.STANDBY, 'Ready to connect') self.on_updated = Event() self.on_status_changed = Event() def connect_to_tracker(self): self._announce_repeater.start_now() self._utility_repeater.start_now() def announce(self): """Starts connection with the tracker.""" logging.debug('Announcing to tracker') deferred = client.getPage(self._create_announce_url()) deferred.addCallback(self._on_announce_response) deferred.addErrback(self._on_tracker_error) def report_utility(self): if len(self.utility_by_peer) == 0: return deferred = client.getPage(self._create_utility_url()) deferred.addCallback(self._on_utility_response) deferred.addErrback(self._on_tracker_error) def _create_announce_url(self): """Creates a request URL for the tracker with the GET query.""" query = dict(peer_id = self.peer.id, port = self.peer.port) if self.peer.ip is not None: query.update(ip = self.peer.ip) parts = list(urlparse.urlsplit(self.tracker_url)) parts[2] += '/announce' # path parts[3] = urllib.urlencode(query) # query return urlparse.urlunsplit(parts) def _create_utility_url(self): parts = list(urlparse.urlsplit(self.tracker_url)) parts[2] += '/utility' parts[3] = urllib.urlencode(self.utility_by_peer) # query. return urlparse.urlunsplit(parts) def _on_tracker_error(self, error): logging.error('Unable to contact the tracker: ' + str(error.value)) self._change_status(TrackerStatus.ERROR, 'Unable to contact the tracker') def _on_announce_response(self, content): try: logging.debug('Received tracker announce response') response = json.loads(content) if 'failure_reason' in response: self._on_announce_failure(response['failure_reason']) return if 'request_interval' in response: self._announce_repeater.seconds = response['request_interval'] if 'peers' in response: self._update_peers(response['peers']) self._change_status(TrackerStatus.OK, 'OK') except Exception as e: self._on_announce_failure(str(e)) def _on_announce_failure(self, error): logging.error('Tracker announce failure: ' + error) self._change_status(TrackerStatus.ERROR, error) def _on_utility_response(self, content): logging.debug('Received tracker utility response') response = json.loads(content) if 'failure_reason' in response: self._on_utility_failure(response['failure_reason']) return def _on_utility_failure(self, error): logging.error('Tracker utility failure: ' + error) self._change_status(TrackerStatus.ERROR, error) def _update_peers(self, peer_list): try: self.peer_list = [] for peer_dict in peer_list: id = peer_dict['id'] ip = peer_dict['ip'] port = peer_dict['port'] uf = peer_dict['utility_factor'] self.peer_list.append(Peer(id, ip, port, uf)) self.on_updated.call(self, self.peer_list) except Exception as e: raise TrackerManagerError('Unable to convert peer list: ' + str(e)) def _change_status(self, status, message): if self.status.status == status and self.status.message == message: return self.status = TrackerStatus(status, message) self.on_status_changed.call(self, self.status)
def open_file(self, filename): self.stream = open(filename, 'rb') self.reader = TwistedRepeater(self._read_file, self.INTERVAL) self.reader.start_later()