v9.13: restore stream_instances endpoint (accidentally removed in v9.12)

This commit is contained in:
Naeel
2026-04-16 15:54:35 +03:00
parent 2813d52d3b
commit a662be9c12
2 changed files with 54 additions and 1 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ spec:
spec: spec:
containers: containers:
- name: cloud-dashboard - name: cloud-dashboard
image: naeel/cloud-dashboard:v9.12 image: naeel/cloud-dashboard:v9.13
imagePullPolicy: Always imagePullPolicy: Always
ports: ports:
- containerPort: 8080 - containerPort: 8080
+53
View File
@@ -1,8 +1,10 @@
from fastapi import FastAPI, Header, HTTPException, Request from fastapi import FastAPI, Header, HTTPException, Request
from fastapi.responses import StreamingResponse
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
import httpx import httpx
from typing import Annotated from typing import Annotated
import asyncio import asyncio
import json
import time import time
app = FastAPI() app = FastAPI()
@@ -256,6 +258,57 @@ async def get_graph(
} }
@app.get("/api/instances/stream")
async def stream_instances(
request: Request,
x_deck_token: Annotated[str | None, Header()] = None,
x_deck_env: Annotated[str | None, Header()] = None,
):
if not x_deck_token:
raise HTTPException(status_code=401, detail="Token required")
_, deck_api = resolve_deck_api(x_deck_env)
all_instances = await fetch_all_instances(x_deck_token, deck_api)
uid_to_inst = {
i.get("instanceUid"): i
for i in all_instances
if i.get("instanceUid")
}
async def generate():
sem = asyncio.Semaphore(20)
queue: asyncio.Queue = asyncio.Queue()
total = len(uid_to_inst)
async def fetch_one(uid: str, client: httpx.AsyncClient):
async with sem:
try:
r = await client.get(
f"{deck_api}/index.cfm/instances/{uid}",
headers=auth_headers(x_deck_token),
)
detail = None if r.status_code >= 400 else r.json().get("instance")
except Exception:
detail = None
await queue.put((uid, detail))
async with httpx.AsyncClient(timeout=25) as shared_client:
tasks = [
asyncio.create_task(fetch_one(uid, shared_client))
for uid in uid_to_inst
]
for _ in range(total):
uid, detail = await queue.get()
row = dict(uid_to_inst.get(uid, {}))
if detail:
row["_detail"] = detail
yield json.dumps(row, ensure_ascii=False) + "\n"
yield json.dumps({"_done": True, "total": total}, ensure_ascii=False) + "\n"
return StreamingResponse(generate(), media_type="application/x-ndjson")
@app.get("/api/instances/{uid}") @app.get("/api/instances/{uid}")
async def get_instance( async def get_instance(
request: Request, request: Request,