"""Command line entrypoints for the LAN visualizer.""" from __future__ import annotations import asyncio import json from pathlib import Path import typer from network_mapper.scanner import NetworkScanner app = typer.Typer(help="LAN discovery + visualization tooling") @app.command() def scan( cidr: str | None = typer.Option( None, help="CIDR range to probe (defaults to the primary IPv4 network).", ), concurrency: int = typer.Option(32, help="Limit the number of simultaneous pings."), ssh_timeout: float = typer.Option(5.0, help="Seconds to wait for SSH probes."), ssh_user: str | None = typer.Option( None, envvar="SSH_USER", help="Username for SSH probes when key auth is available.", ), ssh_key: Path | None = typer.Option( None, envvar="SSH_KEY_PATH", exists=True, file_okay=True, dir_okay=False, help="Private key path for passwordless SSH execution.", ), output: Path | None = typer.Option( None, exists=False, file_okay=True, dir_okay=False, help="Write the scan result JSON to this file instead of stdout.", ), ): """Run a single scan and emit JSON results.""" scanner = NetworkScanner(ssh_user=ssh_user, ssh_key_path=str(ssh_key) if ssh_key else None) result = asyncio.run(scanner.scan(cidr=cidr, concurrency=concurrency, ssh_timeout=ssh_timeout)) payload = result.to_dict() serialized = json.dumps(payload, indent=2) if output: output.write_text(serialized) typer.echo(f"Scan saved to {output}") else: typer.echo(serialized) @app.command() def serve(host: str = "0.0.0.0", port: int = 8000, reload: bool = False): """Start the FastAPI server and front-end.""" import uvicorn uvicorn.run("network_mapper.main:app", host=host, port=port, reload=reload)