mdns-termux/lib/mdns_tools/hosts.py

78 lines
2.3 KiB
Python

"""Sync discovered mDNS hosts into the system hosts file.
Writes a managed block so native tools (ping, curl, kubectl) resolve `.local`
names without the `resolve` wrapper. Only IPv4, only the managed block is
touched — the rest of the file is preserved.
"""
import os
from pathlib import Path
from . import browse as _browse
from ._pick import pick_best
MARK_BEGIN = "# >>> mdns-termux managed >>>"
MARK_END = "# <<< mdns-termux managed <<<"
def hosts_path() -> Path:
prefix = os.environ.get("PREFIX", "")
if prefix and "com.termux" in prefix:
return Path(prefix) / "etc" / "hosts"
return Path("/etc/hosts")
def collect(duration: float = 3.0) -> dict[str, str]:
"""Return {hostname.local: best_ipv4} from all advertised services."""
out: dict[str, str] = {}
for it in _browse.browse(None, duration):
server = (it.get("server") or "").rstrip(".")
v4 = [a for a in (it.get("addresses") or []) if ":" not in a]
if not server or not v4:
continue
best = pick_best(v4, family="v4")
if best and server not in out:
out[server] = best
return out
def _render_block(mapping: dict[str, str]) -> str:
lines = [MARK_BEGIN]
for host in sorted(mapping):
short = host[:-6] if host.endswith(".local") else host
lines.append(f"{mapping[host]}\t{host} {short}")
lines.append(MARK_END)
return "\n".join(lines)
def _strip_block(text: str) -> str:
out, skip = [], False
for line in text.splitlines():
if line.strip() == MARK_BEGIN:
skip = True
continue
if line.strip() == MARK_END:
skip = False
continue
if not skip:
out.append(line)
return "\n".join(out).rstrip("\n")
def sync(duration: float = 3.0, dry_run: bool = False) -> int:
mapping = collect(duration)
if not mapping:
print("no hosts discovered on the LAN")
return 1
block = _render_block(mapping)
if dry_run:
print(block)
return 0
path = hosts_path()
original = path.read_text() if path.exists() else "127.0.0.1\tlocalhost\n"
body = _strip_block(original)
path.write_text(f"{body}\n{block}\n")
print(f"wrote {len(mapping)} host(s) to {path}")
for host, ip in sorted(mapping.items()):
print(f" {ip}\t{host}")
return 0