"""meshnet-tracker CLI entry point.""" import argparse import sys import time from .accounts import DEFAULT_ACCOUNTS_DB_PATH from .billing import DEFAULT_BILLING_DB_PATH from .server import TrackerServer, derive_relay_url_from_public_tracker_url def main() -> None: common = argparse.ArgumentParser(add_help=False) common.add_argument("--host", default="0.0.0.0", help="Host interface to listen on") common.add_argument("--port", type=int, default=8080, help="Port to listen on") common.add_argument( "--heartbeat-timeout", type=float, default=30.0, help="Seconds before a node is removed from the registry after missed heartbeat", ) common.add_argument( "--cluster-peers", default="", help="Comma-separated URLs of peer tracker nodes (enables Raft cluster mode)", ) common.add_argument( "--self-url", default=None, help="This tracker's own URL as seen by peers (auto-derived from --host/--port if omitted)", ) common.add_argument( "--stats-db", default=None, metavar="PATH", help="SQLite database path for persistent model usage statistics", ) common.add_argument( "--relay-url", default=None, help="Public ws(s):// relay URL advertised to nodes, for example wss://ai.neuron.d-popov.com/ws", ) common.add_argument( "--billing-db", default=DEFAULT_BILLING_DB_PATH, metavar="PATH", help=( "SQLite database path for the USDT billing ledger " f"(default: {DEFAULT_BILLING_DB_PATH}; ADR-0015)" ), ) common.add_argument( "--no-billing", action="store_true", help="Disable the USDT billing ledger", ) common.add_argument( "--accounts-db", default=DEFAULT_ACCOUNTS_DB_PATH, metavar="PATH", help=( "SQLite database path for dashboard user accounts " f"(default: {DEFAULT_ACCOUNTS_DB_PATH})" ), ) common.add_argument( "--no-accounts", action="store_true", help="Disable dashboard user accounts (registration/login)", ) common.add_argument( "--solana-rpc-url", default=None, help="Solana RPC URL (e.g. https://api.devnet.solana.com); enables the on-chain treasury", ) common.add_argument( "--usdt-mint", default=None, help="SPL mint address of (mock) USDT — see scripts/devnet_setup.py", ) common.add_argument( "--treasury-keypair", default=None, metavar="PATH", help="Treasury keypair JSON path (only on settlement-capable trackers)", ) common.add_argument( "--settle-period", type=float, default=86400.0, help="Max seconds between payouts to a node (dev: 60, prod: 86400)", ) common.add_argument( "--payout-threshold", type=float, default=5.0, help="Pending USDT that triggers an immediate payout (dev: 0)", ) common.add_argument( "--payout-dust-floor", type=float, default=0.01, help="Never pay out less than this many USDT", ) parser = argparse.ArgumentParser( prog="meshnet-tracker", description="Distributed Inference Network node registry and route selection", parents=[common], ) subparsers = parser.add_subparsers(dest="command") subparsers.add_parser("start", help="Start the tracker server", parents=[common]) args = parser.parse_args() if args.command in {None, "start"}: cluster_peers = [u.strip() for u in args.cluster_peers.split(",") if u.strip()] relay_url = args.relay_url or derive_relay_url_from_public_tracker_url(args.self_url) treasury = None if args.solana_rpc_url and args.usdt_mint and args.treasury_keypair: from meshnet_contracts.solana_adapter import SolanaCustodialTreasury treasury = SolanaCustodialTreasury( args.solana_rpc_url, args.usdt_mint, args.treasury_keypair, ) server = TrackerServer( host=args.host, port=args.port, heartbeat_timeout=args.heartbeat_timeout, cluster_peers=cluster_peers or None, cluster_self_url=args.self_url, stats_db=getattr(args, "stats_db", None), relay_url=relay_url, enable_billing=not args.no_billing, billing_db=None if args.no_billing else args.billing_db, accounts_db=None if args.no_accounts else args.accounts_db, treasury=treasury, settle_period=args.settle_period, payout_threshold=args.payout_threshold, payout_dust_floor=args.payout_dust_floor, ) port = server.start() print(f"meshnet-tracker listening on http://{args.host}:{port}", flush=True) try: while True: time.sleep(1) except KeyboardInterrupt: server.stop() sys.exit(0) else: parser.print_help() if __name__ == "__main__": main()