Files
Medios-Macina/scripts/zerotier_setup.py
2026-01-19 03:14:30 -08:00

133 lines
5.0 KiB
Python

#!/usr/bin/env python3
"""Simple ZeroTier helper for joining networks and discovering peers.
Usage:
python scripts/zerotier_setup.py --join <network_id>
python scripts/zerotier_setup.py --list
python scripts/zerotier_setup.py --discover <network_id>
This is a convenience tool to exercise the API/zerotier.py functionality while
prototyping and bringing up remote peers for store testing.
"""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
from SYS.logger import log
try:
from API import zerotier
except Exception:
zerotier = None
def main(argv=None):
parser = argparse.ArgumentParser(description="ZeroTier helper for Medios-Macina")
parser.add_argument("--list", action="store_true", help="List local ZeroTier networks")
parser.add_argument("--join", type=str, help="Join a ZeroTier network by ID")
parser.add_argument("--leave", type=str, help="Leave a ZeroTier network by ID")
parser.add_argument("--discover", type=str, help="Discover services on a ZeroTier network ID")
parser.add_argument("--upload", type=str, help="Upload a file to a discovered 'remote' service on this ZeroTier network ID")
parser.add_argument("--file", type=str, help="Local file to upload (used with --upload)")
parser.add_argument("--tag", action="append", help="Tag to attach (repeatable)", default=[])
parser.add_argument("--url", action="append", help="URL to associate (repeatable)", default=[])
parser.add_argument("--api-key", type=str, help="API key to use for uploads (optional)")
parser.add_argument("--json", action="store_true", help="Output JSON when appropriate")
args = parser.parse_args(argv)
if zerotier is None:
log("ZeroTier API module not available; ensure API/zerotier.py is importable and zerotier or zerotier-cli is installed")
return 1
if args.list:
nets = zerotier.list_networks()
if args.json:
print(json.dumps([n.__dict__ for n in nets], indent=2))
else:
for n in nets:
print(f"{n.id}\t{name:=}{n.name}\t{n.status}\t{n.assigned_addresses}")
return 0
if args.join:
try:
ok = zerotier.join_network(args.join)
print("Joined" if ok else "Failed to join")
return 0 if ok else 2
except Exception as exc:
log(f"Join failed: {exc}")
print(f"Join failed: {exc}")
return 2
if args.leave:
try:
ok = zerotier.leave_network(args.leave)
print("Left" if ok else "Failed to leave")
return 0 if ok else 2
except Exception as exc:
log(f"Leave failed: {exc}")
print(f"Leave failed: {exc}")
return 2
if args.discover:
probes = zerotier.discover_services_on_network(args.discover)
if args.json:
print(json.dumps([p.__dict__ for p in probes], indent=2, default=str))
else:
for p in probes:
print(f"{p.address}:{p.port}{p.path} -> status={p.status_code} hint={p.service_hint}")
return 0
if args.upload:
# Upload a file to the first discovered remote service on the network
if not args.file:
print("ERROR: --file is required for --upload")
return 2
probe = zerotier.find_peer_service(args.upload, service_hint="remote")
if not probe:
print("No remote service found on network")
return 2
base = f"http://{probe.address}:{probe.port}"
try:
import httpx
url = base.rstrip("/") + "/files/upload"
headers = {}
if args.api_key:
headers["X-API-Key"] = args.api_key
with open(args.file, "rb") as fh:
files = {"file": (Path(args.file).name, fh)}
data = []
for t in (args.tag or []):
data.append(("tag", t))
for u in (args.url or []):
data.append(("url", u))
resp = httpx.post(url, files=files, data=data, headers=headers, timeout=30)
print(resp.status_code, resp.text)
return 0 if resp.status_code in (200, 201) else 2
except Exception:
import requests
url = base.rstrip("/") + "/files/upload"
headers = {}
if args.api_key:
headers["X-API-Key"] = args.api_key
with open(args.file, "rb") as fh:
files = {"file": (Path(args.file).name, fh)}
data = []
for t in (args.tag or []):
data.append(("tag", t))
for u in (args.url or []):
data.append(("url", u))
resp = requests.post(url, files=files, data=data, headers=headers, timeout=30)
print(resp.status_code, resp.text)
return 0 if resp.status_code in (200, 201) else 2
parser.print_help()
return 0
if __name__ == "__main__":
sys.exit(main())