9.1 KiB
9.1 KiB
System Patterns: hosts
System Architecture
Layered Architecture
┌─────────────────────────────────────┐
│ TUI Layer │ ← User Interface (Textual)
├─────────────────────────────────────┤
│ Manager Layer │ ← Orchestration & Operations
├─────────────────────────────────────┤
│ Core Layer │ ← Business Logic
├─────────────────────────────────────┤
│ System Layer │ ← File I/O & DNS
└─────────────────────────────────────┘
Component Relationships
TUI Layer (src/hosts/main.py
)
- ✅ HostsManagerApp: Complete Textual application with reactive state management
- ✅ Responsibilities: User interaction, display logic, event handling, navigation
- ✅ Dependencies: Core models and parser for data operations
- ✅ Implementation: Two-pane layout with ListView and reactive updates
Core Layer (src/hosts/core/
)
- ✅ models.py: Complete data structures (HostEntry, HostsFile) with validation
- ✅ parser.py: Robust hosts file parsing, serialization, and file operations
- ✅ Responsibilities: Pure business logic, data validation, file integrity
- ✅ Implementation: Comprehensive validation and error handling
System Layer (Implemented)
- ✅ File I/O: Atomic file operations with backup support
- ✅ Permission checking: Validation of file access permissions
- 🔄 DNS Resolution: Planned for Phase 5 advanced features
- 🔄 Permission Management: Sudo handling planned for Phase 3 edit mode
Key Technical Decisions
Data Model Design (Implemented)
@dataclass
class HostEntry:
ip_address: str
hostnames: list[str]
comment: str | None = None
is_active: bool = True
dns_name: str | None = None # For CNAME-like functionality
# Implemented methods:
def to_hosts_line(self) -> str
@classmethod
def from_hosts_line(cls, line: str) -> "HostEntry | None"
def __post_init__(self) -> None # Validation
@dataclass
class HostsFile:
entries: list[HostEntry] = field(default_factory=list)
header_comments: list[str] = field(default_factory=list)
footer_comments: list[str] = field(default_factory=list)
# Implemented methods:
def add_entry(self, entry: HostEntry) -> None
def remove_entry(self, index: int) -> None
def toggle_entry(self, index: int) -> None
def get_active_entries(self) -> list[HostEntry]
def get_inactive_entries(self) -> list[HostEntry]
def sort_by_ip(self) -> None
def sort_by_hostname(self) -> None
def find_entries_by_hostname(self, hostname: str) -> list[HostEntry]
def find_entries_by_ip(self, ip: str) -> list[HostEntry]
State Management (Implemented)
- ✅ Reactive state: Using Textual's reactive attributes for UI updates
- ✅ Validation pipeline: All data validated in models and parser
- ✅ File integrity: Atomic operations preserve file structure
- ✅ Error handling: Graceful degradation for all error conditions
- 🔄 Undo/Redo capability: Planned for Phase 4 with command pattern
- 🔄 Dirty state tracking: Will be implemented in Phase 3 edit mode
Permission Model (Planned for Phase 3)
# Current implementation (read-only mode)
class HostsManagerApp:
edit_mode: reactive[bool] = reactive(False) # Always False in Phase 1
def update_status(self):
mode = "Edit mode" if self.edit_mode else "Read-only mode"
# Status bar shows current mode
# Planned for Phase 3:
class PermissionManager:
def __init__(self):
self.edit_mode = False
self.sudo_acquired = False
def enter_edit_mode(self) -> bool:
# Request sudo permissions
# Set edit_mode = True only if successful
def exit_edit_mode(self):
# Release sudo permissions
# Set edit_mode = False
Design Patterns in Use
Reactive Pattern (Implemented)
class HostsManagerApp(App):
# Reactive attributes automatically update UI
hosts_file: reactive[HostsFile] = reactive(HostsFile())
selected_entry_index: reactive[int] = reactive(0)
edit_mode: reactive[bool] = reactive(False)
def on_list_view_highlighted(self, event):
# Automatic UI updates when selection changes
self.selected_entry_index = event.list_view.index or 0
self.update_entry_details()
Data Validation Pattern (Implemented)
@dataclass
class HostEntry:
def __post_init__(self):
# Comprehensive validation on creation
if not self.ip_address or not self.hostnames:
raise ValueError("IP address and hostnames required")
# Validate IP address format
try:
ipaddress.ip_address(self.ip_address)
except ValueError as e:
raise ValueError(f"Invalid IP address: {e}")
Command Pattern (Planned for Phase 4)
# Will be implemented for undo/redo functionality
class Command(ABC):
@abstractmethod
def execute(self) -> HostsFile:
pass
@abstractmethod
def undo(self) -> HostsFile:
pass
Factory Pattern (Implemented)
class HostsParser:
def __init__(self, file_path: str = "/etc/hosts"):
# Single parser handles all hosts file formats
self.file_path = file_path
Critical Implementation Paths
Application Startup (✅ Implemented)
- ✅ Initialize TUI: Textual app with reactive state management
- ✅ Load hosts file: Robust parsing with error handling
- ✅ Build UI: Two-pane layout with ListView and details
- ✅ Enter main loop: Smooth keyboard navigation and event handling
- ✅ Error handling: Graceful degradation for file access issues
Entry Navigation (✅ Implemented)
- ✅ Keyboard navigation: Up/down arrows navigate entries
- ✅ Selection tracking: Reactive updates to selected_entry_index
- ✅ Detail updates: Automatic refresh of right pane details
- ✅ Position restoration: Maintains cursor position on reload
- ✅ Visual feedback: Clear indication of current selection
File Operations (✅ Implemented)
- ✅ File parsing: Comprehensive hosts file format support
- ✅ Comment preservation: Maintains all comments and formatting
- ✅ Error handling: Graceful handling of permission and format errors
- ✅ Validation: Complete IP address and hostname validation
- ✅ Status feedback: Clear user feedback for all operations
Edit Mode Activation (🔄 Planned for Phase 3)
- 🔄 User triggers edit mode: Keyboard shortcut implementation
- 🔄 Request sudo: Secure password prompt
- 🔄 Validate permissions: Ensure write access to
/etc/hosts
- 🔄 Update UI state: Enable edit operations and visual indicators
- 🔄 Maintain permissions: Keep sudo active until explicit exit
Entry Modification (🔄 Planned for Phase 3-4)
- 🔄 User action: Toggle, reorder, or edit entry operations
- 🔄 Create command: Command pattern for undo/redo support
- 🔄 Validate operation: Real-time validation of changes
- 🔄 Execute command: Apply changes to in-memory state
- 🔄 Update UI: Immediate visual feedback
- 🔄 Track dirty state: Mark file as needing save
File Persistence (🔄 Planned for Phase 3)
- 🔄 User saves: Explicit save command or auto-save option
- 🔄 Validate entire file: Comprehensive syntax checking
- 🔄 Create backup: Automatic backup before modifications
- 🔄 Write atomically: Safe temporary file + rename operation
- 🔄 Verify write: Confirm successful file write
DNS Resolution Flow (🔄 Planned for Phase 5)
- 🔄 User requests resolution: For entries with DNS names
- 🔄 Resolve hostname: Async DNS resolution
- 🔄 Compare IPs: Current IP vs resolved IP comparison
- 🔄 Present choice: User dialog for IP selection
- 🔄 Update entry: Apply user's choice with validation
- 🔄 Mark dirty: Flag file for saving
Error Handling Patterns
Graceful Degradation
- Permission denied: Fall back to read-only mode
- DNS resolution failure: Show error but continue
- File corruption: Load what's possible, warn user
- Network unavailable: Disable DNS features
User Feedback
- Status bar: Show current mode and operation status
- Modal dialogs: For errors requiring user attention
- Inline validation: Real-time feedback on input
- Progress indicators: For long-running operations
Recovery Mechanisms
- Undo operations: Allow reverting recent changes
- File restoration: Restore from backup if available
- Safe mode: Minimal functionality if errors occur
- Graceful exit: Always attempt to save valid changes