feat(udp): summary command completed
This commit is contained in:
		| @@ -9,9 +9,10 @@ WORKDIR /server | |||||||
|  |  | ||||||
| # Create files with random content in the /server directory | # Create files with random content in the /server directory | ||||||
| RUN mkdir /server_directory | RUN mkdir /server_directory | ||||||
| # these files is only 750 bytes |  | ||||||
|  | # These files is only 750 bytes, can fit inside a UDP/TCP packet | ||||||
| RUN dd if=/dev/urandom of=/server_directory/file_server.txt bs=1 count=750 | RUN dd if=/dev/urandom of=/server_directory/file_server.txt bs=1 count=750 | ||||||
| RUN dd if=/dev/urandom of=/server_directory/image_server.png bs=1 count=750 | RUN dd if=/dev/urandom of=/server_directory/image_server.png bs=1 count=750 | ||||||
|  |  | ||||||
| # Start your Python application | # generate a file that has random numbers | ||||||
| #CMD python server.py --port_number 12000 --debug 1 | RUN for _ in $(seq 1 150); do shuf -i 0-1000 -n 1 >> /server_directory/numbers.txt; done | ||||||
|   | |||||||
							
								
								
									
										150
									
								
								server_directory/numbers.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								server_directory/numbers.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,150 @@ | |||||||
