···2828| :--- | :--- | :--- |
2929| `DATABASE_PATH` | `./hydrant.db` | path to the database folder. |
3030| `RUST_LOG` | `info` | log filter directives (e.g., `debug`, `hydrant=trace`). standard [`tracing` env-filter syntax](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html). |
3131-| `RELAY_HOST` | `wss://relay.fire.hose.cam` | websocket URL of the upstream firehose relay. |
3131+| `RELAY_HOST` | `http://relay.fire.hose.cam` | URL of the relay. |
3232+| `RELAY_HOSTS` | | comma-separated list of relay URLs. if unset, falls back to `RELAY_HOST`. |
3233| `PLC_URL` | `https://plc.wtf` | base URL(s) of the PLC directory (comma-separated for multiple). |
3334| `FULL_NETWORK` | `false` | if `true`, discovers and indexes all repositories in the network. |
3435| `FILTER_SIGNALS` | | comma-separated list of NSID patterns to use for the filter on startup (e.g. `app.bsky.feed.post,app.bsky.graph.*`). |
···5152| `ENABLE_CRAWLER` | `false` (if Filter), `true` (if Full) | whether to actively query the network for unknown repositories. |
5253| `CRAWLER_MAX_PENDING_REPOS` | `2000` | max pending repos for crawler. |
5354| `CRAWLER_RESUME_PENDING_REPOS` | `1000` | resume threshold for crawler pending repos. |
5555+5656+### multi-relay crawling
5757+5858+the crawler supports querying multiple relays simultaneously. when `RELAY_HOSTS` is configured with multiple URLs:
5959+6060+- one independent crawling loop is spawned per relay
6161+- each relay maintains its own cursor state
6262+- all crawlers share the same pending queue for backfill
6363+- firehose connection uses the first relay in the list
54645565## api
5666
+7-4
src/api/debug.rs
···361361 let cids = tokio::task::spawn_blocking(move || {
362362 let mut unique_cids: std::collections::HashSet<String> = std::collections::HashSet::new();
363363 let db = &state_clone.db;
364364-364364+365365 // 1. Scan records
366366 let records_prefix = crate::db::keys::record_prefix_did(&did);
367367 for guard in db.records.prefix(&records_prefix) {
···371371 }
372372 }
373373 }
374374-374374+375375 // 2. Scan events
376376 let trimmed_did = crate::db::types::TrimmedDid::from(&did);
377377 for guard in db.events.iter() {
···385385 }
386386 }
387387 }
388388-388388+389389 let mut counts: std::collections::HashMap<String, i64> = std::collections::HashMap::new();
390390 for cid_str in unique_cids {
391391 if let Ok(cid) = cid::Cid::from_str(&cid_str) {
392392 let cid_bytes = fjall::Slice::from(cid.to_bytes());
393393- let count = db.block_refcounts.read_sync(cid_bytes.as_ref(), |_, v| *v).unwrap_or(0);
393393+ let count = db
394394+ .block_refcounts
395395+ .read_sync(cid_bytes.as_ref(), |_, v| *v)
396396+ .unwrap_or(0);
394397 counts.insert(cid_str, count);
395398 }
396399 }