|
@@ -4,11 +4,24 @@ use crate::db::{Database, Fortune};
|
|
use futures::stream::futures_unordered::FuturesUnordered;
|
|
use futures::stream::futures_unordered::FuturesUnordered;
|
|
use futures::{FutureExt, StreamExt};
|
|
use futures::{FutureExt, StreamExt};
|
|
use rand::distributions::{Distribution, Uniform};
|
|
use rand::distributions::{Distribution, Uniform};
|
|
|
|
+use rand::rngs::SmallRng;
|
|
|
|
+use rand::SeedableRng;
|
|
use serde::Serialize;
|
|
use serde::Serialize;
|
|
|
|
+use std::cell::RefCell;
|
|
use warp::http::header;
|
|
use warp::http::header;
|
|
use warp::{Filter, Rejection, Reply};
|
|
use warp::{Filter, Rejection, Reply};
|
|
use yarte::Template;
|
|
use yarte::Template;
|
|
|
|
|
|
|
|
+// SmallRng is not a CSPRNG. It's used specifically to match performance of
|
|
|
|
+// benchmarks in other programming languages where the default RNG algorithm
|
|
|
|
+// is not a CSPRNG. Most Rust programs will likely want to use
|
|
|
|
+// rand::thread_rng instead which is more convenient to use and safer.
|
|
|
|
+thread_local!(static RNG: RefCell<SmallRng> = RefCell::new(SmallRng::from_entropy()));
|
|
|
|
+
|
|
|
|
+fn with_rng<T>(f: impl FnOnce(&mut SmallRng) -> T) -> T {
|
|
|
|
+ RNG.with(|rng| f(&mut rng.borrow_mut()))
|
|
|
|
+}
|
|
|
|
+
|
|
#[derive(Serialize)]
|
|
#[derive(Serialize)]
|
|
struct Message {
|
|
struct Message {
|
|
message: &'static str,
|
|
message: &'static str,
|
|
@@ -29,7 +42,7 @@ fn plaintext() -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
|
|
fn db(database: &'static Database) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
|
|
fn db(database: &'static Database) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
|
|
let between = Uniform::from(1..=10_000);
|
|
let between = Uniform::from(1..=10_000);
|
|
warp::path!("db").and_then(move || async move {
|
|
warp::path!("db").and_then(move || async move {
|
|
- let id = between.sample(&mut rand::thread_rng());
|
|
|
|
|
|
+ let id = with_rng(|rng| between.sample(rng));
|
|
let world = database.get_world_by_id(id).await;
|
|
let world = database.get_world_by_id(id).await;
|
|
Ok::<_, Rejection>(warp::reply::json(&world))
|
|
Ok::<_, Rejection>(warp::reply::json(&world))
|
|
})
|
|
})
|
|
@@ -43,12 +56,13 @@ fn queries(
|
|
warp::path!("queries" / ..)
|
|
warp::path!("queries" / ..)
|
|
.and(clamped.or(warp::any().map(|| 1)).unify())
|
|
.and(clamped.or(warp::any().map(|| 1)).unify())
|
|
.and_then(move |queries| {
|
|
.and_then(move |queries| {
|
|
- let mut rng = rand::thread_rng();
|
|
|
|
- (0..queries)
|
|
|
|
- .map(|_| database.get_world_by_id(between.sample(&mut rng)))
|
|
|
|
- .collect::<FuturesUnordered<_>>()
|
|
|
|
- .collect::<Vec<_>>()
|
|
|
|
- .map(|worlds| Ok::<_, Rejection>(warp::reply::json(&worlds)))
|
|
|
|
|
|
+ with_rng(|rng| {
|
|
|
|
+ (0..queries)
|
|
|
|
+ .map(|_| database.get_world_by_id(between.sample(rng)))
|
|
|
|
+ .collect::<FuturesUnordered<_>>()
|
|
|
|
+ .collect::<Vec<_>>()
|
|
|
|
+ .map(|worlds| Ok::<_, Rejection>(warp::reply::json(&worlds)))
|
|
|
|
+ })
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
|