Spaces:
Running on Zero
Running on Zero
Buffy commited on
Commit Β·
6da16aa
1
Parent(s): fcbf608
Clean diagnostics: keep status/version/proxy only
Browse files- node_probe.py +5 -63
node_probe.py
CHANGED
|
@@ -1,35 +1,22 @@
|
|
| 1 |
-
"""
|
|
|
|
| 2 |
|
| 3 |
Mounted under /respite/v2/node/*:
|
| 4 |
/status β is the runtime bootstrapped, is the child alive
|
| 5 |
/version β runs `node --version` as a child process
|
| 6 |
-
/
|
| 7 |
-
|
| 8 |
"""
|
| 9 |
|
| 10 |
-
import json
|
| 11 |
import os
|
| 12 |
import subprocess
|
| 13 |
-
import threading
|
| 14 |
-
import time
|
| 15 |
-
import urllib.request
|
| 16 |
|
| 17 |
import httpx
|
| 18 |
from fastapi import Request
|
| 19 |
-
from fastapi.responses import JSONResponse
|
| 20 |
|
| 21 |
import node_runtime
|
| 22 |
|
| 23 |
-
_TRIVIAL_SERVER_JS = """const http = require('http');
|
| 24 |
-
const s = http.createServer((req, res) => {
|
| 25 |
-
res.writeHead(200, {'content-type': 'application/json'});
|
| 26 |
-
res.end(JSON.stringify({ok: true, url: req.url, ts: Date.now()}));
|
| 27 |
-
});
|
| 28 |
-
s.listen(3211, '127.0.0.1', () => console.log('trivial server on 3211'));
|
| 29 |
-
"""
|
| 30 |
-
_trivial_proc = None
|
| 31 |
-
_trivial_lock = threading.Lock()
|
| 32 |
-
|
| 33 |
|
| 34 |
def _node_path() -> str | None:
|
| 35 |
try:
|
|
@@ -48,27 +35,6 @@ def register_routes(fa_app):
|
|
| 48 |
"backend_dir": node_runtime.BACKEND_DIR,
|
| 49 |
})
|
| 50 |
|
| 51 |
-
@fa_app.get("/respite/v2/node/envcheck")
|
| 52 |
-
def _envcheck():
|
| 53 |
-
keys = sorted(k for k in os.environ if "API" in k.upper() or "KEY" in k.upper() or "TOKEN" in k.upper())
|
| 54 |
-
return JSONResponse({"matching_keys": keys, "hf_token_present": bool(os.environ.get("HF_TOKEN"))})
|
| 55 |
-
|
| 56 |
-
@fa_app.get("/respite/v2/node/childenv")
|
| 57 |
-
def _childenv():
|
| 58 |
-
"""What env does the Node child see? (names only)"""
|
| 59 |
-
node = _node_path()
|
| 60 |
-
if not node:
|
| 61 |
-
return JSONResponse({"error": "no node"}, status_code=500)
|
| 62 |
-
r = subprocess.run(
|
| 63 |
-
[node, "-e", "const o={};for(const k of Object.keys(process.env))if(/API|KEY|TOKEN/i.test(k))o[k]=(process.env[k]||'').length;console.log(JSON.stringify(o))"],
|
| 64 |
-
capture_output=True, text=True, timeout=30,
|
| 65 |
-
)
|
| 66 |
-
import json as _j
|
| 67 |
-
try:
|
| 68 |
-
return JSONResponse({"child_keys": _j.loads(r.stdout.strip())})
|
| 69 |
-
except Exception:
|
| 70 |
-
return JSONResponse({"stdout": r.stdout[:300], "stderr": r.stderr[:300]})
|
| 71 |
-
|
| 72 |
@fa_app.get("/respite/v2/node/version")
|
| 73 |
def _version():
|
| 74 |
node = _node_path()
|
|
@@ -77,30 +43,6 @@ def register_routes(fa_app):
|
|
| 77 |
r = subprocess.run([node, "--version"], capture_output=True, text=True, timeout=30)
|
| 78 |
return JSONResponse({"stdout": r.stdout.strip(), "stderr": r.stderr.strip()[:400], "code": r.returncode})
|
| 79 |
|
| 80 |
-
@fa_app.get("/respite/v2/node/server")
|
| 81 |
-
def _server():
|
| 82 |
-
"""Start a trivial Node HTTP server on 127.0.0.1:3211 and fetch it."""
|
| 83 |
-
global _trivial_proc
|
| 84 |
-
node = _node_path()
|
| 85 |
-
if not node:
|
| 86 |
-
return JSONResponse({"error": "node bootstrap failed"}, status_code=500)
|
| 87 |
-
with _trivial_lock:
|
| 88 |
-
if _trivial_proc is None or _trivial_proc.poll() is not None:
|
| 89 |
-
path = os.path.join(node_runtime.RUNTIME_DIR, "trivial.js")
|
| 90 |
-
os.makedirs(node_runtime.RUNTIME_DIR, exist_ok=True)
|
| 91 |
-
with open(path, "w") as f:
|
| 92 |
-
f.write(_TRIVIAL_SERVER_JS)
|
| 93 |
-
_trivial_proc = subprocess.Popen(
|
| 94 |
-
[node, path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True
|
| 95 |
-
)
|
| 96 |
-
time.sleep(1.5)
|
| 97 |
-
try:
|
| 98 |
-
with urllib.request.urlopen("http://127.0.0.1:3211/ping", timeout=5) as resp:
|
| 99 |
-
body = json.loads(resp.read().decode())
|
| 100 |
-
return JSONResponse({"fetch_ok": True, "body": body})
|
| 101 |
-
except Exception as e:
|
| 102 |
-
return JSONResponse({"fetch_ok": False, "error": str(e)}, status_code=500)
|
| 103 |
-
|
| 104 |
@fa_app.get("/respite/v2/node/proxy/{path:path}")
|
| 105 |
@fa_app.post("/respite/v2/node/proxy/{path:path}")
|
| 106 |
async def _proxy(request: Request, path: str):
|
|
|
|
| 1 |
+
"""Node backend bridge β runs the existing Next.js Respite backend inside
|
| 2 |
+
the Space container (userspace Node, no root) and reverse-proxies to it.
|
| 3 |
|
| 4 |
Mounted under /respite/v2/node/*:
|
| 5 |
/status β is the runtime bootstrapped, is the child alive
|
| 6 |
/version β runs `node --version` as a child process
|
| 7 |
+
/proxy β reverse-proxy <path> (+ query/body/headers) to the Node backend,
|
| 8 |
+
streaming both ways (SSE included)
|
| 9 |
"""
|
| 10 |
|
|
|
|
| 11 |
import os
|
| 12 |
import subprocess
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
import httpx
|
| 15 |
from fastapi import Request
|
| 16 |
+
from fastapi.responses import JSONResponse
|
| 17 |
|
| 18 |
import node_runtime
|
| 19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
def _node_path() -> str | None:
|
| 22 |
try:
|
|
|
|
| 35 |
"backend_dir": node_runtime.BACKEND_DIR,
|
| 36 |
})
|
| 37 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
@fa_app.get("/respite/v2/node/version")
|
| 39 |
def _version():
|
| 40 |
node = _node_path()
|
|
|
|
| 43 |
r = subprocess.run([node, "--version"], capture_output=True, text=True, timeout=30)
|
| 44 |
return JSONResponse({"stdout": r.stdout.strip(), "stderr": r.stderr.strip()[:400], "code": r.returncode})
|
| 45 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
@fa_app.get("/respite/v2/node/proxy/{path:path}")
|
| 47 |
@fa_app.post("/respite/v2/node/proxy/{path:path}")
|
| 48 |
async def _proxy(request: Request, path: str):
|