|
@@ -1,31 +1,31 @@
|
|
|
+mod common;
|
|
|
+mod pg_pool;
|
|
|
+
|
|
|
use axum::{
|
|
|
- extract::Query,
|
|
|
- http::{header, HeaderValue, StatusCode},
|
|
|
- response::IntoResponse,
|
|
|
- routing::get,
|
|
|
- Json, Router,
|
|
|
+ extract::Query, http::StatusCode, response::IntoResponse, routing::get, Router,
|
|
|
};
|
|
|
+
|
|
|
+#[cfg(not(feature = "simd-json"))]
|
|
|
+use axum::Json;
|
|
|
+#[cfg(feature = "simd-json")]
|
|
|
+use common::simd_json::Json;
|
|
|
+
|
|
|
+use common::{random_ids, SELECT_ALL_FORTUNES, SELECT_WORLD_BY_ID, UPDATE_WORLDS};
|
|
|
use dotenv::dotenv;
|
|
|
use futures_util::{stream::FuturesUnordered, TryStreamExt};
|
|
|
-use rand::{rngs::SmallRng, thread_rng, Rng, SeedableRng};
|
|
|
-use tower_http::set_header::SetResponseHeaderLayer;
|
|
|
+use rand::{rngs::SmallRng, thread_rng, SeedableRng};
|
|
|
use yarte::Template;
|
|
|
|
|
|
-mod database_pg_pool;
|
|
|
-mod models_common;
|
|
|
-mod models_pg_pool;
|
|
|
mod server;
|
|
|
-mod utils;
|
|
|
-
|
|
|
-use self::{
|
|
|
- database_pg_pool::{
|
|
|
- create_pool, fetch_all_fortunes, fetch_world_by_id,
|
|
|
- prepare_fetch_all_fortunes_statement, prepare_fetch_world_by_id_statement,
|
|
|
- prepare_update_world_by_id_statement, update_world, DatabaseClient, PgError,
|
|
|
- },
|
|
|
- models_pg_pool::{Fortune, World},
|
|
|
- utils::{get_environment_variable, parse_params, random_number, Params, Utf8Html},
|
|
|
+
|
|
|
+use common::{
|
|
|
+ get_env, random_id,
|
|
|
+ utils::{parse_params, Params, Utf8Html},
|
|
|
};
|
|
|
+use pg_pool::database::{
|
|
|
+ create_pool, fetch_all_fortunes, fetch_world_by_id, DatabaseClient, PgError,
|
|
|
+};
|
|
|
+use pg_pool::models::{Fortune, World};
|
|
|
|
|
|
#[derive(Template)]
|
|
|
#[template(path = "fortunes.html.hbs")]
|
|
@@ -35,11 +35,10 @@ pub struct FortunesTemplate<'a> {
|
|
|
|
|
|
async fn db(DatabaseClient(client): DatabaseClient) -> impl IntoResponse {
|
|
|
let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
|
|
|
+ let random_id = random_id(&mut rng);
|
|
|
|
|
|
- let random_id = (rng.gen::<u32>() % 10_000 + 1) as i32;
|
|
|
-
|
|
|
- let select = prepare_fetch_world_by_id_statement(&client).await;
|
|
|
- let world = fetch_world_by_id(&client, random_id, &select)
|
|
|
+ let select = &client.prepare_cached(SELECT_WORLD_BY_ID).await.unwrap();
|
|
|
+ let world = fetch_world_by_id(&client, random_id, select)
|
|
|
.await
|
|
|
.expect("could not fetch world");
|
|
|
|
|
@@ -53,15 +52,11 @@ async fn queries(
|
|
|
let q = parse_params(params);
|
|
|
|
|
|
let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
|
|
|
-
|
|
|
- let select = prepare_fetch_world_by_id_statement(&client).await;
|
|
|
-
|
|
|
+ let select = &client.prepare_cached(SELECT_WORLD_BY_ID).await.unwrap();
|
|
|
let future_worlds = FuturesUnordered::new();
|
|
|
|
|
|
- for _ in 0..q {
|
|
|
- let w_id = (rng.gen::<u32>() % 10_000 + 1) as i32;
|
|
|
-
|
|
|
- future_worlds.push(fetch_world_by_id(&client, w_id, &select));
|
|
|
+ for id in random_ids(&mut rng, q) {
|
|
|
+ future_worlds.push(fetch_world_by_id(&client, id, select));
|
|
|
}
|
|
|
|
|
|
let worlds: Result<Vec<World>, PgError> = future_worlds.try_collect().await;
|
|
@@ -71,9 +66,9 @@ async fn queries(
|
|
|
}
|
|
|
|
|
|
async fn fortunes(DatabaseClient(client): DatabaseClient) -> impl IntoResponse {
|
|
|
- let select = prepare_fetch_all_fortunes_statement(&client).await;
|
|
|
+ let select = &client.prepare_cached(SELECT_ALL_FORTUNES).await.unwrap();
|
|
|
|
|
|
- let mut fortunes = fetch_all_fortunes(client, &select)
|
|
|
+ let mut fortunes = fetch_all_fortunes(client, select)
|
|
|
.await
|
|
|
.expect("could not fetch fortunes");
|
|
|
|
|
@@ -100,66 +95,49 @@ async fn updates(
|
|
|
let q = parse_params(params);
|
|
|
|
|
|
let mut rng = SmallRng::from_entropy();
|
|
|
+ let select = &client.prepare_cached(SELECT_WORLD_BY_ID).await.unwrap();
|
|
|
+ let update = &client.prepare_cached(UPDATE_WORLDS).await.unwrap();
|
|
|
|
|
|
- let select = prepare_fetch_world_by_id_statement(&client).await;
|
|
|
-
|
|
|
+ // Select the random worlds.
|
|
|
let future_worlds = FuturesUnordered::new();
|
|
|
-
|
|
|
- for _ in 0..q {
|
|
|
- let query_id = random_number(&mut rng);
|
|
|
-
|
|
|
- future_worlds.push(fetch_world_by_id(&client, query_id, &select));
|
|
|
+ for id in random_ids(&mut rng, q) {
|
|
|
+ future_worlds.push(fetch_world_by_id(&client, id, select));
|
|
|
}
|
|
|
-
|
|
|
- let worlds: Result<Vec<World>, PgError> = future_worlds.try_collect().await;
|
|
|
- let results = worlds.expect("worlds could not be retrieved");
|
|
|
-
|
|
|
- let update = prepare_update_world_by_id_statement(&client).await;
|
|
|
-
|
|
|
- let future_world_updates = FuturesUnordered::new();
|
|
|
-
|
|
|
- for w in &results {
|
|
|
- let random_id = random_number(&mut rng);
|
|
|
- let w_id = w.id;
|
|
|
-
|
|
|
- future_world_updates.push(update_world(&client, &update, random_id, w_id));
|
|
|
- }
|
|
|
-
|
|
|
- let world_updates: Result<Vec<u64>, PgError> =
|
|
|
- future_world_updates.try_collect().await;
|
|
|
- world_updates.expect("updates could not be executed");
|
|
|
-
|
|
|
- (StatusCode::OK, Json(results))
|
|
|
+ let worlds: Vec<World> = future_worlds.try_collect().await.unwrap();
|
|
|
+
|
|
|
+ let mut ids = Vec::with_capacity(q);
|
|
|
+ let mut nids = Vec::with_capacity(q);
|
|
|
+ let worlds: Vec<World> = worlds
|
|
|
+ .into_iter()
|
|
|
+ .map(|mut w| {
|
|
|
+ w.randomnumber = random_id(&mut rng);
|
|
|
+ ids.push(w.id);
|
|
|
+ nids.push(w.randomnumber);
|
|
|
+ w
|
|
|
+ })
|
|
|
+ .collect();
|
|
|
+
|
|
|
+ // Update the random worlds in the database.
|
|
|
+ client.execute(update, &[&ids, &nids]).await.unwrap();
|
|
|
+
|
|
|
+ (StatusCode::OK, Json(worlds))
|
|
|
}
|
|
|
|
|
|
#[tokio::main]
|
|
|
async fn main() {
|
|
|
dotenv().ok();
|
|
|
|
|
|
- serve().await;
|
|
|
-}
|
|
|
-
|
|
|
-async fn serve() {
|
|
|
- let database_url: String = get_environment_variable("AXUM_TECHEMPOWER_DATABASE_URL");
|
|
|
- let max_pool_size: u32 = get_environment_variable("AXUM_TECHEMPOWER_MAX_POOL_SIZE");
|
|
|
+ let database_url: String = get_env("POSTGRES_URL");
|
|
|
+ let max_pool_size: u32 = get_env("POSTGRES_MAX_POOL_SIZE");
|
|
|
|
|
|
- // setup Client pool
|
|
|
let pool = create_pool(database_url, max_pool_size).await;
|
|
|
- let server_header_value = HeaderValue::from_static("Axum");
|
|
|
|
|
|
- let router = Router::new()
|
|
|
+ let app = Router::new()
|
|
|
.route("/fortunes", get(fortunes))
|
|
|
.route("/db", get(db))
|
|
|
.route("/queries", get(queries))
|
|
|
.route("/updates", get(updates))
|
|
|
- .with_state(pool)
|
|
|
- .layer(SetResponseHeaderLayer::if_not_present(
|
|
|
- header::SERVER,
|
|
|
- server_header_value,
|
|
|
- ));
|
|
|
-
|
|
|
- server::builder()
|
|
|
- .serve(router.into_make_service())
|
|
|
- .await
|
|
|
- .unwrap();
|
|
|
+ .with_state(pool);
|
|
|
+
|
|
|
+ server::serve_hyper(app, Some(8000)).await
|
|
|
}
|