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
20pub fn build_router(state: Arc<AppState>) -> Router {
22 let public = Router::new()
24 .merge(routes::health::router())
25 .merge(routes::metrics::router());
26
27 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#[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}