very fast at protocol indexer with flexible filtering, xrpc queries, cursor-backed event stream, and more, built on fjall
rust
fjall
at-protocol
atproto
indexer
1use crate::control::Hydrant;
2use crate::state::AppState;
3use axum::{Router, routing::get};
4use std::{net::SocketAddr, sync::Arc};
5use tower_http::cors::CorsLayer;
6use tower_http::trace::TraceLayer;
7
8mod crawler;
9mod db;
10mod debug;
11mod filter;
12mod firehose;
13mod ingestion;
14mod repos;
15mod stats;
16mod stream;
17mod xrpc;
18
19pub async fn serve(hydrant: Hydrant, port: u16) -> miette::Result<()> {
20 #[allow(unused_mut)]
21 let mut app = Router::new()
22 .route("/health", get(|| async { "OK" }))
23 .route("/stats", get(stats::get_stats))
24 .nest("/stream", stream::router())
25 .merge(xrpc::router())
26 .merge(filter::router())
27 .merge(repos::router())
28 .merge(ingestion::router())
29 .merge(crawler::router())
30 .merge(firehose::router())
31 .merge(db::router());
32
33 #[cfg(feature = "backlinks")]
34 {
35 app = app.merge(crate::backlinks::api::router());
36 }
37
38 let app = app
39 .with_state(hydrant)
40 .layer(TraceLayer::new_for_http())
41 .layer(CorsLayer::permissive());
42
43 let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{port}"))
44 .await
45 .map_err(|e| miette::miette!("failed to bind to port {port}: {e}"))?;
46
47 tracing::info!("API server listening on {}", listener.local_addr().unwrap());
48
49 axum::serve(
50 listener,
51 app.into_make_service_with_connect_info::<SocketAddr>(),
52 )
53 .await
54 .map_err(|e| miette::miette!("axum server error: {e}"))?;
55
56 Ok(())
57}
58
59pub async fn serve_debug(state: Arc<AppState>, port: u16) -> miette::Result<()> {
60 let app = debug::router()
61 .with_state(state)
62 .layer(TraceLayer::new_for_http());
63
64 let listener = tokio::net::TcpListener::bind(format!("127.0.0.1:{port}"))
65 .await
66 .map_err(|e| miette::miette!("failed to bind debug server to port {port}: {e}"))?;
67
68 tracing::info!(
69 "debug server listening on {}",
70 listener.local_addr().unwrap()
71 );
72
73 axum::serve(
74 listener,
75 app.into_make_service_with_connect_info::<SocketAddr>(),
76 )
77 .await
78 .map_err(|e| miette::miette!("debug server error: {e}"))?;
79
80 Ok(())
81}