b4tman/qchgk_web#1 using moka
This commit is contained in:
57
src/main.rs
57
src/main.rs
@@ -15,11 +15,15 @@ use rocket_contrib::templates::Template;
|
||||
use rand::distributions::Uniform;
|
||||
use rand::Rng;
|
||||
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
use chgk_ledb_lib::db;
|
||||
use chgk_ledb_lib::questions::Question;
|
||||
|
||||
use moka::sync::Cache;
|
||||
use std::time::Duration;
|
||||
|
||||
const DB_FILENAME: &str = "db.dat";
|
||||
|
||||
trait ErrorEmpty {
|
||||
@@ -34,9 +38,27 @@ impl<T, E> ErrorEmpty for Result<T, E> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ArcTemplateData {
|
||||
value: Arc<serde_json::Value>,
|
||||
}
|
||||
|
||||
impl ArcTemplateData {
|
||||
fn new(value: serde_json::Value) -> ArcTemplateData {
|
||||
ArcTemplateData {
|
||||
value: Arc::new(value),
|
||||
}
|
||||
}
|
||||
fn render(&self, name: &'static str) -> Template {
|
||||
Template::render(name, self.value.deref())
|
||||
}
|
||||
}
|
||||
|
||||
type TemplateCache = moka::sync::Cache<usize, ArcTemplateData>;
|
||||
|
||||
type DataBaseInner = db::Reader<Question>;
|
||||
type DataBase = Arc<DataBaseInner>;
|
||||
struct AppState{
|
||||
struct AppState {
|
||||
db: DataBase,
|
||||
database_distribution: Uniform<usize>,
|
||||
}
|
||||
@@ -49,7 +71,7 @@ impl From<DataBaseInner> for AppState {
|
||||
|
||||
Self {
|
||||
db,
|
||||
database_distribution
|
||||
database_distribution,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,7 +85,16 @@ fn get_question(db: &DataBase, id: usize) -> Result<Question, ()> {
|
||||
db.get(id - 1).err_empty()
|
||||
}
|
||||
|
||||
fn show_question_details(template_name: &'static str, data: &AppState, id: usize) -> Template {
|
||||
fn show_question_details(
|
||||
template_name: &'static str,
|
||||
data: &AppState,
|
||||
cache: &TemplateCache,
|
||||
id: usize,
|
||||
) -> Template {
|
||||
if let Some(value) = cache.get(&id) {
|
||||
return value.render(template_name);
|
||||
}
|
||||
|
||||
match get_question(&data.db, id) {
|
||||
Ok(question) => {
|
||||
let mut context = serde_json::to_value(question).expect("question serialize");
|
||||
@@ -71,7 +102,12 @@ fn show_question_details(template_name: &'static str, data: &AppState, id: usize
|
||||
let next_id = random_question_id(&data.database_distribution);
|
||||
context["next"] = serde_json::to_value(next_id).expect("question id serialize");
|
||||
}
|
||||
Template::render(template_name, &context)
|
||||
|
||||
let value = ArcTemplateData::new(context);
|
||||
let result = value.render(template_name);
|
||||
cache.insert(id, value);
|
||||
|
||||
result
|
||||
}
|
||||
Err(_) => {
|
||||
use std::collections::HashMap;
|
||||
@@ -82,13 +118,13 @@ fn show_question_details(template_name: &'static str, data: &AppState, id: usize
|
||||
}
|
||||
|
||||
#[get("/q/<id>")]
|
||||
fn show_question(data: State<AppState>, id: usize) -> Template {
|
||||
show_question_details("question", data.inner(), id)
|
||||
fn show_question(data: State<AppState>, cache: State<TemplateCache>, id: usize) -> Template {
|
||||
show_question_details("question", data.inner(), cache.inner(), id)
|
||||
}
|
||||
|
||||
#[get("/q/<id>/a")]
|
||||
fn show_answer(data: State<AppState>, id: usize) -> Template {
|
||||
show_question_details("answer", data.inner(), id)
|
||||
fn show_answer(data: State<AppState>, cache: State<TemplateCache>, id: usize) -> Template {
|
||||
show_question_details("answer", data.inner(), cache.inner(), id)
|
||||
}
|
||||
|
||||
#[get("/q/0")]
|
||||
@@ -116,9 +152,14 @@ fn not_found(_req: &rocket::Request) -> Template {
|
||||
|
||||
fn rocket() -> Rocket {
|
||||
let state: AppState = db::Reader::new(DB_FILENAME, 2048).expect("open db").into();
|
||||
let cache: TemplateCache = Cache::builder()
|
||||
.time_to_idle(Duration::from_secs(15 * 60))
|
||||
.max_capacity(300)
|
||||
.build();
|
||||
|
||||
rocket::ignite()
|
||||
.manage(state)
|
||||
.manage(cache)
|
||||
.register(catchers![not_found])
|
||||
.mount(
|
||||
"/",
|
||||
|
Reference in New Issue
Block a user