feat: universal LLM gateway with embedded multilingual admin console
- OpenAI-compatible gateway with intelligent routing via cortiq-router (allaigate) - Embedded build-free admin SPA at /admin: 7 languages (en/ru/de/fr/es/zh/tr), light/dark themes, hot config reload (no restart) - Admin API, per-request statistics + Prometheus /metrics, secret store, playground - English documentation (primary) with Russian translations (*.ru.md) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
//! Embedded static assets for the admin panel (SPA). The `web/` directory is compiled
|
||||
//! into the binary via `rust-embed`, so the gateway remains a single self-contained file.
|
||||
//!
|
||||
//! Served as the main router's fallback: everything under `/admin/*` not matched by
|
||||
//! an explicit route is served as a file; an unknown path under `/admin` falls back to
|
||||
//! `index.html` (the client-side hash router handles navigation).
|
||||
|
||||
use axum::{
|
||||
http::{header, StatusCode, Uri},
|
||||
response::{IntoResponse, Response},
|
||||
};
|
||||
use rust_embed::RustEmbed;
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "web/"]
|
||||
struct WebAssets;
|
||||
|
||||
fn serve_file(path: &str) -> Response {
|
||||
match WebAssets::get(path) {
|
||||
Some(content) => {
|
||||
let mime = mime_guess::from_path(path).first_or_octet_stream();
|
||||
(
|
||||
[(header::CONTENT_TYPE, mime.as_ref())],
|
||||
content.data.into_owned(),
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
None => {
|
||||
// SPA: unknown path under /admin → serve index.html
|
||||
match WebAssets::get("index.html") {
|
||||
Some(content) => (
|
||||
[(header::CONTENT_TYPE, "text/html; charset=utf-8")],
|
||||
content.data.into_owned(),
|
||||
)
|
||||
.into_response(),
|
||||
None => (StatusCode::NOT_FOUND, "not found").into_response(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Application-wide fallback: serves `/admin/*`; everything else → 404 JSON.
|
||||
pub async fn fallback(uri: Uri) -> Response {
|
||||
let path = uri.path();
|
||||
if let Some(rest) = path.strip_prefix("/admin") {
|
||||
let rest = rest.trim_start_matches('/');
|
||||
let file = if rest.is_empty() { "index.html" } else { rest };
|
||||
serve_file(file)
|
||||
} else {
|
||||
(
|
||||
StatusCode::NOT_FOUND,
|
||||
axum::Json(serde_json::json!({
|
||||
"error": { "message": "not found", "type": "not_found", "code": "not_found" }
|
||||
})),
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user