feat(udp): help functionality finished
- Added res-code to client.py - Improved client error handling
This commit is contained in:
		@@ -19,11 +19,20 @@ summary_command_pattern: Pattern = re.compile(r"^summary\s+[^\s]+$")
 | 
				
			|||||||
change_command_pattern: Pattern = re.compile(r"^change\s+[^\s]+\s+[^\s]+$")
 | 
					change_command_pattern: Pattern = re.compile(r"^change\s+[^\s]+\s+[^\s]+$")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# opcodes
 | 
					# opcodes
 | 
				
			||||||
put_request_opcode = "000"
 | 
					put_request_opcode:str = "000"
 | 
				
			||||||
get_request_opcode = "001"
 | 
					get_request_opcode:str = "001"
 | 
				
			||||||
change_request_opcode = "010"
 | 
					change_request_opcode: str = "010"
 | 
				
			||||||
summary_request_opcode = "011"
 | 
					summary_request_opcode: str = "011"
 | 
				
			||||||
help_requrest_opcode = "100"
 | 
					help_requrest_opcode: str = "100"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Res-code
 | 
				
			||||||
 | 
					correct_put_and_change_request_rescode: str = "000"
 | 
				
			||||||
 | 
					correct_get_request_rescode: str = "001"
 | 
				
			||||||
 | 
					correct_summary_request_rescode: str = "010"
 | 
				
			||||||
 | 
					file_not_error_rescode: str = "011"
 | 
				
			||||||
 | 
					unknown_request_rescode: str = "100"
 | 
				
			||||||
 | 
					unsuccessful_change_rescode: str = "101"
 | 
				
			||||||
 | 
					help_rescode: str = "110"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# custome type to represent the hostname(server name) and the server port
 | 
					# custome type to represent the hostname(server name) and the server port
 | 
				
			||||||
Address = Tuple[str, int]
 | 
					Address = Tuple[str, int]
 | 
				
			||||||
@@ -64,7 +73,10 @@ class UDPClient:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                # help
 | 
					                # help
 | 
				
			||||||
                elif command == "help":
 | 
					                elif command == "help":
 | 
				
			||||||
                    continue
 | 
					                    request_payload: str = help_requrest_opcode + "00000"
 | 
				
			||||||
 | 
					                    print(
 | 
				
			||||||
 | 
					                        f"myftp> - {self.mode} - : asking for help from the server"
 | 
				
			||||||
 | 
					                    ) if self.debug else None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                # get command handling
 | 
					                # get command handling
 | 
				
			||||||
                elif get_command_pattern.match(command):
 | 
					                elif get_command_pattern.match(command):
 | 
				
			||||||
