High-performance implementation of plcbundle written in Rust

feat(server): add random DID sampling endpoint

Implement new /random endpoint to sample random DIDs with configurable count and seed parameters. The endpoint returns JSON response containing sampled DIDs, count and seed used for reproducibility.

+68 -1
+60
src/server/handle_random.rs
··· 1 + use crate::server::ServerState; 2 + use crate::server::error::{bad_request, internal_error, task_join_error}; 3 + use axum::{ 4 + extract::{Query, State}, 5 + http::StatusCode, 6 + response::IntoResponse, 7 + }; 8 + use serde::Deserialize; 9 + use serde_json::json; 10 + use std::sync::Arc; 11 + use std::time::{SystemTime, UNIX_EPOCH}; 12 + 13 + #[derive(Deserialize)] 14 + pub struct RandomQuery { 15 + pub count: Option<usize>, 16 + pub seed: Option<u64>, 17 + } 18 + 19 + pub async fn handle_random_dids( 20 + State(state): State<ServerState>, 21 + Query(params): Query<RandomQuery>, 22 + ) -> impl IntoResponse { 23 + let count = params.count.unwrap_or(10); 24 + if count > 1000 { 25 + return bad_request("count must be <= 1000").into_response(); 26 + } 27 + let effective_seed = params 28 + .seed 29 + .unwrap_or_else(|| { 30 + SystemTime::now() 31 + .duration_since(UNIX_EPOCH) 32 + .unwrap() 33 + .as_nanos() as u64 34 + }); 35 + if count == 0 { 36 + return ( 37 + StatusCode::OK, 38 + axum::Json(json!({ "dids": [], "count": 0, "seed": effective_seed })), 39 + ) 40 + .into_response(); 41 + } 42 + 43 + let dids = match tokio::task::spawn_blocking({ 44 + let manager = Arc::clone(&state.manager); 45 + move || manager.sample_random_dids(count, Some(effective_seed)) 46 + }) 47 + .await 48 + { 49 + Ok(Ok(list)) => list, 50 + Ok(Err(e)) => return internal_error(&e.to_string()).into_response(), 51 + Err(e) => return task_join_error(e).into_response(), 52 + }; 53 + 54 + (StatusCode::OK, axum::Json(json!({ 55 + "dids": dids, 56 + "count": count, 57 + "seed": effective_seed 58 + }))) 59 + .into_response() 60 + }
+2
src/server/handle_root.rs
··· 203 203 response.push_str(" GET /op/:pointer Get single operation\n"); 204 204 response.push_str(" GET /status Server status\n"); 205 205 response.push_str(" GET /mempool Mempool operations (JSONL)\n"); 206 + response.push_str(" GET /random Random DID sample (JSON)\n"); 206 207 207 208 if state.config.enable_websocket { 208 209 response.push_str("\nWebSocket Endpoints\n"); ··· 229 230 )); 230 231 response.push_str(&format!(" curl {}/jsonl/1\n", base_url)); 231 232 response.push_str(&format!(" curl {}/op/0\n", base_url)); 233 + response.push_str(&format!(" curl {}/random?count=10&seed=12345\n", base_url)); 232 234 233 235 if state.config.sync_mode { 234 236 response.push_str(&format!(" curl {}/status\n", base_url));
+4
src/server/mod.rs
··· 12 12 #[cfg(feature = "server")] 13 13 mod handle_did; 14 14 #[cfg(feature = "server")] 15 + mod handle_random; 16 + #[cfg(feature = "server")] 15 17 mod handle_root; 16 18 #[cfg(feature = "server")] 17 19 mod handle_status; ··· 86 88 pub use handle_debug::*; 87 89 #[cfg(feature = "server")] 88 90 pub use handle_did::*; 91 + #[cfg(feature = "server")] 92 + pub use handle_random::*; 89 93 #[cfg(feature = "server")] 90 94 pub use handle_root::*; 91 95 #[cfg(feature = "server")]
+2 -1
src/server/routes.rs
··· 6 6 use crate::server::{ 7 7 handle_bundle, handle_bundle_data, handle_bundle_jsonl, handle_debug_didindex, 8 8 handle_debug_memory, handle_debug_resolver, handle_did_routing_guard, handle_index_json, 9 - handle_mempool, handle_operation, handle_root, handle_status, 9 + handle_mempool, handle_operation, handle_random_dids, handle_root, handle_status, 10 10 }; 11 11 use axum::Router; 12 12 use std::sync::Arc; ··· 28 28 .route("/op/{pointer}", axum::routing::get(handle_operation)) 29 29 .route("/status", axum::routing::get(handle_status)) 30 30 .route("/mempool", axum::routing::get(handle_mempool)) 31 + .route("/random", axum::routing::get(handle_random_dids)) 31 32 .route("/debug/memory", axum::routing::get(handle_debug_memory)) 32 33 .route("/debug/didindex", axum::routing::get(handle_debug_didindex)) 33 34 .route("/debug/resolver", axum::routing::get(handle_debug_resolver));