feat(udp): summary command completed

This commit is contained in:
minhtrannhat 2023-12-07 17:44:08 -05:00
parent 73b4e06d02
commit fe23170908
Signed by: minhtrannhat
GPG Key ID: E13CFA85C53F8062
4 changed files with 231 additions and 7 deletions

View File

@ -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

View 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

View File

@ -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

View File

@ -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