Compare commits
3 commits
07b80e654f
...
f4b3a09151
| Author | SHA1 | Date | |
|---|---|---|---|
| f4b3a09151 | |||
| 1058f2418b | |||
| 263c66aedd |
2 changed files with 21 additions and 3 deletions
18
router.py
18
router.py
|
|
@ -6,7 +6,7 @@ version: 0.7
|
|||
license: AGPL
|
||||
"""
|
||||
# -------------------------------------------------------------
|
||||
import orjson, time, asyncio, yaml, ollama, openai, os, re, aiohttp, ssl, random, base64, io, enhance, secrets, math
|
||||
import orjson, time, asyncio, yaml, ollama, openai, os, re, aiohttp, ssl, random, base64, io, enhance, secrets, math, socket
|
||||
try:
|
||||
import truststore; truststore.inject_into_ssl()
|
||||
except ImportError:
|
||||
|
|
@ -373,7 +373,11 @@ async def enforce_router_api_key(request: Request, call_next):
|
|||
return await call_next(request)
|
||||
|
||||
path = request.url.path
|
||||
if path.startswith("/static") or path in {"/", "/favicon.ico"}:
|
||||
# Allow static assets (CSS, JS, images, fonts) but NOT HTML pages,
|
||||
# which would bypass auth by accessing /static/index.html directly.
|
||||
_STATIC_ASSET_EXTS = {".css", ".js", ".ico", ".png", ".jpg", ".jpeg", ".svg", ".woff", ".woff2", ".ttf", ".map"}
|
||||
is_static_asset = path.startswith("/static") and Path(path).suffix.lower() in _STATIC_ASSET_EXTS
|
||||
if is_static_asset or path in {"/", "/favicon.ico"}:
|
||||
return await call_next(request)
|
||||
|
||||
provided_key = _extract_router_api_key(request)
|
||||
|
|
@ -3776,7 +3780,15 @@ async def health_proxy(request: Request):
|
|||
return JSONResponse(content=response_payload, status_code=http_status)
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# 27. SSE route for usage broadcasts
|
||||
# 27. Hostname endpoint
|
||||
# -------------------------------------------------------------
|
||||
@app.get("/api/hostname")
|
||||
async def get_hostname():
|
||||
"""Return the hostname of the machine running the router."""
|
||||
return JSONResponse(content={"hostname": socket.gethostname()})
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# 28. SSE route for usage broadcasts
|
||||
# -------------------------------------------------------------
|
||||
@app.get("/api/usage-stream")
|
||||
async def usage_stream(request: Request):
|
||||
|
|
|
|||
|
|
@ -344,6 +344,7 @@
|
|||
</div>
|
||||
<div class="header-row">
|
||||
<h1>Router Dashboard</h1>
|
||||
<span id="hostname" style="color:#777; font-size:0.85em;"></span>
|
||||
<button id="total-tokens-btn">Stats Total</button>
|
||||
<span id="aggregation-status" class="loading" style="margin-left:8px;"></span>
|
||||
</div>
|
||||
|
|
@ -1418,6 +1419,11 @@ function initStatsChart(timeSeriesData, endpointDistribution) {
|
|||
</script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
authedFetch('/api/hostname').then(r => r.json()).then(data => {
|
||||
const el = document.getElementById('hostname');
|
||||
if (el && data.hostname) el.textContent = data.hostname;
|
||||
}).catch(() => {});
|
||||
|
||||
const totalBtn = document.getElementById('total-tokens-btn');
|
||||
if (totalBtn) {
|
||||
totalBtn.addEventListener('click', async () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue