Module e2eeftp.client.cli
Command-line interface for E2EEFTP client.
This module provides an interactive command-line interface for the E2EEFTP client, allowing users to perform secure file transfers through a rich text-based UI. It includes commands for connecting to servers, uploading/downloading files, listing remote files, and managing connections.
The CLI uses Rich for enhanced terminal output and provides a user-friendly interface for interacting with E2EEFTP servers.
Functions
def check_host_status(host: str = '127.0.0.1', port: int | None = None) ‑> bool-
Expand source code
def check_host_status(host: str = '127.0.0.1', port: None | int = None) -> bool: """ Checks if a host is up. If a port is provided, it attempts a TCP connection. Otherwise, it defaults to a standard ping. Args: host (str): the host ip. port (None | int): the port of the host. Returns: bool if the server is up or not. """ if port: try: # Create a TCP socket and attempt to connect with socket.create_connection((host, int(port)), timeout=2): return True except (socket.timeout, ConnectionRefusedError, OSError): return False else: # Fallback to the original ping logic if no port is provided param = '-n' if platform.system().lower() == 'windows' else '-c' command = ['ping', param, '1', host] try: subprocess.run(command, capture_output=True, text=True, check=True, timeout=2) return True except Exception: return FalseChecks if a host is up. If a port is provided, it attempts a TCP connection. Otherwise, it defaults to a standard ping.
Args
host:str- the host ip.
port:None | int- the port of the host.
Returns
bool if the server is up or not.
Classes
class e2eeftpClientCli (host: str = '127.0.0.1', port: int = 5001)-
Expand source code
class e2eeftpClientCli: """ The CLI for the e2eeftp client for a user frendly TUI experience. """ def __init__(self, host: str='127.0.0.1', port: int=5001): """ Initialize the E2EEFTP client CLI with server connection details. Args: host (str): The hostname or IP address of the E2EEFTP server. port (int): The port number on which the server is listening. This method sets up the client connection, console for rich output, status code mappings for user-friendly messages, and initializes the help system and command interface. """ # Initialize client - ensure host is accessible via self.client.host self.client = e2eeftpClient(host=host, port=port, logging=False) self.console = Console() self.status_map = { "200": "[bold green]200: Success[/bold green]", "226": "[bold cyan]226: Transfer Complete[/bold cyan]", "400": "[bold yellow]400: Bad Request[/bold yellow]", "404": "[bold red]404: File Not Found[/bold red]", "500": "[bold red]500: Internal Server Error[/bold red]" } self._create_help_table() self.commands = self.client def _create_help_table(self): """ Creates the persistent help table. """ self.help_table = Table(title="Available Commands", header_style="bold magenta") self.help_table.add_column("Command", style="cyan", width=15) self.help_table.add_column("Description") self.help_table.add_column("Syntax", style="italic") self.help_table.add_row("SEND", "Upload a file to server", "SEND <local_path>") self.help_table.add_row("GET", "Download from server", "GET <remote_path>") self.help_table.add_row("LIST", "List server files", "LIST") self.help_table.add_row("DELETE", "Delete server file", "DELETE <remote_path>") self.help_table.add_row("HLIST", "List server commands", "HLIST") self.help_table.add_row("PING", "Check server status", "PING") self.help_table.add_row("HELP", "Show this message", "HELP") self.help_table.add_row("EXIT", "Close the client", "EXIT") def _get_status_style(self, code): """ Get the styled status message for a given status code. Args: code: The HTTP-like status code returned by server operations. Returns: str: A Rich-formatted string with appropriate colors and styling for the status code, or a generic unknown status message. """ return self.status_map.get(str(code), f"[white]{code}: Unknown Status[/white]") def run(self): """ Start the interactive CLI session for the E2EEFTP client. This method clears the console, displays a welcome panel, and enters an interactive loop where it accepts user commands. It handles special commands like EXIT and delegates other commands to _evaluate_command for processing. The loop continues until the user exits or an interrupt occurs. The interface provides a clean, Rich-enhanced terminal experience with colored output and formatted panels. """ self.console.clear() self.console.print(Panel.fit( "[bold cyan]E2EE FTP Client[/bold cyan]", border_style="magenta" )) try: while True: # Use Prompt.ask for a clean input experience command_input = _Prompt.ask("[bold green]>>> [/bold green]").strip() if not command_input: continue if command_input.upper() == "EXIT": rprint("[yellow]Exiting...[/yellow]") break self._evaluate_command(command_input) except (KeyboardInterrupt, EOFError): rprint("\n[red]Session terminated.[/red]") def _evaluate_command(self, command: str): """ Parse and execute a user-entered command. Args: command (str): The raw command string entered by the user. This method parses the command, determines the operation type, and executes the appropriate action. Supported commands include: - SEND: Upload a file to the server - GET: Download a file from the server - LIST: Display server's file directory - DELETE: Remove a file from the server - HLIST: Show available server commands - HELP: Display the help table - PING: Check server connectivity - EXIT: Terminate the session (handled in run()) For file operations, it validates arguments and provides user feedback through Rich-formatted console output. Invalid commands are reported with appropriate error messages. """ parts = command.split(maxsplit=1) method = parts[0].upper() args = parts[1] if len(parts) > 1 else None match method: case "SEND": if args: if os.path.exists(args): rprint(f"[blue]Action:[/blue] Uploading {args}...") status = self.client.send(args) rprint(f"Status: {self._get_status_style(status)}") else: rprint(f"[bold red]Error:[/bold red] Local file '{args}' not found.") else: rprint("[red]Error: Provide a file path.[/red]") case "GET": if args: rprint(f"[blue]Action:[/blue] Downloading {args}...") status = self.client.get(args) rprint(f"Status: {self._get_status_style(status)}") else: rprint("[red]Error: Provide a file path.[/red]") case "LIST": rprint("[blue]Action:[/blue] Requesting file list...") file_list = self.client.list_files() if file_list is not None: # Handle empty list or list with a single empty string from split if not file_list or (len(file_list) == 1 and not file_list[0]): rprint("[yellow]Server directory is empty.[/yellow]") return table = Table(title="Server Directory", header_style="bold magenta") table.add_column("Filename", style="white") i = 0 for filename in file_list: if filename: # Don't add empty rows table.add_row(filename) i += 1 self.console.print(table) rprint("[i][blue]check:[/blue] list.txt[/i]") rprint(f"[i][blue]Total files:[/blue] {i}[/i]") else: rprint("[bold red]Error:[/bold red] Could not retrieve directory list. Check logs for details.") case "DELETE": if args: rprint(f"[blue]Action:[/blue] Deleteing {args}...") status = self.client.delete(args) rprint(f"Status: {self._get_status_style(status or 200)}") else: rprint("[red]Error: Provide a file path.[/red]") case "HLIST": rprint("[blue]Action:[/blue] Requesting server commands...") cmd_list = self.client.hlist() if cmd_list is not None: # Handle empty list or list with a single empty string from split if not cmd_list or (len(cmd_list) == 1 and not cmd_list[0]): rprint("[yellow]Server has no commands available.[/yellow]") return table = Table(title="Available Server Commands", header_style="bold magenta") table.add_column("Command", style="cyan") i = 0 for cmd in cmd_list: if cmd: # Don't add empty rows table.add_row(cmd) i += 1 self.console.print(table) rprint(f"[i][blue]Total commands:[/blue] {i}[/i]") else: rprint("[bold red]Error:[/bold red] Could not retrieve command list. Check logs for details.") case "HELP": self.console.print(self.help_table) case "PING": # Use the host and port from your client instance host = getattr(self.client, 'host', 'localhost') port = getattr(self.client, 'port', 21) # Default FTP port is 21 rprint(f"[blue]Checking connection to {host}:{port}...[/blue]") if check_host_status(host, port): rprint(f"Status: [bold green]UP (Port {port} is open)[/bold green]") else: rprint(f"Status: [bold red]DOWN (Could not connect to port {port})[/bold red]") case _: rprint(f"Status: {self._get_status_style(400)} (Unknown Command '{method}')")The CLI for the e2eeftp client for a user frendly TUI experience.
Initialize the E2EEFTP client CLI with server connection details.
Args
host:str- The hostname or IP address of the E2EEFTP server.
port:int- The port number on which the server is listening.
This method sets up the client connection, console for rich output, status code mappings for user-friendly messages, and initializes the help system and command interface.
Methods
def run(self)-
Expand source code
def run(self): """ Start the interactive CLI session for the E2EEFTP client. This method clears the console, displays a welcome panel, and enters an interactive loop where it accepts user commands. It handles special commands like EXIT and delegates other commands to _evaluate_command for processing. The loop continues until the user exits or an interrupt occurs. The interface provides a clean, Rich-enhanced terminal experience with colored output and formatted panels. """ self.console.clear() self.console.print(Panel.fit( "[bold cyan]E2EE FTP Client[/bold cyan]", border_style="magenta" )) try: while True: # Use Prompt.ask for a clean input experience command_input = _Prompt.ask("[bold green]>>> [/bold green]").strip() if not command_input: continue if command_input.upper() == "EXIT": rprint("[yellow]Exiting...[/yellow]") break self._evaluate_command(command_input) except (KeyboardInterrupt, EOFError): rprint("\n[red]Session terminated.[/red]")Start the interactive CLI session for the E2EEFTP client.
This method clears the console, displays a welcome panel, and enters an interactive loop where it accepts user commands. It handles special commands like EXIT and delegates other commands to _evaluate_command for processing. The loop continues until the user exits or an interrupt occurs.
The interface provides a clean, Rich-enhanced terminal experience with colored output and formatted panels.