Skip to main content

clawbox_server/
lib.rs

1#![doc = include_str!("../README.md")]
2
3pub mod auth;
4pub mod config;
5#[cfg(feature = "docker")]
6pub mod container_proxy;
7pub mod metrics;
8pub mod proxy_handler;
9pub mod routes;
10pub mod state;
11
12pub use config::{ClawboxConfig, ImageTemplate, ImagesConfig, ToolsConfig};
13pub use state::AppState;
14
15use axum::{Router, extract::DefaultBodyLimit, middleware};
16use std::sync::Arc;
17use tower::limit::ConcurrencyLimitLayer;
18use tower_http::trace::TraceLayer;
19
20/// Build the axum router with all routes.
21pub fn build_router(state: Arc<AppState>) -> Router {
22    // Health and metrics are public (no auth)
23    let public = Router::new()
24        .merge(routes::health::router())
25        .merge(routes::metrics::router());
26
27    // Protected routes require auth, with concurrency limit
28    let protected = {
29        let r = Router::new()
30            .merge(routes::execute::router())
31            .merge(routes::tools::router());
32
33        #[cfg(feature = "docker")]
34        let r = r
35            .merge(routes::containers::router())
36            .merge(routes::agents::router());
37
38        r
39    };
40
41    let protected = protected
42        .layer(DefaultBodyLimit::max(10 * 1024 * 1024))
43        .layer(middleware::from_fn_with_state(
44            state.clone(),
45            auth::require_auth,
46        ))
47        .layer(ConcurrencyLimitLayer::new(
48            state.config.server.max_concurrent_executions,
49        ));
50
51    public
52        .merge(protected)
53        .with_state(state)
54        .layer(TraceLayer::new_for_http())
55}
56
57/// Spawn a Unix domain socket listener serving the same router.
58#[cfg(unix)]
59pub async fn spawn_unix_listener(socket_path: &str, app: Router) -> std::io::Result<()> {
60    use tokio::net::UnixListener;
61
62    let _ = std::fs::remove_file(socket_path);
63    let uds = UnixListener::bind(socket_path)?;
64
65    {
66        use std::os::unix::fs::PermissionsExt;
67        std::fs::set_permissions(socket_path, std::fs::Permissions::from_mode(0o600))?;
68    }
69
70    tracing::info!(path = socket_path, "Unix socket listener started");
71
72    tokio::spawn(async move {
73        axum::serve(uds, app).await.ok();
74    });
75
76    Ok(())
77}