Use Mutex instead of RwLock and prevent unneeded allocation on answer check
This commit is contained in:
parent
0b9283a69b
commit
db0ad404a1
2 changed files with 39 additions and 24 deletions
|
@ -1,58 +1,71 @@
|
||||||
use std::sync::RwLock;
|
use std::{ops::Deref, sync::Mutex};
|
||||||
|
|
||||||
struct CaptchaSolutions {
|
pub struct CaptchaSolutions {
|
||||||
last_id: u16,
|
last_id: u16,
|
||||||
solutions: Vec<Option<String>>,
|
solutions: Vec<Option<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CaptchaSolutions {
|
impl CaptchaSolutions {
|
||||||
fn get_sol(&self, id: u16) -> &Option<String> {
|
fn get(&self, id: u16) -> &Option<String> {
|
||||||
&self.solutions[id as usize]
|
&self.solutions[id as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_sol(&mut self, id: u16, sol: Option<String>) {
|
fn set(&mut self, id: u16, sol: Option<String>) {
|
||||||
self.solutions[id as usize] = sol;
|
self.solutions[id as usize] = sol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use = "The new id has to be stored for future verification of an answer!"]
|
||||||
|
fn push(&mut self, sol: String) -> u16 {
|
||||||
|
self.last_id = self.last_id.wrapping_add(1);
|
||||||
|
self.set(self.last_id, Some(sol));
|
||||||
|
|
||||||
|
self.last_id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SharedCaptchaSolutions {
|
pub struct SharedCaptchaSolutions {
|
||||||
inner: RwLock<CaptchaSolutions>,
|
inner: Mutex<CaptchaSolutions>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SharedCaptchaSolutions {
|
impl Default for SharedCaptchaSolutions {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let max_size = (u16::MAX as usize) + 1;
|
let max_size = u16::MAX as usize + 1;
|
||||||
let mut solutions = Vec::with_capacity(max_size);
|
|
||||||
solutions.resize(max_size, None);
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
inner: RwLock::new(CaptchaSolutions {
|
inner: Mutex::new(CaptchaSolutions {
|
||||||
last_id: 0,
|
last_id: 0,
|
||||||
solutions,
|
solutions: vec![None; max_size],
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Deref for SharedCaptchaSolutions {
|
||||||
|
type Target = Mutex<CaptchaSolutions>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl SharedCaptchaSolutions {
|
impl SharedCaptchaSolutions {
|
||||||
pub fn store_sol(&self, sol: String) -> u16 {
|
#[must_use = "The new id has to be stored for future verification of an answer!"]
|
||||||
let mut captcha_solutions = self.inner.write().unwrap();
|
pub fn store_solution(&self, sol: String) -> u16 {
|
||||||
|
let mut sols = self.lock().unwrap();
|
||||||
|
|
||||||
let new_id = captcha_solutions.last_id.wrapping_add(1);
|
sols.push(sol)
|
||||||
captcha_solutions.last_id = new_id;
|
|
||||||
|
|
||||||
captcha_solutions.set_sol(new_id, Some(sol));
|
|
||||||
|
|
||||||
new_id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_answer(&self, id: u16, answer: &str) -> bool {
|
pub fn check_answer(&self, id: u16, answer: &str) -> bool {
|
||||||
if *self.inner.read().unwrap().get_sol(id) != Some(answer.trim().to_string()) {
|
let mut sols = self.lock().unwrap();
|
||||||
return false;
|
|
||||||
|
if let Some(sol) = sols.get(id) {
|
||||||
|
if sol == answer.trim() {
|
||||||
|
sols.set(id, None);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.inner.write().unwrap().set_sol(id, None);
|
false
|
||||||
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ pub async fn render_contact_form(params: IndexParams<'_>) -> Result<Response, er
|
||||||
|
|
||||||
let solution = captcha.chars_as_string();
|
let solution = captcha.chars_as_string();
|
||||||
|
|
||||||
let id = params.captcha_solutions.store_sol(solution);
|
let id = params.captcha_solutions.store_solution(solution);
|
||||||
|
|
||||||
let template = templates::ContactForm {
|
let template = templates::ContactForm {
|
||||||
base: templates::Base {
|
base: templates::Base {
|
||||||
|
@ -92,6 +92,7 @@ pub async fn submit(
|
||||||
) -> Result<Response, errors::AppError> {
|
) -> Result<Response, errors::AppError> {
|
||||||
if !captcha_solutions.check_answer(form.id, &form.captcha_answer) {
|
if !captcha_solutions.check_answer(form.id, &form.captcha_answer) {
|
||||||
info!("Wrong CAPTCHA");
|
info!("Wrong CAPTCHA");
|
||||||
|
|
||||||
return failed_submission(
|
return failed_submission(
|
||||||
Arc::clone(&config),
|
Arc::clone(&config),
|
||||||
captcha_solutions,
|
captcha_solutions,
|
||||||
|
@ -105,6 +106,7 @@ pub async fn submit(
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("{e:?}");
|
error!("{e:?}");
|
||||||
|
|
||||||
return failed_submission(
|
return failed_submission(
|
||||||
Arc::clone(&config),
|
Arc::clone(&config),
|
||||||
captcha_solutions,
|
captcha_solutions,
|
||||||
|
|
Loading…
Reference in a new issue