"""Addressbook manager for SusiDNS. Manages hostname-to-destination mappings with search, file I/O, and integration with the addressbook storage. Ported from i2p.susi.dns.AddressbookBean. """ from __future__ import annotations from dataclasses import dataclass from pathlib import Path @dataclass class AddressbookEntry: """A single hostname→destination mapping.""" hostname: str destination: str def __str__(self) -> str: return f"{self.hostname}={self.destination}" class AddressbookManager: """Manages .i2p hostname-to-destination mappings.""" def __init__(self) -> None: self._entries: dict[str, str] = {} def add(self, hostname: str, destination: str) -> None: """Add or update an entry.""" self._entries[hostname] = destination def remove(self, hostname: str) -> None: """Remove an entry.""" self._entries.pop(hostname, None) def lookup(self, hostname: str) -> str | None: """Look up a destination by hostname.""" return self._entries.get(hostname) def list_entries(self) -> list[AddressbookEntry]: """List all entries sorted by hostname.""" return [ AddressbookEntry(h, d) for h, d in sorted(self._entries.items()) ] def search(self, query: str) -> list[AddressbookEntry]: """Search entries by hostname prefix.""" query_lower = query.lower() return [ AddressbookEntry(h, d) for h, d in sorted(self._entries.items()) if query_lower in h.lower() ] def save(self, path: Path) -> None: """Save entries to a hosts.txt file.""" lines = [f"{h}={d}" for h, d in sorted(self._entries.items())] path.write_text("\n".join(lines) + "\n") @classmethod def from_file(cls, path: Path) -> AddressbookManager: """Load entries from a hosts.txt file.""" mgr = cls() if not path.exists(): return mgr for line in path.read_text().splitlines(): line = line.strip() if not line or line.startswith("#"): continue if "=" in line: hostname, destination = line.split("=", 1) mgr.add(hostname.strip(), destination.strip()) return mgr