feat(udp): put command completed
This commit is contained in:
		@@ -4,7 +4,7 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
from socket import socket, AF_INET, SOCK_DGRAM
 | 
			
		||||
from typing import Pattern, Tuple
 | 
			
		||||
from typing import Pattern, Tuple, Optional
 | 
			
		||||
from argparse import ArgumentParser
 | 
			
		||||
import traceback
 | 
			
		||||
import os
 | 
			
		||||
@@ -30,7 +30,7 @@ unknown_request_opcode: int = 0b101
 | 
			
		||||
rescode_dict: dict[int, str] = {
 | 
			
		||||
    0b011: "File Not Found Error",
 | 
			
		||||
    0b100: "Unknown Request",
 | 
			
		||||
    0b101: "Change Unsuccessful Error",
 | 
			
		||||
    0b101: "Change/Put Unsuccessful Error",
 | 
			
		||||
    0b000: "Put/Change Request Successful",
 | 
			
		||||
    0b001: "Get Request Successful",
 | 
			
		||||
    0b010: "Summary Request Successful",
 | 
			
		||||
@@ -87,7 +87,7 @@ class Client:
 | 
			
		||||
 | 
			
		||||
                    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(
 | 
			
		||||
                        f"myftp> - {self.protocol} - Getting file {filename} from the server"
 | 
			
		||||
@@ -96,6 +96,11 @@ class Client:
 | 
			
		||||
                # put command handling
 | 
			
		||||
                elif put_command_pattern.match(command):
 | 
			
		||||
                    command_name, filename = command.split(" ", 1)
 | 
			
		||||
 | 
			
		||||
                    first_byte, second_byte_to_n_byte, data = self.put_payload_handling(
 | 
			
		||||
                        filename
 | 
			
		||||
                    )
 | 
			
		||||
 | 
			
		||||
                    print(
 | 
			
		||||
                        f"myftp> - {self.protocol} - Putting file {filename} into the server"
 | 
			
		||||
                    ) if self.debug else None
 | 
			
		||||
@@ -120,9 +125,16 @@ class Client:
 | 
			
		||||
                    first_byte: int = unknown_request_opcode << 5
 | 
			
		||||
 | 
			
		||||
                # 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
 | 
			
		||||
 | 
			
		||||
                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":
 | 
			
		||||
                    pass
 | 
			
		||||
 | 
			
		||||
@@ -189,19 +201,50 @@ class Client:
 | 
			
		||||
 | 
			
		||||
        # successful rescodes
 | 
			
		||||
        else:
 | 
			
		||||
            # help rescode and successful change or put rescode
 | 
			
		||||
            if rescode == 0b110:
 | 
			
		||||
                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)
 | 
			
		||||
 | 
			
		||||
    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(
 | 
			
		||||
        self, filename_length: int, response_data: bytes
 | 
			
		||||
    ):
 | 
			
		||||
        """
 | 
			
		||||
        response_data is
 | 
			
		||||
        file name (filename_length bytes) +
 | 
			
		||||
        file size (4 bytes) +
 | 
			
		||||
        file content (rest of the bytes)
 | 
			
		||||
        Response_data is
 | 
			
		||||
        File name (filename_length bytes) +
 | 
			
		||||
        File size (4 bytes) +
 | 
			
		||||
        File content (rest of the bytes)
 | 
			
		||||
        """
 | 
			
		||||
        try:
 | 
			
		||||
            filename = response_data[:filename_length].decode("ascii")
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
from socket import socket, AF_INET, SOCK_DGRAM
 | 
			
		||||
from argparse import ArgumentParser
 | 
			
		||||
from typing import Optional, Tuple
 | 
			
		||||
import traceback
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
# Res-codes
 | 
			
		||||
@@ -68,7 +69,9 @@ class Server:
 | 
			
		||||
 | 
			
		||||
                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(
 | 
			
		||||
                    f"myftp> - {self.protocol} - Received message from client at {clientAddress}: {req_payload}"
 | 
			
		||||
@@ -83,7 +86,7 @@ class Server:
 | 
			
		||||
                    rescode = rescode_success_dict["help_rescode"]
 | 
			
		||||
                    response_data = "get,put,summary,change,help,bye".encode("ascii")
 | 
			
		||||
                    filename = None
 | 
			
		||||
                    filename_length = None
 | 
			
		||||
                    filename_length_in_bytes = None
 | 
			
		||||
 | 
			
		||||
                elif request_type == "get":
 | 
			
		||||
                    pre_payload = self.process_get_req(req_payload[1:])
 | 
			
		||||
@@ -95,24 +98,41 @@ class Server:
 | 
			
		||||
                    ):
 | 
			
		||||
                        rescode = rescode_success_dict["correct_get_request_rescode"]
 | 
			
		||||
                        filename = pre_payload[0]
 | 
			
		||||
                        filename_length = pre_payload[2]
 | 
			
		||||
                        filename_length_in_bytes = pre_payload[2]
 | 
			
		||||
                        response_data = pre_payload[1]
 | 
			
		||||
 | 
			
		||||
                    else:
 | 
			
		||||
                        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
 | 
			
		||||
                        response_data = None
 | 
			
		||||
 | 
			
		||||
                elif request_type == "unknown":
 | 
			
		||||
                    rescode = rescode_fail_dict["unknown_request_rescode"]
 | 
			
		||||
                    filename_length = None
 | 
			
		||||
                    filename_length_in_bytes = None
 | 
			
		||||
                    filename = None
 | 
			
		||||
                    response_data = None
 | 
			
		||||
 | 
			
		||||
                res_payload: bytes = self.build_res_payload(
 | 
			
		||||
                    rescode=rescode,  # type: ignore
 | 
			
		||||
                    filename_length=filename_length,
 | 
			
		||||
                    filename_length=filename_length_in_bytes,
 | 
			
		||||
                    filename=filename,  # type: ignore
 | 
			
		||||
                    response_data=response_data,  # type:ignore
 | 
			
		||||
                )
 | 
			
		||||
@@ -154,6 +174,38 @@ class Server:
 | 
			
		||||
 | 
			
		||||
        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(
 | 
			
		||||
        self, second_byte_to_byte_n: bytes
 | 
			
		||||
    ) -> Tuple[Optional[str], Optional[bytes], Optional[int]]:
 | 
			
		||||
@@ -219,6 +271,7 @@ class Server:
 | 
			
		||||
            if filename is None:
 | 
			
		||||
                second_byte_to_FL_plus_five = None
 | 
			
		||||
            else:
 | 
			
		||||
                # get case
 | 
			
		||||
                second_byte_to_FL_plus_five = (
 | 
			
		||||
                    filename.encode() + len(response_data).to_bytes(4, "big")
 | 
			
		||||
                    if response_data is not None
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user