def download_files(self):
        while True:
            if self.disconnect:
                break
            if not self.cur_info:
                continue
            else:
                filenames = []
                for filename in self.cur_info["info"]:
                    if filename not in self.completed_files:
                        filenames.append(filename)

                if len(filenames) == 0:
                    continue

                chosen_file = random.choice(filenames)

                potential_peers = []

                for peer in self.cur_info["info"][chosen_file]["peers"]:
                    if peer is not None:
                        if chosen_file not in self.all_files:
                            self.all_files[chosen_file] = {
                                "cur_chunk": 0,
                            }
                        if self.all_files[chosen_file]["cur_chunk"] < peer["cur_chunk"]:
                            potential_peers.append(peer)

                chosen_peer = random.choice(potential_peers)
                start_chunk = self.all_files[chosen_file]["cur_chunk"]
                end_chunk = min(
                    start_chunk + MAX_SEND_CHUNKS,
                    self.cur_info["info"][chosen_file]["info"]["numchunks"]
                )

                download_socket = socket(AF_INET, SOCK_STREAM)

                try:
                    download_socket.connect((chosen_peer["addr"], chosen_peer["upload_port"]))
                    msg = {
                        "filename": chosen_file,
                        "start_chunk": start_chunk,
                        "end_chunk": end_chunk
                    }
                    packet.send_msg(download_socket, json.dumps(msg).encode())
                    peer_msg = packet.recv_msg(download_socket)
                except:
                    continue

                P2PFile.write_to_file(chosen_file, peer_msg)

                download_socket.close()

                self.all_files[chosen_file]["cur_chunk"] = end_chunk

                if end_chunk == self.cur_info["info"][chosen_file]["info"]["numchunks"]:
                    self.completed_files.add(chosen_file)

                # send update to tracker
                self.update_tracker(chosen_file, end_chunk)
 def connect_to_tracker(self):
     tracker_sock = socket(AF_INET, SOCK_STREAM)
     tracker_sock.connect((self.tracker_addr, self.tracker_port))
     msg = {
         "type": "CONNECT",
         "file_info": self.my_orig_files,
         "upload_port": self.upload_sock_port,
         "listen_port": self.listen_sock_port
     }
     packet.send_msg(tracker_sock, json.dumps(msg).encode())
     self.id = int(packet.recv_msg(tracker_sock).decode())
     tracker_sock.close()
 def update_peers(self):
     for i in range(0, MAX_PEERS):
         if self.all_info.peers[i]:
             update_peer_sock = socket(AF_INET, SOCK_STREAM)
             peer_info = self.all_info.peers[i]
             update_peer_sock.connect(
                 (peer_info["addr"], peer_info["listen_port"]))
             msg = {
                 "info": self.all_info.info,
                 "peers": self.all_info.peers
             }
             packet.send_msg(update_peer_sock, json.dumps(msg).encode())
             update_peer_sock.close()
 def update_tracker(self, filename, cur_chunk):
     while True:
         try:
             tracker_sock = socket(AF_INET, SOCK_STREAM)
             tracker_sock.connect((self.tracker_addr, self.tracker_port))
             msg = {
                 "id": self.id,
                 "type": "DOWNLOADED",
                 "filename": filename,
                 "cur_chunk": cur_chunk
             }
             packet.send_msg(tracker_sock, json.dumps(msg).encode())
             tracker_sock.close()
             break
         except:
             continue
 def upload_files(self):
     self.upload_sock.listen(1)
     while True:
         try:
             peer_sock, addr = self.upload_sock.accept()
         except:
             if self.disconnect:
                 break
             continue
         peer_msg = json.loads(packet.recv_msg(peer_sock).decode())
         msg = P2PFile.get_bytes_from_file_in_shared(
             peer_msg["filename"],
             peer_msg["start_chunk"],
             peer_msg["end_chunk"]
         )
         packet.send_msg(peer_sock, msg)
         # peer_sock.send(msg)
         peer_sock.close()
    def timeout(self):
        tracker_sock = socket(AF_INET, SOCK_STREAM)
        tracker_sock.connect((self.tracker_addr, self.tracker_port))
        msg = {
            "type": "DISCONNECT",
            "id": self.id

        }
        packet.send_msg(tracker_sock, json.dumps(msg).encode())
        all_files = P2PFile.get_all_info_in_shared()
        print("PEER {} SHUTDOWN: HAS {}".format(
            self.id,
            len(all_files)
        ))
        for fileinfo in all_files:
            print("{}    {}".format(
                self.id,
                fileinfo["filename"]
            ))
        self.disconnect = True
    def listen_to_peers(self):
        self.sock.listen(1)
        while True:
            peer_socket, addr = self.sock.accept()
            peer_addr = addr[0]
            peer_port = addr[1]

            peer_msg = json.loads(packet.recv_msg(peer_socket).decode())

            if peer_msg["type"] == "CONNECT":
                packet.send_msg(peer_socket, str(self.cur_peer_num).encode())
                files_info = []

                for file_info in peer_msg["file_info"]:
                    p2pfile = P2PFile.load_file_info(file_info)
                    files_info.append(p2pfile)
                    peer_file_info = PeerFileInfo(self.cur_peer_num,
                                                  peer_addr,
                                                  peer_msg["upload_port"],
                                                  peer_msg["listen_port"],
                                                  p2pfile,
                                                  complete=True)
                    self.all_info.add_peer_info(peer_file_info)

                self.output_peer_files(self.cur_peer_num, files_info)
                self.cur_peer_num += 1

            elif peer_msg["type"] == "DISCONNECT":
                self.all_info.remove_peer_info(int(peer_msg["id"]))

            elif peer_msg["type"] == "DOWNLOADED":
                peer_id = peer_msg["id"]
                filename = peer_msg["filename"]
                cur_chunk = peer_msg["cur_chunk"]
                self.all_info.update_peer_info(peer_id, filename, cur_chunk)

            self.update_peers()
            peer_socket.close()