1use axum::{routing::get, Router};
2use tower_http::request_id::{MakeRequestUuid, PropagateRequestIdLayer, SetRequestIdLayer};
3use tower_http::trace::TraceLayer;
4
5use crate::http::handlers::*;
6use crate::http::middleware::rate_limit_middleware;
7use crate::http::state::SharedState;
8use crate::http::ws::ws_handler;
9
10fn build_base_routes() -> Router<SharedState> {
11 Router::new()
12 .route("/agents", get(list_agents).post(register_agent))
13 .route(
14 "/agents/{agent_id}",
15 get(get_agent).delete(disconnect_agent),
16 )
17 .route(
18 "/agents/{agent_id}/retire",
19 axum::routing::post(retire_agent),
20 )
21 .route("/agents/{agent_id}/messages/pending", get(pending_messages))
22 .route("/messages", get(poll_messages).post(send_message))
23 .route("/messages/{message_id}", get(get_message))
24 .route(
25 "/messages/{message_id}/ack",
26 axum::routing::post(ack_message),
27 )
28 .route("/agents/{agent_id}/circuit", get(get_circuit))
29 .route(
30 "/agents/{agent_id}/circuit/failure",
31 axum::routing::post(record_circuit_failure),
32 )
33 .route("/health", get(health))
34 .route("/stats", get(stats))
35 .route("/heartbeat", axum::routing::post(heartbeat))
36 .route("/dependencies", axum::routing::post(create_dependency))
37 .route("/dependencies/blocker/{agent_id}", get(get_blocker_deps))
38 .route(
39 "/dependencies/dependent/{agent_id}",
40 get(get_dependent_deps),
41 )
42 .route(
43 "/dependencies/{dep_id}/resolve",
44 axum::routing::post(resolve_dependency),
45 )
46 .route(
47 "/nudge-config",
48 get(get_nudge_config).post(update_nudge_config),
49 )
50 .route("/events/hook", axum::routing::post(ingest_hook_event))
51 .route("/events/gate", axum::routing::post(ingest_gate_event))
52 .route("/events/ci", axum::routing::post(ingest_ci_event))
53 .route("/events/doc", axum::routing::post(ingest_doc_event))
54 .route("/events/verify", axum::routing::post(ingest_verify_event))
55 .route("/events", get(query_events))
56 .route("/audit", get(query_audit))
57 .route("/tasks/propose", axum::routing::post(propose_task))
58 .route("/tasks/claim-next", axum::routing::post(claim_next_task))
59 .route("/tasks/{id}/claim", axum::routing::post(claim_task))
60 .route("/tasks/{id}/state", axum::routing::post(update_task_state))
61 .route("/tasks/{id}/audit", get(query_task_audit))
62 .route("/tasks/{id}", get(get_task))
63 .route("/tasks", get(list_tasks))
64 .route("/subscriptions", axum::routing::post(subscribe_agent))
65 .route(
66 "/subscriptions/{agent_id}/{project}",
67 axum::routing::delete(unsubscribe_agent),
68 )
69 .route("/subscriptions/{agent_id}", get(list_subscriptions))
70 .route(
71 "/projects/{name}/config",
72 get(get_project_config).post(set_project_config),
73 )
74 .route("/ws/{agent_id}", get(ws_handler))
75 .route("/metrics", get(crate::metrics::metrics_endpoint))
76}
77
78#[cfg(feature = "atheneum")]
79fn add_atheneum_routes(routes: Router<SharedState>) -> Router<SharedState> {
80 crate::atheneum_bridge::add_atheneum_routes(routes)
81}
82
83pub fn build_router(state: SharedState) -> Router {
85 let routes = build_base_routes();
86
87 #[cfg(feature = "atheneum")]
88 let routes = add_atheneum_routes(routes);
89
90 routes
91 .with_state(state.clone())
92 .layer(axum::extract::DefaultBodyLimit::max(1_048_576))
93 .layer(axum::middleware::from_fn_with_state(
94 state,
95 rate_limit_middleware,
96 ))
97 .layer(TraceLayer::new_for_http())
98 .layer(PropagateRequestIdLayer::x_request_id())
99 .layer(SetRequestIdLayer::x_request_id(MakeRequestUuid))
100 .layer(axum::middleware::from_fn(
101 crate::metrics::metrics_middleware,
102 ))
103}
104
105pub fn build_router_unlimited(state: SharedState) -> Router {
107 let routes = build_base_routes();
108
109 #[cfg(feature = "atheneum")]
110 let routes = add_atheneum_routes(routes);
111
112 routes.with_state(state)
113}