feat(udp): put command completed
This commit is contained in:
		@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user