14 KiB
14 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
and src/hosts/tui/
)
- ✅ HostsManagerApp: Complete Textual application with reactive state management and DataTable interface
- ✅ ConfigModal: Professional modal dialog for configuration management
- ✅ Responsibilities: User interaction, display logic, event handling, navigation, configuration UI
- ✅ Dependencies: Core models, parser, and config for data operations
- ✅ Implementation: Two-pane layout with DataTable, modal system, and rich visual styling
Core Layer (src/hosts/core/
)
- ✅ models.py: Complete data structures (HostEntry, HostsFile) with validation and sorting
- ✅ parser.py: Robust hosts file parsing, serialization, and file operations
- ✅ config.py: Configuration management with JSON persistence and default handling
- ✅ Responsibilities: Pure business logic, data validation, file integrity, settings management
- ✅ Implementation: Comprehensive validation, error handling, and configuration persistence
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]
# Configuration Management (Implemented)
class Config:
def __init__(self):
self.config_dir = Path.home() / ".config" / "hosts-manager"
self.config_file = self.config_dir / "config.json"
self._settings = self._load_default_settings()
# Implemented methods:
def load(self) -> None
def save(self) -> None
def get(self, key: str, default: Any = None) -> Any
def set(self, key: str, value: Any) -> None
def is_default_entry(self, ip_address: str, hostname: str) -> bool
def should_show_default_entries(self) -> bool
def toggle_show_default_entries(self) -> None
State Management (Implemented)
- ✅ Reactive state: Using Textual's reactive attributes for complex UI updates
- ✅ Configuration state: Persistent settings with JSON storage and graceful error handling
- ✅ Sorting state: Reactive sort column and direction with visual indicators
- ✅ Validation pipeline: All data validated in models, parser, and configuration
- ✅ File integrity: Atomic operations preserve file structure
- ✅ Error handling: Graceful degradation for all error conditions
- ✅ Modal state: Professional modal dialog lifecycle management
- 🔄 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)
sort_column: reactive[str] = reactive("") # "ip" or "hostname"
sort_ascending: reactive[bool] = reactive(True)
def on_data_table_row_highlighted(self, event):
# Automatic UI updates when selection changes
self.selected_entry_index = event.cursor_row
self.update_entry_details()
def on_data_table_header_selected(self, event):
# Interactive column sorting
if "IP Address" in str(event.column_key):
self.action_sort_by_ip()
elif "Canonical Hostname" in str(event.column_key):
self.action_sort_by_hostname()
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
# Configuration Factory Pattern (Implemented)
class Config:
def _load_default_settings(self) -> Dict[str, Any]:
# Factory method for default configuration
return {
"show_default_entries": False,
"default_entries": [
{"ip": "127.0.0.1", "hostname": "localhost"},
{"ip": "255.255.255.255", "hostname": "broadcasthost"},
{"ip": "::1", "hostname": "localhost"},
],
"window_settings": {
"last_sort_column": "",
"last_sort_ascending": True,
}
}
Modal Pattern (Implemented)
class ConfigModal(ModalScreen):
def __init__(self, config: Config):
super().__init__()
self.config = config
def action_save(self) -> None:
# Save configuration and close modal
checkbox = self.query_one("#show-defaults-checkbox", Checkbox)
self.config.set("show_default_entries", checkbox.value)
self.config.save()
self.dismiss(True)
def action_cancel(self) -> None:
# Cancel changes and close modal
self.dismiss(False)
Critical Implementation Paths
Application Startup (✅ Implemented)
- ✅ Initialize TUI: Textual app with reactive state management and configuration loading
- ✅ Load configuration: JSON settings with graceful error handling and defaults
- ✅ Load hosts file: Robust parsing with error handling and filtering
- ✅ Build UI: Two-pane layout with DataTable, details, and modal system
- ✅ Enter main loop: Smooth keyboard navigation, sorting, and event handling
- ✅ Error handling: Graceful degradation for file access and configuration issues
Entry Navigation (✅ Implemented)
- ✅ DataTable navigation: Professional table with cursor and selection tracking
- ✅ Keyboard navigation: Up/down arrows, header clicking, and keyboard shortcuts
- ✅ Selection tracking: Reactive updates to selected_entry_index with DataTable events
- ✅ Detail updates: Automatic refresh of right pane details with rich formatting
- ✅ Position restoration: Maintains cursor position on reload with intelligent matching
- ✅ Visual feedback: Color-coded entries with clear active/inactive indication
File Operations (✅ Implemented)
- ✅ File parsing: Comprehensive hosts file format support with edge case handling
- ✅ Comment preservation: Maintains all comments and formatting perfectly
- ✅ Error handling: Graceful handling of permission, format, and configuration errors
- ✅ Validation: Complete IP address and hostname validation with user feedback
- ✅ Status feedback: Rich status bar with detailed information and operation feedback
- ✅ Configuration integration: Settings-aware parsing and display
Configuration Management (✅ Implemented)
- ✅ Settings loading: JSON configuration with graceful error handling
- ✅ Default management: Intelligent default entry detection and filtering
- ✅ Modal interface: Professional configuration dialog with keyboard bindings
- ✅ Persistence: Automatic saving to ~/.config/hosts-manager/ directory
- ✅ Live updates: Immediate application of configuration changes
- ✅ Error recovery: Fallback to defaults on configuration errors
Sorting and Filtering (✅ Implemented)
- ✅ Interactive sorting: Click column headers to sort by IP or hostname
- ✅ Sort direction toggle: Ascending/descending with visual indicators
- ✅ Keyboard shortcuts: Sort by IP (i) and hostname (n) keys
- ✅ Visual feedback: Sort arrows in column headers showing current state
- ✅ Default entry filtering: Hide/show system entries based on configuration
- ✅ Intelligent IP sorting: Proper IPv4/IPv6 numerical sorting
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 with clear status indication
- Configuration errors: Use defaults and continue with warning
- File corruption: Load what's possible, warn user, maintain functionality
- DNS resolution failure: Show error but continue (planned for Phase 5)
- Network unavailable: Disable DNS features (planned for Phase 5)
User Feedback
- Rich status bar: Show current mode, entry counts, file path, and operation status
- Modal dialogs: Professional configuration interface with proper keyboard handling
- Color-coded entries: Visual distinction between active/inactive entries
- Sort indicators: Visual arrows showing current sort column and direction
- Interactive headers: Click feedback and hover states for column sorting
- Progress indicators: For long-running operations (planned for Phase 3)
Recovery Mechanisms
- Configuration fallback: Automatic fallback to defaults on configuration errors
- Position restoration: Intelligent cursor position maintenance on reload
- Error isolation: Configuration errors don't affect core functionality
- Undo operations: Allow reverting recent changes (planned for Phase 4)
- File restoration: Restore from backup if available (planned for Phase 3)
- Safe mode: Minimal functionality if errors occur
- Graceful exit: Always attempt to save valid changes and configuration