Document who can call the loopback API and let the user pick the listen port.

This commit is contained in:
alexveley
2026-09-22 08:19:12 -04:00
parent cfda629418
commit 33944dbd07
10 changed files with 184 additions and 18 deletions
+48 -4
View File
@@ -20,9 +20,12 @@ if sys.platform == "win32":
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
HOST = "127.0.0.1"
PORT = int(os.environ.get("FAB_PORT", "17634"))
DEFAULT_PORT = int(os.environ.get("FAB_PORT", "17634"))
PORT = DEFAULT_PORT
MAX_BODY = 256 * 1024
ALLOWED_HOSTS = {f"127.0.0.1:{PORT}", f"localhost:{PORT}"}
HTTP_SERVER: ThreadingHTTPServer | None = None
SERVER_LOCK = threading.Lock()
ALLOWED_METHODS = frozenset(
{
"meta.ping",
@@ -45,6 +48,45 @@ PENDING: dict[str, tuple[threading.Event, dict[str, Any]]] = {}
PENDING_LOCK = threading.Lock()
def set_port_globals(port: int) -> None:
global PORT, ALLOWED_HOSTS
PORT = port
ALLOWED_HOSTS = {f"127.0.0.1:{port}", f"localhost:{port}"}
def apply_listen_port(requested: Any) -> dict[str, Any]:
global HTTP_SERVER
try:
port = int(requested)
except (TypeError, ValueError):
return {"type": "config-result", "ok": False, "error": "invalid port"}
if port < 1024 or port > 65535:
return {
"type": "config-result",
"ok": False,
"port": port,
"error": "port must be 102465535",
}
with SERVER_LOCK:
if HTTP_SERVER is not None and PORT == port:
return {"type": "config-result", "ok": True, "port": port}
old = HTTP_SERVER
HTTP_SERVER = None
if old is not None:
old.shutdown()
old.server_close()
try:
set_port_globals(port)
HTTP_SERVER = ThreadingHTTPServer((HOST, port), Handler)
except OSError as exc:
return {"type": "config-result", "ok": False, "port": port, "error": str(exc)}
threading.Thread(
target=HTTP_SERVER.serve_forever, name="fab-http", daemon=True
).start()
log(f"listening on http://{HOST}:{port}")
return {"type": "config-result", "ok": True, "port": port}
def log(msg: str) -> None:
sys.stderr.write(msg + "\n")
sys.stderr.flush()
@@ -252,6 +294,9 @@ def stdin_loop() -> None:
break
if message is None:
break
if message.get("type") == "config":
send_to_extension(apply_listen_port(message.get("port")))
continue
req_id = str(message.get("id") or "")
with PENDING_LOCK:
pending = PENDING.pop(req_id, None)
@@ -265,10 +310,9 @@ def stdin_loop() -> None:
def main() -> int:
threading.Thread(target=stdin_loop, name="fab-stdin", daemon=True).start()
server = ThreadingHTTPServer((HOST, PORT), Handler)
log(f"listening on http://{HOST}:{PORT}")
apply_listen_port(DEFAULT_PORT)
try:
server.serve_forever()
threading.Event().wait()
except KeyboardInterrupt:
return 0
return 0