feat(udp): put command completed
This commit is contained in:
parent
ae1d34da2a
commit
73b4e06d02
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
|
|
||||||
from socket import socket, AF_INET, SOCK_DGRAM
|
from socket import socket, AF_INET, SOCK_DGRAM
|
||||||
from typing import Pattern, Tuple
|
from typing import Pattern, Tuple, Optional
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
import traceback
|
import traceback
|
||||||
import os
|
import os
|
||||||
@ -30,7 +30,7 @@ unknown_request_opcode: int = 0b101
|
|||||||
rescode_dict: dict[int, str] = {
|
rescode_dict: dict[int, str] = {
|
||||||
0b011: "File Not Found Error",
|
0b011: "File Not Found Error",
|
||||||
0b100: "Unknown Request",
|
0b100: "Unknown Request",
|
||||||
0b101: "Change Unsuccessful Error",
|
0b101: "Change/Put Unsuccessful Error",
|
||||||
0b000: "Put/Change Request Successful",
|
0b000: "Put/Change Request Successful",
|
||||||
0b001: "Get Request Successful",
|
0b001: "Get Request Successful",
|
||||||
0b010: "Summary Request Successful",
|
0b010: "Summary Request Successful",
|
||||||
@ -87,7 +87,7 @@ class Client:
|
|||||||
|
|
||||||
first_byte = (get_request_opcode << 5) + len(filename)
|
first_byte = (get_request_opcode << 5) + len(filename)
|
||||||
|
|
||||||
second_byte_to_n_byte: bytes = filename.encode("ascii")
|
second_byte_to_n_byte = filename.encode("ascii")
|
||||||
|
|
||||||
print(
|
print(
|
||||||
f"myftp> - {self.protocol} - Getting file {filename} from the server"
|
f"myftp> - {self.protocol} - Getting file {filename} from the server"
|
||||||
@ -96,6 +96,11 @@ class Client:
|
|||||||
# put command handling
|
# put command handling
|
||||||
elif put_command_pattern.match(command):
|
elif put_command_pattern.match(command):
|
||||||
command_name, filename = command.split(" ", 1)
|
command_name, filename = command.split(" ", 1)
|
||||||
|
|
||||||
|
first_byte, second_byte_to_n_byte, data = self.put_payload_handling(
|
||||||
|
filename
|
||||||
|
)
|
||||||
|
|
||||||
print(
|
print(
|
||||||
f"myftp> - {self.protocol} - Putting file {filename} into the server"
|
f"myftp> - {self.protocol} - Putting file {filename} into the server"
|
||||||
) if self.debug else None
|
) if self.debug else None
|
||||||
@ -120,9 +125,16 @@ 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" or command_name == "put":
|
if command_name == "get":
|
||||||
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":
|
||||||
|
payload = (
|
||||||
|
first_byte.to_bytes(1, "big") + second_byte_to_n_byte + data # type: ignore
|
||||||
|
if second_byte_to_n_byte is not None and data is not None # type: ignore
|
||||||
|
else first_byte.to_bytes(1, "big") # type: ignore
|
||||||
|
)
|
||||||
|
|
||||||
elif command_name == "summary":
|
elif command_name == "summary":
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -189,19 +201,50 @@ class Client:
|
|||||||
|
|
||||||
# successful rescodes
|
# successful rescodes
|
||||||
else:
|
else:
|
||||||
|
# help rescode and successful change or put rescode
|
||||||
if rescode == 0b110:
|
if rescode == 0b110:
|
||||||
print(f"myftp> - {self.protocol} - {response_data.decode('ascii')}")
|
print(f"myftp> - {self.protocol} - {response_data.decode('ascii')}")
|
||||||
else:
|
elif rescode == 0b000:
|
||||||
|
print(f"myftp> - {self.protocol} - {rescode_dict[rescode]}")
|
||||||
|
# get rescode
|
||||||
|
elif rescode == 0b001:
|
||||||
self.handle_get_response_from_server(filename_length, response_data)
|
self.handle_get_response_from_server(filename_length, response_data)
|
||||||
|
|
||||||
|
def put_payload_handling(
|
||||||
|
self, filename: str
|
||||||
|
) -> Tuple[int, Optional[bytes], Optional[bytes]]:
|
||||||
|
"""
|
||||||
|
Assemble the pay load to put the file onto server
|
||||||
|
|
||||||
|
Return first_byte, second_byte_to_n_byte and data if successful
|
||||||
|
Or (None, None, None) if file not found
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with open(os.path.join(self.directory_path, filename), "rb") as file:
|
||||||
|
content = file.read()
|
||||||
|
content_length = len(content)
|
||||||
|
|
||||||
|
first_byte = (put_request_opcode << 5) + len(filename)
|
||||||
|
|
||||||
|
second_byte_to_n_byte = filename.encode(
|
||||||
|
"ascii"
|
||||||
|
) + content_length.to_bytes(4, "big")
|
||||||
|
|
||||||
|
data = content
|
||||||
|
|
||||||
|
return (first_byte, second_byte_to_n_byte, data)
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
return ((put_request_opcode << 5), None, None)
|
||||||
|
|
||||||
def handle_get_response_from_server(
|
def handle_get_response_from_server(
|
||||||
self, filename_length: int, response_data: bytes
|
self, filename_length: int, response_data: bytes
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
response_data is
|
Response_data is
|
||||||
file name (filename_length bytes) +
|
File name (filename_length bytes) +
|
||||||
file size (4 bytes) +
|
File size (4 bytes) +
|
||||||
file content (rest of the bytes)
|
File content (rest of the bytes)
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
filename = response_data[:filename_length].decode("ascii")
|
filename = response_data[:filename_length].decode("ascii")
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
from socket import socket, AF_INET, SOCK_DGRAM
|
from socket import socket, AF_INET, SOCK_DGRAM
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from typing import Optional, Tuple
|
from typing import Optional, Tuple
|
||||||
|
import traceback
|
||||||
import os
|
import os
|
||||||
|
|
||||||
# Res-codes
|
# Res-codes
|
||||||
@ -68,7 +69,9 @@ class Server:
|
|||||||
|
|
||||||
first_byte = bytes([req_payload[0]])
|
first_byte = bytes([req_payload[0]])
|
||||||
|
|
||||||
request_type, filename_length = self.decode_first_byte(first_byte)
|
request_type, filename_length_in_bytes = self.decode_first_byte(
|
||||||
|
first_byte
|
||||||
|
)
|
||||||
|
|
||||||
print(
|
print(
|
||||||
f"myftp> - {self.protocol} - Received message from client at {clientAddress}: {req_payload}"
|
f"myftp> - {self.protocol} - Received message from client at {clientAddress}: {req_payload}"
|
||||||
@ -83,7 +86,7 @@ class Server:
|
|||||||
rescode = rescode_success_dict["help_rescode"]
|
rescode = rescode_success_dict["help_rescode"]
|
||||||
response_data = "get,put,summary,change,help,bye".encode("ascii")
|
response_data = "get,put,summary,change,help,bye".encode("ascii")
|
||||||
filename = None
|
filename = None
|
||||||
filename_length = None
|
filename_length_in_bytes = None
|
||||||
|
|
||||||
elif request_type == "get":
|
elif request_type == "get":
|
||||||
pre_payload = self.process_get_req(req_payload[1:])
|
pre_payload = self.process_get_req(req_payload[1:])
|
||||||
@ -95,24 +98,41 @@ class Server:
|
|||||||
):
|
):
|
||||||
rescode = rescode_success_dict["correct_get_request_rescode"]
|
rescode = rescode_success_dict["correct_get_request_rescode"]
|
||||||
filename = pre_payload[0]
|
filename = pre_payload[0]
|
||||||
filename_length = pre_payload[2]
|
filename_length_in_bytes = pre_payload[2]
|
||||||
response_data = pre_payload[1]
|
response_data = pre_payload[1]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
rescode = rescode_fail_dict["file_not_error_rescode"]
|
rescode = rescode_fail_dict["file_not_error_rescode"]
|
||||||
filename_length = None
|
filename_length_in_bytes = None
|
||||||
|
filename = None
|
||||||
|
response_data = None
|
||||||
|
|
||||||
|
elif request_type == "put":
|
||||||
|
# put request failed since there wasnt a file sent from client
|
||||||
|
if filename_length_in_bytes == 0:
|
||||||
|
rescode = rescode_fail_dict["unsuccessful_change_rescode"]
|
||||||
|
filename_length_in_bytes = None
|
||||||
|
filename = None
|
||||||
|
response_data = None
|
||||||
|
|
||||||
|
# put request success
|
||||||
|
else:
|
||||||
|
rescode = self.process_put_req(
|
||||||
|
filename_length_in_bytes, req_payload[1:]
|
||||||
|
)
|
||||||
|
filename_length_in_bytes = None
|
||||||
filename = None
|
filename = None
|
||||||
response_data = None
|
response_data = None
|
||||||
|
|
||||||
elif request_type == "unknown":
|
elif request_type == "unknown":
|
||||||
rescode = rescode_fail_dict["unknown_request_rescode"]
|
rescode = rescode_fail_dict["unknown_request_rescode"]
|
||||||
filename_length = None
|
filename_length_in_bytes = None
|
||||||
filename = None
|
filename = None
|
||||||
response_data = None
|
response_data = None
|
||||||
|
|
||||||
res_payload: bytes = self.build_res_payload(
|
res_payload: bytes = self.build_res_payload(
|
||||||
rescode=rescode, # type: ignore
|
rescode=rescode, # type: ignore
|
||||||
filename_length=filename_length,
|
filename_length=filename_length_in_bytes,
|
||||||
filename=filename, # type: ignore
|
filename=filename, # type: ignore
|
||||||
response_data=response_data, # type:ignore
|
response_data=response_data, # type:ignore
|
||||||
)
|
)
|
||||||
@ -154,6 +174,38 @@ class Server:
|
|||||||
|
|
||||||
return request_type, filename_length_in_bytes
|
return request_type, filename_length_in_bytes
|
||||||
|
|
||||||
|
def process_put_req(self, filename_length: int, req_payload: bytes) -> int:
|
||||||
|
"""
|
||||||
|
Reconstruct file put by client
|
||||||
|
"""
|
||||||
|
filename = req_payload[:filename_length].decode("ascii")
|
||||||
|
filesize = int.from_bytes(
|
||||||
|
req_payload[filename_length : filename_length + 4], "big"
|
||||||
|
)
|
||||||
|
file_content = req_payload[filename_length + 4 :]
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"myftp> - {self.protocol} - Reconstructing the file {filename} of size {filesize} bytes on the server after the client finished sending"
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(os.path.join(self.directory_path, filename), "wb") as file:
|
||||||
|
file.write(file_content)
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"myftp> - {self.protocol} - File {filename} uploaded successfully"
|
||||||
|
)
|
||||||
|
|
||||||
|
return rescode_success_dict["correct_put_and_change_request_rescode"]
|
||||||
|
|
||||||
|
except Exception as error:
|
||||||
|
traceback_info = traceback.format_exc()
|
||||||
|
|
||||||
|
print(f"myftp> - {self.protocol} - {error} happened.")
|
||||||
|
|
||||||
|
print(traceback_info)
|
||||||
|
return rescode_fail_dict["unsuccessful_change_rescode"]
|
||||||
|
|
||||||
def process_get_req(
|
def process_get_req(
|
||||||
self, second_byte_to_byte_n: bytes
|
self, second_byte_to_byte_n: bytes
|
||||||
) -> Tuple[Optional[str], Optional[bytes], Optional[int]]:
|
) -> Tuple[Optional[str], Optional[bytes], Optional[int]]:
|
||||||
@ -219,6 +271,7 @@ class Server:
|
|||||||
if filename is None:
|
if filename is None:
|
||||||
second_byte_to_FL_plus_five = None
|
second_byte_to_FL_plus_five = None
|
||||||
else:
|
else:
|
||||||
|
# get case
|
||||||
second_byte_to_FL_plus_five = (
|
second_byte_to_FL_plus_five = (
|
||||||
filename.encode() + len(response_data).to_bytes(4, "big")
|
filename.encode() + len(response_data).to_bytes(4, "big")
|
||||||
if response_data is not None
|
if response_data is not None
|
||||||
|
Loading…
x
Reference in New Issue
Block a user