def startup(): while True: shell.print_blue('\nThis process will allow you to add a tracker.\n') tracker = net_utils.prompt_host_request('Insert a known host') LocalData.set_tracker(tracker) # LocalData.set_tracker(('172.16.1.', 'fc00::1:', 3000)) # tenta login ip = net_utils.get_local_ip_for_response() port = str(net_utils.get_peer_port()).zfill(5) packet = "LOGI" + ip + port tracker_ip4 = LocalData.get_tracker_ip4() tracker_ip6 = LocalData.get_tracker_ip6() tracker_port = LocalData.get_tracker_port() try: sock = net_utils.send_packet(tracker_ip4, tracker_ip6, tracker_port, packet) response = sock.recv(50).decode() if len(response) != 20: shell.print_red(f'There was an error in the login process: unexpected: {response}.\nPlease retry.') continue session_id = response[4:20] if session_id == '0' * 16: shell.print_red( f'There was an error in the login process: unexpected session_id: {session_id}.\nPlease retry.') continue LocalData.session_id = session_id break except (socket.error, AttributeError): shell.print_yellow(f'Unable to contact {tracker_ip4}|{tracker_ip6} [{tracker_port}]') if sock is not None: sock.close() continue shell.print_green(f'Successfully logged to the tracker: {tracker_ip4}|{tracker_ip6} [{tracker_port}]\n') log = Logger.Logger('peer/peer.log') server = ServerThread(net_utils.get_peer_port(), UploadHandler.UploadHandler(log)) server.daemon = True server.start() Menu(MenuHandler.MenuHandler(), server).show()
#!/usr/bin/env python import os from utils import net_utils, shell_colors as shell from superpeer import superpeer from peer import peer if __name__ == '__main__': shell.print_blue(' _ ', end='') shell.print_yellow(' _ __ ', end='') shell.print_blue(' ') shell.print_blue(' /\ | | ', end='') shell.print_yellow('| |/ / ', end='') shell.print_blue(' ') shell.print_blue(' / \ | | __ _', end='') shell.print_yellow('| \' / __ _ ______ _ __ _', end='') shell.print_blue(' _ __ ___ ') shell.print_blue(' / /\ \ | |/ _` ', end='') shell.print_yellow('| < / _` |_ / _` |/ _` |', end='') shell.print_blue(' \'_ ` _ \ ') shell.print_blue(' / ____ \| | (_| ', end='') shell.print_yellow('| . \ (_| |/ / (_| | (_| |', end='') shell.print_blue(' | | | | | ') shell.print_blue(' /_/ \_\_|\__,_', end='') shell.print_yellow('|_|\_\__,_/___\__,_|\__,_|', end='') shell.print_blue('_| |_| |_| ') if not os.path.exists('shared'): os.mkdir('shared')
def serve(self, sd: socket.socket) -> None: """ Handle the peer request :param sd: the socket descriptor used for read the request :return None """ try: response = sd.recv(300).decode() except socket.error as e: shell.print_red(f'Unable to read the response from the socket: {e}\n') sd.close() return sd.close() command = response[0:4] if command == "AQUE": if len(response) != 212: shell.print_red(f"Invalid response: : {command} -> {response}. Expected: AQUE<pkt_id><ip_peer><port_peer><file_md5><filename>") return pktid = response[4:20] ip_peer = response[20:75] ip4_peer, ip6_peer = net_utils.get_ip_pair(ip_peer) port_peer = int(response[75:80]) file_md5 = response[80:112] filename = response[112:212].lstrip().rstrip() if pktid != LocalData.get_sent_menu_quer_packet(): return if not LocalData.exist_menu_peer_file(ip4_peer, ip6_peer, port_peer, file_md5, filename): LocalData.add_menu_peer_file(ip4_peer, ip6_peer, port_peer, file_md5, filename) index = LocalData.menu_peer_file_index(ip4_peer, ip6_peer, port_peer, file_md5, filename) print(f'{index +1}] ', end='') print(f'{filename} ', end='') shell.print_yellow(f'md5={file_md5} ', end='') print(f'({ip4_peer}|{ip6_peer} [{port_peer}])') elif command == "ASUP": if len(response) != 80: shell.print_red(f"Invalid response: : {command} -> {response}. Expected: ASUP<pkt_id><ip_peer><port_peer>") return pktid = response[4:20] ip_peer = response[20:75] ip4_peer, ip6_peer = net_utils.get_ip_pair(ip_peer) port_peer = int(response[75:80]) if pktid != LocalData.get_sent_supe_packet(): return if not LocalData.is_super_friend(ip4_peer, ip6_peer, port_peer): LocalData.add_super_friend(ip4_peer, ip6_peer, port_peer) shell.print_green('New superfriend found: ', end='') print(f'{ip4_peer}|{ip6_peer} [{port_peer}]') else: shell.print_red(f"\nInvalid response: {command} -> {response}\n") return
def serve(self, choice: str) -> None: """ Handle the peer packet :param choice: the choice to handle :return: None """ if choice == "SUPE": # SUPE[4B].Packet_Id[16B].IP_Peer[55B].Port_Peer[5B].TTL[2B] pktid = str(uuid.uuid4().hex[:16].upper()) ip = net_utils.get_local_ip_for_response() port = net_utils.get_asup_port() ttl = '04' packet = choice + pktid + ip + str(port).zfill(5) + ttl LocalData.set_sent_supe_packet(pktid) old_superfriends_len = len(LocalData.get_super_friends()) server = ServerThread(port, MenuTimedResponseHandler()) server.daemon = True server.start() spinner = SpinnerThread('Searching superpeers (ENTER to continue)', 'Research done! (ENTER to continue)') spinner.start() timer = Timer(20, lambda: (spinner.stop(), server.stop())) timer.start() self.__broadcast(packet) input() print('\033[1A', end='\r') if timer.is_alive(): spinner.stop() spinner.join() timer.cancel() timer.join() server.stop() server.join() else: spinner.join() timer.join() server.join() if len(LocalData.get_super_friends()) == old_superfriends_len: shell.print_yellow('\nNo new superpeer found.\n') elif choice == "ADFF": if not os.path.exists('shared'): shell.print_red('\nCannot find the shared folder.') return dir_file = list() if not os.scandir('shared'): shell.print_yellow('\nNo file in the shared folder.') return for count, dir_entry in enumerate(os.scandir('shared'), 1): dir_file.append((dir_entry.name, hasher.get_md5(dir_entry.path), dir_entry.stat().st_size)) print(f'\n{count}) {dir_entry.name}', end='') shell.print_yellow(f' {hasher.get_md5(dir_entry.path)}', end='') print(f' size: {dir_entry.stat().st_size}') while True: index = input('\nPlease select a file to share(pres q to exit): ') if index == 'q': print('\n') return try: index = int(index) - 1 except ValueError: shell.print_red(f'\nWrong index: number in range 1 - {count} expected.') continue if 0 <= index <= count - 1: chosen_file = dir_file.pop(index) filename = LocalData.get_shared_filename(chosen_file) filemd5 = LocalData.get_shared_filemd5(chosen_file) filedim = LocalData.get_shared_dim(chosen_file) if not LocalData.exist_shared_file(filename, filemd5, filedim): LocalData.add_shared_file(filename, filemd5, filedim) shell.print_green('\nThe file is now shared.') else: shell.print_yellow('\nThe file is already shared.') break else: shell.print_red(f'\nWrong index: number in range 1 - {count} expected.') continue elif choice == "DEFF": if not LocalData.get_shared_files(): shell.print_yellow('\nNo file in sharing.') return for count, file in enumerate(LocalData.get_shared_files(), 1): print(f'\n{count}) {LocalData.get_shared_filename(file)}', end='') shell.print_yellow(f' {LocalData.get_shared_filemd5(file)}', end='') print(f' size: {LocalData.get_shared_dim(file)}') while True: index = input('\nPlease select a file to delete from sharing(pres q to exit): ') if index == 'q': print('\n') return try: index = int(index) - 1 except ValueError: shell.print_red(f'\nWrong index: number in range 1 - {count} expected.') continue if 0 <= index <= count - 1: deleted_file = LocalData.get_shared_file_by_index(index) shell.print_blue(f'\n{LocalData.get_shared_filename(deleted_file)}', end='') shell.print_yellow(f' {LocalData.get_shared_filemd5(deleted_file)}', end='') shell.print_blue(' removed from sharing.') break else: shell.print_red(f'\nWrong index: number in range 1 - {count} expected.') continue elif choice == "QUER": while True: search = input('\nEnter the file name: ') if search != '*': search = '%' + search + '%' if not 0 < len(search) <= 20: shell.print_red('\nFile name must be between 1 and 20 chars long.\n') continue break # Read matching files from DB try: conn = database.get_connection(db_file) conn.row_factory = database.sqlite3.Row except database.Error as e: shell.print_red(f'\nError while getting connection from database: {e}') return try: total_db_file = file_repository.get_files_count_by_querystring(conn, search) if total_db_file == 0: shell.print_yellow('\nNo matching results from your peers.\n') else: shell.print_green('\nFiles from your logged peers:\n') file_rows = file_repository.get_files_by_querystring(conn, search) # print('\nFile from peers: ') for file_row in file_rows: file_md5 = file_row['file_md5'] file_name = file_row['file_name'] owner_rows = peer_repository.get_peers_by_file(conn, file_md5) for owner_row in owner_rows: owner_ip = owner_row['ip'] owner_port = int(owner_row['port']) ip4_peer, ip6_peer = net_utils.get_ip_pair(owner_ip) # stampa di debug # print(f'\n{LocalData.menu_peer_file_index(ip4_peer, ip6_peer, peer.port, file.file_md5, file.file_name)}', end='') # shell.print_yellow(f' {file.file_md5}', end='') # print(f' {file.file_name} from {ip4_peer|ip6_peer} on port {peer.port}') LocalData.add_menu_peer_file(ip4_peer, ip6_peer, owner_port, file_md5, file_name) index = LocalData.menu_peer_file_index(ip4_peer, ip6_peer, owner_port, file_md5, file_name) print(f'{index +1}] ', end='') print(f'{file_name} ', end='') shell.print_yellow(f'md5={file_md5} ', end='') print(f'({ip4_peer}|{ip6_peer} [{owner_port}])') conn.commit() conn.close() except database.Error as e: conn.rollback() conn.close() LocalData.clear_menu_peer_files() shell.print_red(f'\nError while retrieving data from database: {e}') # Send a search for a file on the superpeer network shell.print_green('\nFiles from the network:\n') pktid = str(uuid.uuid4().hex[:16].upper()) ip = net_utils.get_local_ip_for_response() port = net_utils.get_aque_port() ttl = '05' packet = choice + pktid + ip + str(port).zfill(5) + ttl + search.ljust(20) LocalData.set_sent_menu_quer_packet(pktid) server = ServerThread(port, MenuTimedResponseHandler()) server.daemon = True server.start() spinner = SpinnerThread('Searching files (ENTER to continue)', 'Research done! (ENTER to continue)') spinner.start() timer = Timer(20, lambda: (spinner.stop(), server.stop())) timer.start() self.__broadcast(packet) input() print('\033[1A', end='\r') if timer.is_alive(): spinner.stop() spinner.join() timer.cancel() timer.join() server.stop() server.join() else: spinner.join() timer.join() server.join() # Retrieving the list of database's files and superpeer network's files peer_files = LocalData.get_menu_peer_files() if len(peer_files) == total_db_file: shell.print_yellow('\nNo matching results from the superpeer network.\n') if len(peer_files) < 1: shell.print_yellow('\nNo file matching the keyword.\n') return while True: index = input('\nPlease select a file to download: ') if index == 'q': print('\n') LocalData.clear_menu_peer_files() return try: index = int(index) - 1 except ValueError: shell.print_red(f'\nWrong index: number in range 1 - {len(peer_files)} expected.') continue if 0 <= index <= len(peer_files): chosen_peer_file = LocalData.get_menu_peer_file_by_index(index) host_ip4 = LocalData.get_menu_file_owner_ip4(chosen_peer_file) host_ip6 = LocalData.get_menu_file_owner_ip6(chosen_peer_file) host_port = LocalData.get_menu_file_owner_port(chosen_peer_file) file_md5 = LocalData.get_menu_file_md5(chosen_peer_file) file_name = LocalData.get_menu_file_name(chosen_peer_file) # preparo packet per retr, faccio partire server in attesa download, invio packet e attendo packet = 'RETR' + file_md5 try: Downloader(host_ip4, host_ip6, host_port, packet, file_name).start() shell.print_green(f'\nDownload of {file_name} completed.\n') LocalData.clear_menu_peer_files() except OSError: shell.print_red(f'\nError while downloading {file_name}\n') break else: shell.print_red(f'\nWrong index: number in range 1 - {len(peer_files)} expected.') continue elif choice == "LISTSUPERPEERS": shell.print_green('\nList of known superpeers:') if not LocalData.get_super_friends(): shell.print_red('You do not know any superpeers.') else: for count, friend in enumerate(LocalData.get_super_friends(), 1): friend_ip4 = LocalData.get_super_friend_ip4(friend) friend_ip6 = LocalData.get_super_friend_ip6(friend) friend_port = LocalData.get_super_friend_port(friend) shell.print_blue(f'{count}] {friend_ip4} {friend_ip6} {str(friend_port)}') elif choice == "LISTPEERS": try: conn = database.get_connection(db_file) conn.row_factory = database.sqlite3.Row except database.Error as e: print(f'Error: {e}') print('The server has encountered an error while trying to serve the request.') return try: peer_list = peer_repository.find_all(conn) if not peer_list: shell.print_red('You do not know any peers.') conn.close() return else: shell.print_green('\nList of known peers:') for count, peer_row in enumerate(peer_list, 1): shell.print_blue(f'{count}]' + peer_row['ip'] + peer_row['port'] + '\n') except database.Error as e: conn.rollback() conn.close() print(f'Error: {e}') print('The server has encountered an error while trying to serve the request.') return elif choice == "LISTFILES": try: conn = database.get_connection(db_file) conn.row_factory = database.sqlite3.Row except database.Error as e: print(f'Error: {e}') print('The server has encountered an error while trying to serve the request.') return try: files = file_repository.find_all(conn) shell.print_green('\nYour shared files:') if not LocalData.get_shared_files(): shell.print_red('You do not have shared files.') for count, shared_file in enumerate(LocalData.get_shared_files(), 1): print(f'{count}] {LocalData.get_shared_filename(shared_file)} ', end='') shell.print_yellow(f'{LocalData.get_shared_filemd5(shared_file)}\n') shell.print_green('\nLogged peers files:') if not files: shell.print_red('You do not have logged peers files.') conn.close() return for count, file_row in enumerate(files, 1): print(f'{count}] {file_row["file_name"]} ', end='') shell.print_yellow(f'{file_row["file_md5"]}') except database.Error as e: conn.rollback() conn.close() print(f'Error: {e}') print('The server has encountered an error while trying to serve the request.') return else: pass
def startup(): while True: # verifico se ho superpeer e file in sharing nel json (ossia se il peer è crashato) if LocalData.superpeer_is_empty(): while True: shell.print_blue( '\nThis process will allow you to add your known peer.\n') superpeer = net_utils.prompt_friend_request() LocalData.set_superpeer(superpeer) # 1) Lancia una SUPE al nodo conosciuto pktid = str(uuid.uuid4().hex[:16].upper()) ip = net_utils.get_local_ip_for_response() port = str(net_utils.get_network_port()).zfill(5) ttl = '04' packet = 'SUPE' + pktid + ip + port + ttl super_ip4 = LocalData.get_superpeer_ip4() super_ip6 = LocalData.get_superpeer_ip6() super_port = LocalData.get_superpeer_port() LocalData.set_sent_packet(pktid) server = ServerThread( net_utils.get_network_port(), TimedResponseHandler.TimedResponseHandler()) server.start() spinner = SpinnerThread('Trying to login', '') spinner.start() try: net_utils.send_packet_and_close(super_ip4, super_ip6, super_port, packet) except socket.error as e: shell.print_red( f'There was an error in the login process: {e}') continue # 2) Attende ASUP per 20 sec timer = Timer(20, lambda: (server.stop(), spinner.stop())) timer.start() timer.join() spinner.join() # 3) Se non è possibile agganciarsi ad un super, devo far reinserire il peer all'utente if len(LocalData.get_superpeer_candidates()) == 0: shell.print_red( 'Cannot contact a superpeer from the peer you provide, please retry.' ) continue # 3) Se il peer aggiunto era veramente un superpeer, allora non lo cambio elif LocalData.get_superpeer( ) in LocalData.get_superpeer_candidates(): break # 3) Se invece era un superpeer falso, pesco un super a random dalla lista dei candidati else: index = random.randint( 0, len(LocalData.get_superpeer_candidates()) - 1) superpeer = LocalData.get_superpeer_candidate_by_index( index) LocalData.set_superpeer(superpeer) break # Lancio una LOGI al superpeer scelto ip = net_utils.get_local_ip_for_response() port = str(net_utils.get_network_port()).zfill(5) packet = "LOGI" + ip + port super_ip4 = LocalData.get_superpeer_ip4() super_ip6 = LocalData.get_superpeer_ip6() super_port = LocalData.get_superpeer_port() try: sock = net_utils.send_packet(super_ip4, super_ip6, super_port, packet) response = sock.recv(100).decode() if len(response) != 20: shell.print_red( f'There was an error in the login process: unexpected: {response}.\nPlease retry.' ) LocalData.clear_backup_data() continue session_id = response[4:20] if session_id == '0' * 16: shell.print_red( f'There was an error in the login process: unexpected session_id: {session_id}.\nPlease retry.' ) LocalData.clear_backup_data() continue LocalData.session_id = response[4:20] break except (socket.error, AttributeError): shell.print_yellow( f'Unable to contact {super_ip4}|{super_ip6} [{super_port}]') # pulisco il file json da file in sharing e superpeer vecchio LocalData.clear_backup_data() if sock is not None: sock.close() continue shell.print_green( f'Successfully logged to the superpeer: {super_ip4}|{super_ip6} [{super_port}]\n' ) log = Logger.Logger('peer/peer.log') server = ServerThread(net_utils.get_network_port(), NetworkHandler.NetworkHandler(log)) server.daemon = True server.start() Menu(MenuHandler.MenuHandler()).show()
def serve(self, sd: socket.socket) -> None: """ Handle the peer request :param sd: the socket descriptor used for read the request :return None """ try: command = sd.recv(4).decode() except OSError as e: shell_colors.print_red( f'\nUnable to read the command from the socket: {e}\n') sd.close() return if command == "AQUE": try: response = sd.recv(300).decode() except socket.error as e: shell_colors.print_red( f'\nUnable to read the {command} response from the socket: {e}\n' ) sd.close() return sd.close() if len(response) != 208: print( f"\nInvalid response: {command} -> {response}. Expected: AQUE<pkt_id><ip_peer><port_peer><fileMD5><filename>\n" ) return pktid = response[0:16] ip_peer = response[16:71] ip4_peer, ip6_peer = net_utils.get_ip_pair(ip_peer) port_peer = int(response[71:76]) filemd5 = response[76:108] filename = response[108:208].lower().lstrip().rstrip() if pktid != AppData.get_sent_packet(): sd.close() return if not AppData.exist_peer_files(ip4_peer, ip6_peer, port_peer, filemd5, filename): AppData.add_peer_files(ip4_peer, ip6_peer, port_peer, filemd5, filename) index = AppData.peer_file_index(ip4_peer, ip6_peer, port_peer, filemd5, filename) print(f'{index +1}] ', end='') shell_colors.print_blue(f'{filename} ', end='') shell_colors.print_yellow(f'md5={filemd5} ', end='') print(f'({ip4_peer}|{ip6_peer} [{port_peer}])') elif command == "ANEA": try: response = sd.recv(300).decode() except socket.error as e: shell_colors.print_red( f'\nUnable to read the {command} response from the socket: {e}\n' ) sd.close() return sd.close() if len(response) != 76: shell_colors.print_red( f"\nInvalid response: : {command} -> {response}. Expected: ANEA<pkt_id><ip_peer><port_peer>" ) return pktid = response[0:16] ip_peer = response[16:71] ip4_peer, ip6_peer = net_utils.get_ip_pair(ip_peer) port_peer = int(response[71:76]) if pktid != AppData.get_sent_packet(): return if len(AppData.get_neighbours()) >= 5: return if not AppData.is_neighbour(ip4_peer, ip6_peer, port_peer): AppData.add_neighbour(ip4_peer, ip6_peer, port_peer) shell_colors.print_green('New neighbour found: ', end='') print(f'{ip4_peer}|{ip6_peer} [{port_peer}]') else: wrong_response = sd.recv(300).decode() sd.close() shell_colors.print_red( f"\nInvalid response: {command} -> {wrong_response}\n") return
def serve(choice: str) -> None: """ Handle the peer packet :param choice: the choice to handle :return: None """ tracker_ip4 = LocalData.get_tracker_ip4() tracker_ip6 = LocalData.get_tracker_ip6() tracker_port = LocalData.get_tracker_port() ssid = LocalData.get_session_id() log = Logger.Logger('peer/peer.log') if choice == "LOOK": # Search a file while True: search = input('\nInsert file\'s name (q to cancel): ') if search == "q": print('\n') return if not 0 < len(search) <= 20: shell.print_red( '\nQuery string must be a valid value (1 - 20 chars).') continue break packet = choice + ssid + search.ljust(20) sd = None try: sd = net_utils.send_packet(tracker_ip4, tracker_ip6, tracker_port, packet) except net_utils.socket.error as e: shell.print_red( f'\nError while sending the request to the tracker: {tracker_ip4}|{tracker_ip6} [{tracker_port}].' ) shell.print_red(f'Error: {e}') if sd is not None: sd.close() return # Receiving the response list try: command = sd.recv(4).decode() except net_utils.socket.error as e: shell.print_red( f'Unable to read the command from the socket: {e}\n') sd.close() return if command != 'ALOO': shell.print_red( f'\nReceived a packet with a wrong command ({command}).') return try: num_files = int(sd.recv(3).decode()) except net_utils.socket.error as e: shell.print_red( f'Unable to read the command from the socket: {e}\n') sd.close() return if num_files == 0: shell.print_yellow(f'{search} not found.\n') sd.close() return downloadables = list() for i in range(num_files): try: file_md5 = sd.recv(32).decode() file_name = sd.recv(100).decode().lstrip().rstrip() len_file = int(sd.recv(10)) len_part = int(sd.recv(6)) except net_utils.socket.error as e: shell.print_red( f'\nError while receiving the response from the tracker: {e}\n' ) continue except ValueError: shell.print_red(f'\nInvalid packet from tracker: {e}\n') continue downloadables.append((file_md5, file_name, len_file, len_part)) sd.close() if not downloadables: shell.print_red( f'\nSomething went wrong while retrieving {search}\n') return shell.print_green(f'\nFiles found:') for count, downloadable in enumerate(downloadables, 1): print( f'{count}] {LocalData.get_downloadable_file_name(downloadable)} | ', end='') shell.print_yellow( f'{LocalData.get_downloadable_file_md5(downloadable)}') # Download choice while True: file_index = input( '\nChoose a file to download (q to cancel): ') if file_index == "q": return try: file_index = int(file_index) - 1 except ValueError: shell.print_red( f'\nWrong index: number in range 1 - {len(downloadables)} expected\n' ) continue if not 0 <= file_index <= len(downloadables) - 1: shell.print_red( f'\nWrong index: number in range 1 - {len(downloadables)} expected\n' ) continue else: choosed_file_md5 = LocalData.get_downloadable_file_md5( downloadables[file_index]) choosed_file_name = LocalData.get_downloadable_file_name( downloadables[file_index]) if LocalData.is_shared_file(choosed_file_md5, choosed_file_name): shell.print_green( f'\nYou already have downloaded {choosed_file_name}.' ) continue choosed_file_lenght = LocalData.get_downloadable_file_length( downloadables[file_index]) choosed_file_part_lenght = LocalData.get_downloadable_file_part_length( downloadables[file_index]) break choosed_file_parts = int( math.ceil(choosed_file_lenght / choosed_file_part_lenght)) choosed_file_part_list_length = int( math.ceil(choosed_file_parts / 8)) # Download phase LocalData.create_downloading_part_list( choosed_file_part_list_length) # 1) Initiating the thread responsible for update of the part_list_table in background update_event = Event() updater_thread = UpdaterThread.UpdaterThread( choosed_file_md5, choosed_file_part_list_length, update_event, log) updater_thread.start() # 2) Create the new file f_obj = open(f'shared/{choosed_file_name}', 'wb') f_obj.close() LocalData.set_num_parts_owned(0) progress_bar.print_progress_bar(0, choosed_file_parts, prefix='Downloading:', suffix='Complete', length=50) # Adding the file to the shared file list LocalData.add_shared_file(choosed_file_md5, choosed_file_name) # Until all the parts hasn't been downloaded while choosed_file_parts != LocalData.get_num_parts_owned(): update_event.wait(70) update_event.clear() # We can use a with statement to ensure threads are cleaned up promptly with ThreadPoolExecutor(max_workers=10) as executor: # Get the file parts we don't have yet downloadable_parts = LocalData.get_downloadable_parts() for part_num in downloadable_parts: try: # Start the load operations executor.submit(download_task.run, choosed_file_md5, choosed_file_name, part_num, choosed_file_part_lenght, choosed_file_parts, log) except OSError as e: log.write_red( f'\nError while downloading {choosed_file_name}: {e}' ) executor.shutdown() updater_thread.stop() shell.print_green('\nDownload completed.') elif choice == "ADDR": # check if shared directory exist if not os.path.exists('shared'): shell.print_red('\nCannot find the shared folder.') return # check for file available in shared directory if not os.listdir('shared'): shell.print_yellow( 'No file available for sharing.\nAdd files to shared dir to get started.\n' ) return temp_files = [] shell.print_blue('\nFiles available for sharing:') for count, file in enumerate(os.scandir('shared'), 1): # print scandir results file_md5 = hasher.get_md5(f'shared/{file.name}') print(f'{count}] {file.name} | {file_md5}') temp_files.append((file_md5, file.name)) while True: file_index = input('\nChoose a file to share (q to cancel): ') if file_index == "q": return try: file_index = int(file_index) - 1 except ValueError: shell.print_red( f'\nWrong index: number in range 1 - {len(temp_files)} expected\n' ) continue if 0 <= file_index <= len(temp_files) - 1: file_name = LocalData.get_shared_file_name( temp_files[file_index]) file_md5 = LocalData.get_shared_file_md5( temp_files[file_index]) # check if file is already in sharing if not LocalData.is_shared_file(file_md5, file_name): try: f_obj = open('shared/' + file_name, 'rb') except OSError as e: shell.print_red( f'Cannot open the file to upload: {e}') return try: filesize = str(os.fstat(f_obj.fileno()).st_size) except OSError as e: shell.print_red(f'Something went wrong: {e}') return except ValueError as e: shell.print_red( f'\nUnable to convert filesize in string: {e}\n' ) return part_size = str(net_utils.get_part_size()) # build packet and sent to tracker packet = choice + ssid + filesize.zfill( 10) + part_size.zfill(6) + file_name.ljust( 100) + file_md5 sd = None try: sd = net_utils.send_packet(tracker_ip4, tracker_ip6, tracker_port, packet) except net_utils.socket.error as e: shell.print_red( f'\nError while sending the request to the tracker: {tracker_ip4}|{tracker_ip6} [{tracker_port}].' ) shell.print_red(f'Error: {e}') if sd is not None: sd.close() return try: response = sd.recv(200).decode() except net_utils.socket.error as e: shell.print_red( f'Unable to read the response from the socket: {e}\n' ) sd.close() return sd.close() if len(response) != 12: shell.print_red( f"Invalid response: : {response}. Expected: AADR<num_part>" ) return command = response[0:4] if command != 'AADR': shell.print_red( f'\nReceived a packet with a wrong command ({command}).' ) return num_part = response[4:12] # add file to shared_files LocalData.add_shared_file(file_md5, file_name) shell.print_blue( f'\nNew shared file added {file_name} | {file_md5}', end='') shell.print_green(f' #parts: {num_part}') break else: # if not in sharing shell.print_yellow( f'\n{file_name} | {file_md5} already in sharing.\n' ) break else: shell.print_red( f'\nWrong index: number in range 1 - {len(temp_files)} expected\n' ) continue elif choice == "LOGO": packet = choice + ssid sd = None try: sd = net_utils.send_packet(tracker_ip4, tracker_ip6, tracker_port, packet) except net_utils.socket.error as e: shell.print_red( f'\nError while sending the request to the tracker: {tracker_ip4}|{tracker_ip6} [{tracker_port}].' ) shell.print_red(f'{e}') if sd is not None: sd.close() return try: response = sd.recv(50).decode() except net_utils.socket.error as e: shell.print_red( f'Unable to read the response from the socket: {e}\n') sd.close() return sd.close() if len(response) != 14: shell.print_red( f"Invalid response form the socket: {response}.") return command = response[0:4] if command == "ALOG": part_own = int(response[4:14]) shell.print_green('\nSuccessfully logged out') shell.print_blue( f'{part_own} parts has been removed from sharing.\n') LocalData.clear_tracker() elif command == "NLOG": part_down = int(response[4:14]) shell.print_yellow( f'\nUnable to logout:\nYou have shared only {part_down} parts with other peer.\n' ) else: shell.print_red( f'\nReceived a packet with a wrong command from the socket: {command} -> {response}' ) elif choice == 'SHAR': files = LocalData.get_shared_files() if not files: shell.print_red('\nYou currently have no files in sharing.') print('\nFiles actually in sharing:') for count, file in enumerate(files, 1): print(f'{count}] {LocalData.get_downloadable_file_name(file)}') elif choice == 'TRAC': shell.print_green( f'\nYour tracker is: {LocalData.get_tracker_ip4()}|{LocalData.get_tracker_ip6()} [{LocalData.get_tracker_port()}]' ) else: shell.print_yellow( f'\nInvalid input code: "{choice}".\nPlease retry.\n') return
def serve(choice: str) -> None: """ Handle the peer packet :param choice: the choice to handle :return: None """ sp_ip4 = LocalData.get_superpeer_ip4() sp_ip6 = LocalData.get_superpeer_ip6() sp_port = LocalData.get_superpeer_port() p_ssid = LocalData.session_id if choice == "ADFF": # check se shared dir esiste if not os.path.exists('shared'): shell.print_red('\nCannot find the shared folder.') return # se non ci sono file nella shared dir avvisa ed esce if not os.scandir('shared'): shell.print_yellow( 'No file available for sharing. Add files to shared dir to get started.\n' ) return temp_files = [] shell.print_blue('\nFiles available for sharing:') for count, file in enumerate(os.scandir('shared'), 1): # stampa i risultati della scandir file_md5 = hasher.get_md5(f'shared/{file.name}') print(f'{count}] {file.name} | {file_md5}') temp_files.append((file_md5, file.name)) while True: index = input('Choose a file to share (q to cancel): ') if index == "q": print('\n') return try: index = int(index) - 1 except ValueError: shell.print_red( f'\nWrong index: number in range 1 - {len(temp_files)} expected\n' ) continue if 0 <= index <= len(temp_files) - 1: file_name = LocalData.get_shared_file_name( temp_files[index]) file_md5 = LocalData.get_shared_file_md5(temp_files[index]) # controlla se il file è già in condivisione if not LocalData.is_shared_file(temp_files[index]): # crea il pacchetto e lo invia al super peer packet = choice + p_ssid + file_md5 + file_name.ljust( 100) try: net_utils.send_packet_and_close( sp_ip4, sp_ip6, sp_port, packet) shell.print_green( f'Packet sent to supernode: {sp_ip4}|{sp_ip6} [{sp_port}]' ) except net_utils.socket.error: shell.print_red( f'\nError while sending packet to supernode: {sp_ip4}|{sp_ip6} [{sp_port}]\n' ) # aggiunge il file alla struttura dati ed esce LocalData.add_shared_file(file_md5, file_name) shell.print_blue( f'\nNew shared file added {file_name} | {file_md5}' ) break else: # il file è già in condivisione shell.print_yellow( f'\n{file_name} | {file_md5} already in sharing.\n' ) break else: shell.print_red( f'\nWrong index: number in range 1 - {len(temp_files)} expected\n' ) continue elif choice == "DEFF": # recupera i files in sharing files = LocalData.get_shared_files() # check se ci sono file in sharing if not files: shell.print_yellow( 'No files currently in sharing. Add files choosing the command from the menu.\n' ) return # scelta del file da rimuovere shell.print_blue('\nFile currently in sharing:') for count, file in enumerate(files, 1): print( f'{count}] {LocalData.get_shared_file_name(file)} | {LocalData.get_shared_file_md5(file)}' ) while True: index = input( 'Choose a file to remove from sharing (q to cancel): ') if index == "q": print('\n') return try: index = int(index) - 1 except ValueError: shell.print_red( f'\nWrong index: number in range 1 - {len(files)} expected\n' ) continue if 0 <= index <= len(files) - 1: # recupera il file dalla DS file = LocalData.get_shared_file(index) # crea ed invia il pacchetto al supernode packet = choice + p_ssid + LocalData.get_shared_file_md5( file) try: net_utils.send_packet_and_close( sp_ip4, sp_ip6, sp_port, packet) except net_utils.socket.error: shell.print_red( f'\nError while sending packet to supernode: {sp_ip4}|{sp_ip6} [{sp_port}]\n' ) # rimuove il file dalla DS LocalData.remove_shared_file(file) shell.print_green( f'\n{LocalData.get_shared_file_name(file)} | {LocalData.get_shared_file_md5(file)} removed successfully.' ) break else: shell.print_red( f'\nWrong index: number in range 1 - {len(files)} expected\n' ) continue elif choice == "FIND": while True: search = input('\nInsert file\'s name (q to cancel): ') if search == "q": print('\n') return if not 0 < len(search) <= 20: shell.print_red( '\nQuery string must be a valid value (1 - 20 chars).') continue break packet = choice + p_ssid + search.ljust(20) try: socket = net_utils.send_packet(sp_ip4, sp_ip6, sp_port, packet) except (net_utils.socket.error, AttributeError): shell.print_red( f'\nError while sending the request to the superpeer: {sp_ip4}|{sp_ip6} [{sp_port}].\n' ) if socket is not None: socket.close() return spinner = SpinnerThread('Searching files', 'Research done!') spinner.start() try: socket.settimeout(25) command = socket.recv(4).decode() spinner.stop() spinner.join() print('\033[1A', end='\r') if command != "AFIN": shell.print_red( f'\nReceived a packet with a wrong command ({command}).\n' ) socket.close() return except net_utils.socket.error: shell.print_red( f'\nError while receiving the response from the superpeer: {sp_ip4}|{sp_ip6} [{sp_port}].\n' ) return except ValueError: shell.print_red( f'\nInvalid packet from superpeer: {sp_ip4}|{sp_ip6} [{sp_port}].\n' ) return # ('file_name', 'file_md5', owners[]) downloadables = list() try: num_downloadables = int(socket.recv(3)) # check se ci sono file da scaricare if num_downloadables == 0: shell.print_yellow(f'{search} not found.\n') socket.close() return except net_utils.socket.error: shell.print_red( f'\nError while receiving the response from the superpeer: {sp_ip4}|{sp_ip6} [{sp_port}].\n' ) return for i in range(num_downloadables): # ('owner_ip4', 'owner_ip6', 'owner_port') owners = list() try: file_md5 = socket.recv(32).decode() file_name = socket.recv(100).decode().lstrip().rstrip() num_copies = int(socket.recv(3)) except net_utils.socket.error: shell.print_red( f'\nError while receiving the response from the superpeer: {sp_ip4}|{sp_ip6} [{sp_port}].\n' ) continue except ValueError: shell.print_red( f'\nInvalid packet from superpeer: {sp_ip4}|{sp_ip6} [{sp_port}].\n' ) continue for j in range(num_copies): try: (owner_ip4, owner_ip6) = net_utils.get_ip_pair( socket.recv(55).decode()) owner_port = int(socket.recv(5)) owners.append((owner_ip4, owner_ip6, owner_port)) except net_utils.socket.error: shell.print_red( f'\nError while receiving the response from the superpeer: {sp_ip4}|{sp_ip6} [{sp_port}].\n' ) continue except ValueError: shell.print_red( f'\nInvalid packet from superpeer: {sp_ip4}|{sp_ip6} [{sp_port}].\n' ) continue if owners: # prepara una lista con tutti i file che possono essere scaricati downloadables.append((file_name, file_md5, owners)) if not downloadables: shell.print_red( f'\nSomething went wrong while retrieving {search}\n') socket.close() return shell.print_green(f'\nFiles found:') for count, downloadable in enumerate(downloadables, 1): print(f'{count}] {downloadable[0]} | {downloadable[1]}') while True: choosed_file_index = input( 'Choose a file to download (q to cancel): ') if choosed_file_index == "q": print('\n') socket.close() return try: choosed_file_index = int(choosed_file_index) - 1 except ValueError: shell.print_red( f'\nWrong index: number in range 1 - {len(downloadables)} expected\n' ) continue if not 0 <= choosed_file_index <= len(downloadables) - 1: shell.print_red( f'\nWrong index: number in range 1 - {len(downloadables)} expected\n' ) continue else: choosed_file_name = downloadables[choosed_file_index][0] choosed_file_md5 = downloadables[choosed_file_index][1] choosed_file_owners = downloadables[choosed_file_index][2] shell.print_green( f'\nAvailable sources for {choosed_file_name}:') for count, choosed_file_owner in enumerate( choosed_file_owners, 1): print( f'{count}] {choosed_file_owner[0]}|{choosed_file_owner[1]} [{choosed_file_owner[2]}]' ) while True: choosed_owner_index = input( f'Choose a source for {choosed_file_name} (q to cancel): ' ) if choosed_owner_index == "q": print('\n') return try: choosed_owner_index = int(choosed_owner_index) - 1 except ValueError: shell.print_red( f'\nWrong index: number in range 1 - {len(choosed_file_owners)} expected\n' ) continue if 0 <= choosed_owner_index <= len( choosed_file_owners) - 1: packet = "RETR" + choosed_file_md5 try: Downloader( choosed_file_owners[choosed_owner_index] [0], choosed_file_owners[choosed_owner_index] [1], choosed_file_owners[choosed_owner_index] [2], packet, choosed_file_name).start() shell.print_green( f'\n{choosed_file_name} downloaded successfully.\n' ) except OSError: shell.print_red( f'\nError while downloading {choosed_file_name}.\n' ) break else: shell.print_red( f'\nWrong index: number in range 1 - {len(choosed_file_owners)} expected\n' ) continue break elif choice == "SHOWSUPER": print( f'\nYour current superpeer is: {sp_ip4}|{sp_ip6} [{sp_port}]\n' ) elif choice == "LOGO": packet = choice + p_ssid sock = net_utils.send_packet(sp_ip4, sp_ip6, sp_port, packet) try: command = sock.recv(4).decode() if command != "ALGO": shell.print_red( f'\nWrong response code "{command}": "{choice}" expected.\n' ) num_files = int(sock.recv(3)) shell.print_blue( f'\n{num_files} files has been removed from sharing.\n') except (net_utils.socket.error, AttributeError): shell.print_red( f'\nError while receiving the response for "{choice}".\n') LocalData.clear_backup_data() else: pass
#!/usr/bin/env python from service.ServerThread import ServerThread from service.Menu import Menu from handler.NeighboursHandler import NeighboursHandler from handler.MenuHandler import MenuHandler from utils import shell_colors as shell import os from utils import net_utils, Logger, hasher from service.AppData import AppData if __name__ == '__main__': shell.print_red(' ____ ___ ___ _ ', end='') shell.print_yellow(' _ _ ') shell.print_red('| _ \ / _ \ / _ \| |_ ', end='') shell.print_yellow('___| | | __ _ ') shell.print_red('| |_) | | | | | | | __/', end='') shell.print_yellow(' _ \ | |/ _` |') shell.print_red('| _ <| |_| | |_| | |', end='') shell.print_yellow('| __/ | | (_| |') shell.print_red('|_| \__\\___/ \___/ \__', end='') shell.print_yellow('\___|_|_|\__,_|') if not os.path.exists('shared'): os.mkdir('shared') for dir_entry in os.scandir('shared'): AppData.add_shared_file(dir_entry.name, hasher.get_md5(dir_entry.path), dir_entry.stat().st_size)
def serve(self, choice: str) -> None: """ Handle the peer packet :param choice: the choice to handle :return: None """ if choice == "LISTFILES": try: conn = database.get_connection(self.db_file) conn.row_factory = database.sqlite3.Row except database.Error as e: print(f'Error: {e}') print( 'The server has encountered an error while trying to serve the request.' ) return try: files = file_repository.find_all(conn) shell.print_green('\nLogged peers files:') if not files: shell.print_red('There are not logged peers files.') for count, shared_file in enumerate(files, 1): print(f'{count}] {shared_file["file_name"]} ', end='') shell.print_yellow(f'{shared_file["file_md5"]}\n') except database.Error as e: conn.rollback() conn.close() print(f'Error: {e}') print( 'The server has encountered an error while trying to serve the request.' ) return elif choice == "SHOWPARTS": try: conn = database.get_connection(self.db_file) conn.row_factory = database.sqlite3.Row except database.Error as e: print(f'Error: {e}') print( 'The server has encountered an error while trying to serve the request.' ) return peer_list = peer_repository.find_all(conn) if not peer_list: shell.print_red('There are no logged peers.') conn.close() return else: shell.print_green('\nList of known peers:') for count, peer_row in enumerate(peer_list, 1): shell.print_blue(f'{count}]' + peer_row['ip'] + peer_row['port'] + '\n') while True: index = input('\nPlease select a peer(q to cancel): ') if index == 'q': print('\n') return try: index = int(index) - 1 except ValueError: shell.print_red( f'\nWrong index: number in range 1 - {len(peer_list)} expected.' ) continue if 0 <= index <= len(peer_list): chosen_peer = peer_list.pop(index) peer_session_id = chosen_peer['session_id'] file_rows = file_repository.get_all_peer_files( conn, peer_session_id) if not file_rows: shell.print_red('This peer has no file\'s parts') conn.close() return for count, file_row in enumerate(file_rows, 1): file_name = file_row['file_name'] file_md5 = file_row['file_md5'] part_list = bytearray( file_repository.get_part_list_by_file_and_owner( conn, file_md5, peer_session_id)) print(f'{count}] ', end='') shell.print_blue(f'{file_name}|{file_md5} -> ', end='') for byte_index in range(len(part_list)): print( f'{bin(part_list[byte_index])[2:].zfill(8)} ', end='') print('') return () else: shell.print_red( f'\nWrong index: number in range 1 - {len(peer_list)} expected.' ) continue elif choice == "LISTPEERS": try: conn = database.get_connection(self.db_file) conn.row_factory = database.sqlite3.Row except database.Error as e: print(f'Error: {e}') print( 'The server has encountered an error while trying to serve the request.' ) return try: peer_list = peer_repository.find_all(conn) if not peer_list: shell.print_red('There are not logged peers.') conn.close() return else: shell.print_green('\nList of known peers:') for count, peer_row in enumerate(peer_list, 1): shell.print_blue(f'{count}]' + peer_row['ip'] + peer_row['port'] + '\n') except database.Error as e: conn.rollback() conn.close() print(f'Error: {e}') print( 'The server has encountered an error while trying to serve the request.' ) return else: pass