Use RwLock

This commit is contained in:
Mo 2022-12-28 14:36:30 +01:00
parent adcc18f5a5
commit 7abe487918
2 changed files with 26 additions and 24 deletions

View file

@ -1,12 +1,22 @@
use std::sync::{Arc, Mutex, MutexGuard}; use std::sync::RwLock;
struct CaptchaSolutions { struct CaptchaSolutions {
last_id: u16, last_id: u16,
solutions: Vec<Option<String>>, solutions: Vec<Option<String>>,
} }
impl CaptchaSolutions {
fn get_sol(&self, id: u16) -> &Option<String> {
&self.solutions[id as usize]
}
fn set_sol(&mut self, id: u16, sol: Option<String>) {
self.solutions[id as usize] = sol;
}
}
pub struct SharedCaptchaSolutions { pub struct SharedCaptchaSolutions {
arc: Arc<Mutex<CaptchaSolutions>>, inner: RwLock<CaptchaSolutions>,
} }
impl Default for SharedCaptchaSolutions { impl Default for SharedCaptchaSolutions {
@ -16,42 +26,33 @@ impl Default for SharedCaptchaSolutions {
solutions.resize(max_size, None); solutions.resize(max_size, None);
Self { Self {
arc: Arc::new(Mutex::new(CaptchaSolutions { inner: RwLock::new(CaptchaSolutions {
last_id: 0, last_id: 0,
solutions, solutions,
})), }),
} }
} }
} }
impl SharedCaptchaSolutions { impl SharedCaptchaSolutions {
fn lock(&self) -> MutexGuard<CaptchaSolutions> { pub fn store_sol(&self, sol: String) -> u16 {
self.arc.lock().unwrap() let mut captcha_solutions = self.inner.write().unwrap();
}
pub fn store_solution(&self, solution: &str) -> u16 {
let mut captcha_solutions = self.lock();
let new_id = captcha_solutions.last_id.wrapping_add(1); let new_id = captcha_solutions.last_id.wrapping_add(1);
captcha_solutions.last_id = new_id; captcha_solutions.last_id = new_id;
captcha_solutions.solutions[new_id as usize] = Some(solution.to_string()); captcha_solutions.set_sol(new_id, Some(sol));
new_id 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 captcha_solutions = self.lock(); return false;
let id = id as usize;
if captcha_solutions.solutions[id] == Some(answer.trim().to_string()) {
captcha_solutions.solutions[id] = None;
return true;
}
} }
false self.inner.write().unwrap().set_sol(id, None);
true
} }
} }

View file

@ -24,6 +24,7 @@ pub async fn index(
State(captcha_solutions): State<Arc<captcha_solutions::SharedCaptchaSolutions>>, State(captcha_solutions): State<Arc<captcha_solutions::SharedCaptchaSolutions>>,
) -> Result<Response, errors::AppError> { ) -> Result<Response, errors::AppError> {
info!("Visited get(index)"); info!("Visited get(index)");
render_contact_form(IndexParams { render_contact_form(IndexParams {
config, config,
captcha_solutions, captcha_solutions,
@ -41,9 +42,9 @@ pub async fn render_contact_form(params: IndexParams<'_>) -> Result<Response, er
let captcha = captcha::by_name(captcha::Difficulty::Easy, captcha::CaptchaName::Lucy); let captcha = captcha::by_name(captcha::Difficulty::Easy, captcha::CaptchaName::Lucy);
let captcha_base64 = captcha.as_base64().context("Failed to create a captcha!")?; let captcha_base64 = captcha.as_base64().context("Failed to create a captcha!")?;
let id = params let solution = captcha.chars_as_string();
.captcha_solutions
.store_solution(&captcha.chars_as_string()); let id = params.captcha_solutions.store_sol(solution);
let template = templates::ContactForm { let template = templates::ContactForm {
base: templates::Base { base: templates::Base {