v9.13: restore stream_instances endpoint (accidentally removed in v9.12)
This commit is contained in:
+1
-1
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user