clickhouseohlc / server.py
Subham9126's picture
Upload 5 files
d88b60b verified
Raw
History Blame Contribute Delete
2.43 kB
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import StreamingResponse, HTMLResponse
import subprocess
import httpx
app = FastAPI(title="Market-Data Observatory")
# Async HTTP client for proxying to ClickHouse's internal HTTP interface
ch_client = httpx.AsyncClient(base_url="http://127.0.0.1:8123", timeout=60.0)
# ── Refresh endpoint (git pull) ──
@app.post("/refresh")
def refresh():
try:
result = subprocess.check_output(
"cd /app/data/ohlc_data && git pull",
shell=True, stderr=subprocess.STDOUT
)
return {"status": "updated", "details": result.decode().strip()}
except subprocess.CalledProcessError as e:
msg = e.output.decode() if e.output else str(e)
raise HTTPException(status_code=500, detail={"error": "Refresh failed", "message": msg})
# ── Health check ──
@app.get("/health")
async def health():
try:
r = await ch_client.get("/ping")
return {"clickhouse": r.text.strip(), "status": "ok"}
except Exception as e:
raise HTTPException(status_code=503, detail={"status": "unhealthy", "error": str(e)})
# ── Catch-all reverse proxy to ClickHouse ──
# This gives you /play, /dashboard, native HTTP API, everything.
@app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD", "PATCH"])
async def proxy_to_clickhouse(request: Request, path: str):
url = httpx.URL(path=f"/{path}", query=request.url.query.encode("utf-8"))
# Forward headers, strip hop-by-hop
headers = dict(request.headers)
for h in ("host", "content-length", "transfer-encoding"):
headers.pop(h, None)
try:
body = await request.body()
req = ch_client.build_request(
method=request.method,
url=url,
headers=headers,
content=body,
)
r = await ch_client.send(req, stream=True)
# Pass through ClickHouse response headers
resp_headers = dict(r.headers)
for h in ("content-length", "content-encoding", "transfer-encoding"):
resp_headers.pop(h, None)
return StreamingResponse(
r.aiter_raw(),
status_code=r.status_code,
headers=resp_headers,
)
except httpx.RequestError as exc:
raise HTTPException(status_code=502, detail=f"ClickHouse proxy error: {exc}")