|  | 970 | ||||||
|  | 408 | ||||||
|  | 627 | ||||||
|  | 774 | ||||||
|  | 374 | ||||||
|  | 425 | ||||||
|  | 292 | ||||||
|  | 570 | ||||||
|  | 681 | ||||||
|  | 971 | ||||||
|  | 141 | ||||||
|  | 468 | ||||||
|  | 271 | ||||||
|  | 120 | ||||||
|  | 450 | ||||||
|  | 298 | ||||||
|  | 802 | ||||||
|  | 34 | ||||||
|  | 448 | ||||||
|  | 979 | ||||||
|  | 181 | ||||||
|  | 117 | ||||||
|  | 322 | ||||||
|  | 885 | ||||||
|  | 733 | ||||||
|  | 31 | ||||||
|  | 818 | ||||||
|  | 582 | ||||||
|  | 83 | ||||||
|  | 524 | ||||||
|  | 104 | ||||||
|  | 285 | ||||||
|  | 932 | ||||||
|  | 964 | ||||||
|  | 292 | ||||||
|  | 306 | ||||||
|  | 621 | ||||||
|  | 584 | ||||||
|  | 109 | ||||||
|  | 302 | ||||||
|  | 555 | ||||||
|  | 250 | ||||||
|  | 2 | ||||||
|  | 59 | ||||||
|  | 602 | ||||||
|  | 452 | ||||||
|  | 357 | ||||||
|  | 404 | ||||||
|  | 486 | ||||||
|  | 37 | ||||||
|  | 616 | ||||||
|  | 667 | ||||||
|  | 154 | ||||||
|  | 938 | ||||||
|  | 552 | ||||||
|  | 887 | ||||||
|  | 969 | ||||||
|  | 602 | ||||||
|  | 701 | ||||||
|  | 284 | ||||||
|  | 358 | ||||||
|  | 37 | ||||||
|  | 802 | ||||||
|  | 290 | ||||||
|  | 1 | ||||||
|  | 94 | ||||||
|  | 829 | ||||||
|  | 854 | ||||||
|  | 678 | ||||||
|  | 938 | ||||||
|  | 156 | ||||||
|  | 466 | ||||||
|  | 420 | ||||||
|  | 391 | ||||||
|  | 757 | ||||||
|  | 22 | ||||||
|  | 843 | ||||||
|  | 346 | ||||||
|  | 658 | ||||||
|  | 330 | ||||||
|  | 383 | ||||||
|  | 274 | ||||||
|  | 229 | ||||||
|  | 537 | ||||||
|  | 444 | ||||||
|  | 14 | ||||||
|  | 656 | ||||||
|  | 646 | ||||||
|  | 616 | ||||||
|  | 357 | ||||||
|  | 930 | ||||||
|  | 975 | ||||||
|  | 626 | ||||||
|  | 964 | ||||||
|  | 497 | ||||||
|  | 860 | ||||||
|  | 290 | ||||||
|  | 558 | ||||||
|  | 714 | ||||||
|  | 969 | ||||||
|  | 496 | ||||||
|  | 871 | ||||||
|  | 667 | ||||||
|  | 148 | ||||||
|  | 262 | ||||||
|  | 424 | ||||||
|  | 402 | ||||||
|  | 337 | ||||||
|  | 770 | ||||||
|  | 61 | ||||||
|  | 899 | ||||||
|  | 153 | ||||||
|  | 567 | ||||||
|  | 129 | ||||||
|  | 922 | ||||||
|  | 12 | ||||||
|  | 375 | ||||||
|  | 810 | ||||||
|  | 658 | ||||||
|  | 991 | ||||||
|  | 399 | ||||||
|  | 820 | ||||||
|  | 198 | ||||||
|  | 25 | ||||||
|  | 17 | ||||||
|  | 696 | ||||||
|  | 885 | ||||||
|  | 307 | ||||||
|  | 254 | ||||||
|  | 600 | ||||||
|  | 508 | ||||||
|  | 983 | ||||||
|  | 703 | ||||||
|  | 175 | ||||||
|  | 363 | ||||||
|  | 197 | ||||||
|  | 831 | ||||||
|  | 998 | ||||||
|  | 534 | ||||||
|  | 833 | ||||||
|  | 291 | ||||||
|  | 434 | ||||||
|  | 218 | ||||||
|  | 858 | ||||||
|  | 795 | ||||||
|  | 140 | ||||||
|  | 102 | ||||||
|  | 170 | ||||||
|  | 182 | ||||||
|  | 992 | ||||||
| @@ -112,6 +112,10 @@ class Client: | |||||||
|                         f"myftp> - {self.protocol} - Summary file {filename} from the server" |                         f"myftp> - {self.protocol} - Summary file {filename} from the server" | ||||||
|                     ) if self.debug else None |                     ) if self.debug else None | ||||||
|  |  | ||||||
|  |                     first_byte = (summary_request_opcode << 5) + len(filename) | ||||||
|  |  | ||||||
|  |                     second_byte_to_n_byte = filename.encode("ascii") | ||||||
|  |  | ||||||
|                 # change command handling |                 # change command handling | ||||||
|                 elif change_command_pattern.match(command): |                 elif change_command_pattern.match(command): | ||||||
|                     command_name, old_filename, new_filename = command.split() |                     command_name, old_filename, new_filename = command.split() | ||||||
| @@ -125,7 +129,7 @@ class Client: | |||||||
|                     first_byte: int = unknown_request_opcode << 5 |                     first_byte: int = unknown_request_opcode << 5 | ||||||
|  |  | ||||||
|                 # get or put case |                 # get or put case | ||||||
|                 if command_name == "get": |                 if command_name == "get" or command_name == "summary": | ||||||
|                     payload = first_byte.to_bytes(1, "big") + second_byte_to_n_byte  # type: ignore |                     payload = first_byte.to_bytes(1, "big") + second_byte_to_n_byte  # type: ignore | ||||||
|  |  | ||||||
|                 elif command_name == "put": |                 elif command_name == "put": | ||||||
| @@ -135,9 +139,6 @@ class Client: | |||||||
|                         else first_byte.to_bytes(1, "big")  # type: ignore |                         else first_byte.to_bytes(1, "big")  # type: ignore | ||||||
|                     ) |                     ) | ||||||
|  |  | ||||||
|                 elif command_name == "summary": |  | ||||||
|                     pass |  | ||||||
|  |  | ||||||
|                 elif command == "change": |                 elif command == "change": | ||||||
|                     pass |                     pass | ||||||
|  |  | ||||||
|   | |||||||
| @@ -124,6 +124,20 @@ class Server: | |||||||
|                         filename = None |                         filename = None | ||||||
|                         response_data = None |                         response_data = None | ||||||
|  |  | ||||||
|  |                 elif request_type == "summary": | ||||||
|  |                     # empty filename error | ||||||
|  |                     if filename_length_in_bytes <= 0: | ||||||
|  |                         rescode = rescode_fail_dict["file_not_error_rescode"] | ||||||
|  |                     else: | ||||||
|  |                         ( | ||||||
|  |                             rescode, | ||||||
|  |                             filename,  # "summary.txt" | ||||||
|  |                             filename_length_in_bytes,  # of the summary file | ||||||
|  |                             response_data,  # summary.txt file content | ||||||
|  |                         ) = self.process_summary_req( | ||||||
|  |                             filename_length_in_bytes, req_payload[1:] | ||||||
|  |                         ) | ||||||
|  |  | ||||||
|                 elif request_type == "unknown": |                 elif request_type == "unknown": | ||||||
|                     rescode = rescode_fail_dict["unknown_request_rescode"] |                     rescode = rescode_fail_dict["unknown_request_rescode"] | ||||||
|                     filename_length_in_bytes = None |                     filename_length_in_bytes = None | ||||||
| @@ -174,6 +188,64 @@ class Server: | |||||||
|  |  | ||||||
|         return request_type, filename_length_in_bytes |         return request_type, filename_length_in_bytes | ||||||
|  |  | ||||||
|  |     def process_summary_req( | ||||||
|  |         self, filename_length: int, req_payload: bytes | ||||||
|  |     ) -> Tuple[int, Optional[str], Optional[int], Optional[bytes]]: | ||||||
|  |         """ | ||||||
|  |         Find the filename mentioned | ||||||
|  |         Calculate the min,max,avg | ||||||
|  |         Put those numbers into a file called summary.txt | ||||||
|  |         """ | ||||||
|  |         filename = req_payload[:filename_length].decode("ascii") | ||||||
|  |  | ||||||
|  |         print( | ||||||
|  |             f"myftp> - {self.protocol} - Summarizing the file named {filename} on the server" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         try: | ||||||
|  |             with open(os.path.join(self.directory_path, filename), "r") as file: | ||||||
|  |                 numbers = [int(line.strip()) for line in file if line.strip().isdigit()] | ||||||
|  |  | ||||||
|  |                 # Find the largest, smallest, and calculate the average | ||||||
|  |                 largest_number = max(numbers) | ||||||
|  |                 smallest_number = min(numbers) | ||||||
|  |                 average_value = sum(numbers) / len(numbers) if numbers else 0 | ||||||
|  |  | ||||||
|  |                 print( | ||||||
|  |                     f"myftp> - {self.protocol} - File {filename} summarized successfully. The max is {largest_number}, the min is {smallest_number}, the average is {average_value}" | ||||||
|  |                 ) | ||||||
|  |  | ||||||
|  |                 with open( | ||||||
|  |                     os.path.join(self.directory_path, "summary.txt"), "w" | ||||||
|  |                 ) as summary_file: | ||||||
|  |                     summary_file.write(f"min: {smallest_number}\n") | ||||||
|  |                     summary_file.write(f"max: {largest_number}\n") | ||||||
|  |                     summary_file.write(f"avg: {average_value}\n") | ||||||
|  |  | ||||||
|  |                 print( | ||||||
|  |                     f"myftp> - {self.protocol} - Created file summary.txt summarized successfully. Sending it back to the client" | ||||||
|  |                 ) | ||||||
|  |  | ||||||
|  |                 with open( | ||||||
|  |                     os.path.join(self.directory_path, "summary.txt"), "rb" | ||||||
|  |                 ) as summary_file: | ||||||
|  |                     binary_content = summary_file.read() | ||||||
|  |  | ||||||
|  |                 return ( | ||||||
|  |                     rescode_success_dict["correct_summary_request_rescode"], | ||||||
|  |                     "summary.txt", | ||||||
|  |                     11, | ||||||
|  |                     binary_content, | ||||||
|  |                 ) | ||||||
|  |  | ||||||
|  |         except Exception as error: | ||||||
|  |             traceback_info = traceback.format_exc() | ||||||
|  |  | ||||||
|  |             print(f"myftp> - {self.protocol} - {error} happened.") | ||||||
|  |  | ||||||
|  |             print(traceback_info) | ||||||
|  |             return rescode_fail_dict["file_not_error_rescode"], None, None, None | ||||||
|  |  | ||||||
|     def process_put_req(self, filename_length: int, req_payload: bytes) -> int: |     def process_put_req(self, filename_length: int, req_payload: bytes) -> int: | ||||||
|         """ |         """ | ||||||
|         Reconstruct file put by client |         Reconstruct file put by client | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user