Stage 3: Admin-Router einbinden (AppState, /admin)
CI / test (push) Failing after 5m29s

This commit is contained in:
2026-06-23 21:01:26 +00:00
parent fab77775ff
commit 5f35f1a205
+19 -9
View File
@@ -1,3 +1,5 @@
mod admin;
use std::collections::HashSet;
use std::sync::Arc;
@@ -15,11 +17,12 @@ use dtrack_tools::{shared_client, DtrackServer};
use rmcp::transport::streamable_http_server::{
session::local::LocalSessionManager, StreamableHttpService,
};
use tokio::sync::RwLock;
/// Bearer-Token-Gate fuer den /mcp-Endpoint.
///
/// Stage 2: eine flache Token-Liste aus `DTRACK_HTTP_TOKENS` (kommagetrennt).
/// Multi-Client mit Rechten pro Token folgt in Stage 3 (Permission-Engine).
/// Rechte pro Token (Permission-Engine) folgen spaeter.
#[derive(Clone)]
struct AuthState {
tokens: Arc<HashSet<String>>,
@@ -48,11 +51,7 @@ impl AuthState {
}
}
async fn auth_mw(
State(auth): State<AuthState>,
req: Request,
next: Next,
) -> Result<Response, StatusCode> {
async fn auth_mw(State(auth): State<AuthState>, req: Request, next: Next) -> Result<Response, StatusCode> {
if auth.allow_all {
return Ok(next.run(req).await);
}
@@ -79,9 +78,17 @@ async fn main() -> Result<()> {
let cfg = DtrackConfig::resolve()?;
let client = DtrackClient::from_config(&cfg)?;
// Laufzeit-austauschbarer Client-Handle (Admin-UI kann ihn spaeter neu bauen).
let config_path = std::env::var("DTRACK_CONFIG").ok().map(std::path::PathBuf::from);
// Laufzeit-austauschbarer Client-Handle (Admin-UI baut ihn live neu).
let shared = shared_client(client);
let app_state = admin::AppState {
config: Arc::new(RwLock::new(cfg)),
client: shared.clone(),
config_path,
};
// Pro Session ein frischer DtrackServer; der Handle wird nur geklont (Arc).
let mcp_service = StreamableHttpService::new(
move || Ok(DtrackServer::new(shared.clone())),
@@ -94,15 +101,18 @@ async fn main() -> Result<()> {
.nest_service("/mcp", mcp_service)
.layer(middleware::from_fn_with_state(auth, auth_mw));
let admin_router = admin::router(app_state, admin::AdminAuth::from_env());
let app = Router::new()
.route("/health", get(|| async { "OK" }))
.merge(mcp);
.merge(mcp)
.merge(admin_router);
let addr = std::env::var("DTRACK_HTTP_ADDR").unwrap_or_else(|_| "0.0.0.0:8080".to_string());
let listener = tokio::net::TcpListener::bind(&addr)
.await
.with_context(|| format!("Bind auf {addr} fehlgeschlagen"))?;
tracing::info!("dtrack-http laeuft auf http://{addr}/mcp");
tracing::info!("dtrack-http laeuft auf http://{addr}/mcp (Admin: /admin)");
axum::serve(listener, app)
.with_graceful_shutdown(async {