This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user