"""Peer history tracking. Ported from net.i2p.router.peermanager.DBHistory / TunnelHistory. """ import time from dataclasses import dataclass, field @dataclass class HistoryEntry: timestamp: float success: bool latency_ms: float = 0.0 detail: str = "" class DBHistory: """Historical record of NetDB operations with a peer.""" def __init__(self, max_entries: int = 100): self._entries: list[HistoryEntry] = [] self._max_entries = max_entries def _add_entry(self, entry: HistoryEntry) -> None: self._entries.append(entry) if len(self._entries) > self._max_entries: self._entries = self._entries[-self._max_entries:] def record_store(self, success: bool, latency_ms: float = 0.0) -> None: self._add_entry(HistoryEntry( timestamp=time.time(), success=success, latency_ms=latency_ms, detail="store", )) def record_lookup(self, success: bool, latency_ms: float = 0.0) -> None: self._add_entry(HistoryEntry( timestamp=time.time(), success=success, latency_ms=latency_ms, detail="lookup", )) @property def success_rate(self) -> float: if not self._entries: return 0.0 successes = sum(1 for e in self._entries if e.success) return successes / len(self._entries) @property def average_latency(self) -> float: if not self._entries: return 0.0 return sum(e.latency_ms for e in self._entries) / len(self._entries) @property def recent_entries(self) -> list[HistoryEntry]: return list(self._entries) class TunnelHistory: """Historical record of tunnel participation.""" def __init__(self, max_entries: int = 100): self._entries: list[HistoryEntry] = [] self._max_entries = max_entries def _add_entry(self, entry: HistoryEntry) -> None: self._entries.append(entry) if len(self._entries) > self._max_entries: self._entries = self._entries[-self._max_entries:] def record_build(self, success: bool) -> None: self._add_entry(HistoryEntry( timestamp=time.time(), success=success, detail="build", )) def record_participation(self, success: bool, data_transferred: int = 0) -> None: self._add_entry(HistoryEntry( timestamp=time.time(), success=success, detail=f"participate:{data_transferred}", )) @property def build_success_rate(self) -> float: builds = [e for e in self._entries if e.detail == "build"] if not builds: return 0.0 return sum(1 for e in builds if e.success) / len(builds) @property def participation_rate(self) -> float: participations = [e for e in self._entries if e.detail.startswith("participate")] if not participations: return 0.0 return sum(1 for e in participations if e.success) / len(participations)