""" Progress Bar Widget for PCAP parsing progress """ from textual.widget import Widget from textual.reactive import reactive from rich.console import RenderableType from rich.progress import Progress, BarColumn, TextColumn, TaskProgressColumn, MofNCompleteColumn, TimeRemainingColumn from rich.text import Text import time class ParsingProgressBar(Widget): """Progress bar widget for PCAP parsing with rich formatting""" DEFAULT_CSS = """ ParsingProgressBar { height: 3; margin: 1; padding: 1; background: $surface; border: solid $accent; } """ # Reactive attributes progress = reactive(0.0) total_packets = reactive(0) processed_packets = reactive(0) packets_per_second = reactive(0.0) estimated_time_remaining = reactive(0.0) is_complete = reactive(False) is_visible = reactive(False) error_message = reactive("") def __init__(self, **kwargs): super().__init__(**kwargs) self.start_time = None def render(self) -> RenderableType: """Render the progress bar""" if not self.is_visible: return Text("") if self.error_message: return Text(f"❌ Error: {self.error_message}", style="red") if self.is_complete: elapsed = time.time() - self.start_time if self.start_time else 0 return Text( f"✅ Parsing complete! {self.processed_packets:,} packets processed in {elapsed:.1f}s", style="green" ) # Create rich progress bar progress = Progress( TextColumn("[bold blue]Parsing PCAP..."), BarColumn(bar_width=40), TaskProgressColumn(), MofNCompleteColumn(), TextColumn("•"), TextColumn("{task.fields[rate]}"), TextColumn("•"), TimeRemainingColumn(), expand=False ) # Format rate display if self.packets_per_second >= 1000: rate_str = f"{self.packets_per_second/1000:.1f}K pkt/s" else: rate_str = f"{self.packets_per_second:.0f} pkt/s" task = progress.add_task( "parsing", total=self.total_packets, completed=self.processed_packets, rate=rate_str ) return progress def start_parsing(self, total_packets: int): """Start showing progress for parsing""" self.total_packets = total_packets self.processed_packets = 0 self.progress = 0.0 self.is_complete = False self.is_visible = True self.error_message = "" self.start_time = time.time() self.refresh() def update_progress(self, processed: int, total: int, pps: float, eta: float): """Update progress values""" self.processed_packets = processed self.total_packets = total self.packets_per_second = pps self.estimated_time_remaining = eta self.progress = (processed / total * 100) if total > 0 else 0 self.refresh() def complete_parsing(self): """Mark parsing as complete""" self.is_complete = True self.refresh() # Hide after 3 seconds self.set_timer(3.0, self.hide_progress) def show_error(self, error: str): """Show error message""" self.error_message = error self.is_visible = True self.refresh() # Hide after 5 seconds self.set_timer(5.0, self.hide_progress) def hide_progress(self): """Hide the progress bar""" self.is_visible = False self.refresh()