@@ -87,7 +99,7 @@ class UDPClient:
 | 
				
			|||||||
                        f"myftp> - {self.mode} - : summary file {filename} from the server"
 | 
					                        f"myftp> - {self.mode} - : summary file {filename} from the server"
 | 
				
			||||||
                    ) if self.debug else None
 | 
					                    ) if self.debug else None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                # summary command handling
 | 
					                # change command handling
 | 
				
			||||||
                elif change_command_pattern.match(command):
 | 
					                elif change_command_pattern.match(command):
 | 
				
			||||||
                    _, old_filename, new_filename = command.split()
 | 
					                    _, old_filename, new_filename = command.split()
 | 
				
			||||||
                    print(
 | 
					                    print(
 | 
				
			||||||
@@ -100,9 +112,10 @@ class UDPClient:
 | 
				
			|||||||
                    )
 | 
					                    )
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                client_socket.send(command.encode())
 | 
					                client_socket.send(request_payload.encode("utf-8"))
 | 
				
			||||||
                modified_message = client_socket.recv(2048)
 | 
					                modified_message = client_socket.recv(2048)[1:]
 | 
				
			||||||
                print(modified_message.decode())
 | 
					                print(modified_message.decode())
 | 
				
			||||||
 | 
					                client_socket.close() # type: ignore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            except ConnectionRefusedError:
 | 
					            except ConnectionRefusedError:
 | 
				
			||||||
                print(
 | 
					                print(
 | 
				
			||||||
@@ -112,8 +125,6 @@ class UDPClient:
 | 
				
			|||||||
                print(
 | 
					                print(
 | 
				
			||||||
                    f"myftp> - {self.mode} - {error} happened."
 | 
					                    f"myftp> - {self.mode} - {error} happened."
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
            finally:
 | 
					 | 
				
			||||||
                client_socket.close() # type: ignore
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # ping pong UDP
 | 
					    # ping pong UDP
 | 
				
			||||||
    def check_udp_server(self):
 | 
					    def check_udp_server(self):
 | 
				
			||||||
@@ -170,9 +181,7 @@ def get_address_input() -> Address:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            # Ensure there are exactly two parts
 | 
					            # Ensure there are exactly two parts
 | 
				
			||||||
            if len(input_parts) != 2:
 | 
					            if len(input_parts) != 2:
 | 
				
			||||||
                raise ValueError(
 | 
					                raise ValueError
 | 
				
			||||||
                    "myftp>Invalid input. Please enter a servername/hostname/ip address as a string and the port number as an integer separated by a space."
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Extract the values and create the tuple
 | 
					            # Extract the values and create the tuple
 | 
				
			||||||
            string_part, int_part = input_parts
 | 
					            string_part, int_part = input_parts
 | 
				
			||||||
@@ -183,7 +192,7 @@ def get_address_input() -> Address:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        except ValueError as e:
 | 
					        except ValueError as e:
 | 
				
			||||||
            print(
 | 
					            print(
 | 
				
			||||||
                f"Error: {e}. Invalid input. Please enter a servername/hostname/ip address as a string and the port number as an integer separated by a space."
 | 
					                f"Error: Invalid input. Please enter a servername/hostname/ip address as a string and the port number as an integer separated by a space."
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,13 @@ unknown_request_rescode: str = "100"
 | 
				
			|||||||
unsuccessful_change_rescode: str = "101"
 | 
					unsuccessful_change_rescode: str = "101"
 | 
				
			||||||
help_rescode: str = "110"
 | 
					help_rescode: str = "110"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# opcodes
 | 
				
			||||||
 | 
					put_request_opcode: str = "000"
 | 
				
			||||||
 | 
					get_request_opcode: str = "001"
 | 
				
			||||||
 | 
					change_request_opcode: str = "010"
 | 
				
			||||||
 | 
					summary_request_opcode: str = "011"
 | 
				
			||||||
 | 
					help_requrest_opcode: str = "100"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UDPServer:
 | 
					class UDPServer:
 | 
				
			||||||
    def __init__(
 | 
					    def __init__(
 | 
				
			||||||
@@ -41,33 +48,45 @@ class UDPServer:
 | 
				
			|||||||
        try:
 | 
					        try:
 | 
				
			||||||
            while not shut_down:
 | 
					            while not shut_down:
 | 
				
			||||||
                message, clientAddress = self.server_socket.recvfrom(2048)
 | 
					                message, clientAddress = self.server_socket.recvfrom(2048)
 | 
				
			||||||
                message_in_utf8 = message.decode()
 | 
					                request_payload = message.decode()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                print(
 | 
					                print(
 | 
				
			||||||
                    f"myftp> - {self.mode} - received message from client at {clientAddress}: {message_in_utf8}"
 | 
					                    f"myftp> - {self.mode} - received message from client at {clientAddress}: {request_payload}"
 | 
				
			||||||
                ) if self.debug else None
 | 
					                ) if self.debug else None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                # check for connectivity
 | 
					                # check for connectivity
 | 
				
			||||||
                if message_in_utf8 == "ping":
 | 
					                if request_payload == "ping":
 | 
				
			||||||
                    response_message = "pong"
 | 
					                    self.server_socket.sendto("pong".encode(), clientAddress)
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                # list files available on server
 | 
					                # list files available on server
 | 
				
			||||||
                elif message_in_utf8 == "list":
 | 
					                elif request_payload == "list":
 | 
				
			||||||
                    encoded_message = pickle.dumps(
 | 
					                    encoded_message = pickle.dumps(
 | 
				
			||||||
                        get_files_in_directory(self.directory_path)
 | 
					                        get_files_in_directory(self.directory_path)
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
                    self.server_socket.sendto(encoded_message, clientAddress)
 | 
					                    self.server_socket.sendto(encoded_message, clientAddress)
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # help request handling
 | 
				
			||||||
 | 
					                elif request_payload == help_requrest_opcode + "00000":
 | 
				
			||||||
 | 
					                    print(
 | 
				
			||||||
 | 
					                        f"myftp> - {self.mode} - received help request"
 | 
				
			||||||
 | 
					                    ) if self.debug else None
 | 
				
			||||||
 | 
					                    rescode = help_rescode
 | 
				
			||||||
 | 
					                    response_data_string = "get,put,summary,change,help,bye"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    response_message = message_in_utf8.upper()
 | 
					                    # handle unrecognized request here
 | 
				
			||||||
 | 
					                    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                payload: bytes = self.build_res_payload(rescode, response_data_string)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.server_socket.sendto(payload, clientAddress)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                print(
 | 
					                print(
 | 
				
			||||||
                    f"myftp> - {self.mode} - sent message to client at {clientAddress}: {response_message}"
 | 
					                    f"myftp> - {self.mode} - sent message to client at {clientAddress}: {payload}"
 | 
				
			||||||
                ) if self.debug else None
 | 
					                ) if self.debug else None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                self.server_socket.sendto(response_message.encode(), clientAddress)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        except KeyboardInterrupt:
 | 
					        except KeyboardInterrupt:
 | 
				
			||||||
            shut_down = True
 | 
					            shut_down = True
 | 
				
			||||||
            self.server_socket.close()
 | 
					            self.server_socket.close()
 | 
				
			||||||
@@ -76,6 +95,40 @@ class UDPServer:
 | 
				
			|||||||
        finally:
 | 
					        finally:
 | 
				
			||||||
            print(f"myftp> - {self.mode} - Closed the server socket\n")
 | 
					            print(f"myftp> - {self.mode} - Closed the server socket\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # assembling the payload to send back to the client
 | 
				
			||||||
 | 
					    def build_res_payload(self,
 | 
				
			||||||
 | 
					                            rescode: str,
 | 
				
			||||||
 | 
					                            response_data_string: str) -> bytes:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bytes_response_data = response_data_string.encode("utf-8")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        data_len = len(bytes_response_data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        print(f"myftp> - {self.mode} - Rescode {rescode}") if self.debug else None
 | 
				
			||||||
 | 
					        print(f"myftp> - {self.mode} - Length of data {data_len}") if self.debug else None
 | 
				
			||||||
 | 
					        print(f"myftp> - {self.mode} - Data {response_data_string}") if self.debug else None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # convert to binary
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            # pad the length of data to make sure it is always 5 bits
 | 
				
			||||||
 | 
					            # i.e "010" -> "00010"
 | 
				
			||||||
 | 
					            binary_data_len: str = bin(data_len).zfill(5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            print(f"myftp> - {self.mode} - binary_data_len {binary_data_len[2:]}") if self.debug else None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # create the first byte
 | 
				
			||||||
 | 
					            # since binary_data_len is of the format 0b00100, we have to remove the first two characters 0b
 | 
				
			||||||
 | 
					            first_byte: bytes = bytes([int(rescode + binary_data_len[2:], 2)])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            print(f"myftp> - {self.mode} - First byte assembled for rescode {rescode}: {bin(int.from_bytes(first_byte, byteorder='big'))[2:]}") if self.debug else None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        except Exception as e:
 | 
				
			||||||
 | 
					            raise Exception(e)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        res_payload = first_byte + bytes_response_data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return res_payload
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_files_in_directory(directory_path: str) -> list[str]:
 | 
					def get_files_in_directory(directory_path: str) -> list[str]:
 | 
				
			||||||
    file_list = []
 | 
					    file_list = []
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user