diff --git a/src/lib.rs b/src/lib.rs index 0a1c89b..8d5efe9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,10 @@ use redis_module::{redis_command, redis_module}; use redis_module::{Context, NextArg, RedisResult}; mod pocket; +mod utils; + +use pocket::MCAPTCHA_POCKET_TYPE; + fn timer_create(ctx: &Context, args: Vec) -> RedisResult { let mut args = args.into_iter().skip(1); // mcaptcha captcha key name @@ -35,8 +39,8 @@ fn timer_create(ctx: &Context, args: Vec) -> RedisResult { redis_module! { name: "mcaptcha_cahce", version: 1, - data_types: [], + data_types: [MCAPTCHA_POCKET_TYPE,], commands: [ - ["mcaptcha_cahce.create", timer_create, "", 0, 0, 0], + ["mcaptcha_cahce.create", timer_create, "write", 1, 1, 1], ], } diff --git a/src/pocket.rs b/src/pocket.rs index 41854cf..c1a4148 100644 --- a/src/pocket.rs +++ b/src/pocket.rs @@ -15,48 +15,33 @@ * along with this program. If not, see . */ -use std::collections::HashMap; use std::os::raw::c_void; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; +use std::time::Duration; use redis_module::native_types::RedisType; use redis_module::raw::KeyType; use redis_module::RedisError; use redis_module::{raw, Context}; -pub const PREFIX_COUNTER: &str = "mcaptcha_cache:captcha:"; -pub const PREFIX_TIME_POCKET: &str = "mcaptcha_cache:pocket:"; +use crate::utils::*; #[derive(Debug, Clone)] pub struct Pocket { timer: Option, pocket_instant: u64, - decrement: HashMap, -} - -#[inline] -/// duration in seconds -fn get_pocket_name(pocket_instant: u64) -> String { - format!("{}{}", PREFIX_TIME_POCKET, pocket_instant) -} - -#[inline] -fn pocket_instant(duration: u64) -> Result { - match SystemTime::now().duration_since(UNIX_EPOCH) { - Ok(val) => Ok(val.as_secs() + duration), - Err(_) => Err(RedisError::String("SystemTime before UNIX EPOCH!".into())), - } -} - -#[inline] -fn get_captcha_key(name: &str) -> String { - format!("{}{}", PREFIX_COUNTER, name) + decrement: Vec<(String, u32)>, } impl Pocket { + #[inline] + fn get_mut<'a>(v: &'a mut Vec<(String, u32)>, query: &str) -> Option<&'a mut (String, u32)> { + v.iter_mut() + .find(|(name, _)| if name == query { true } else { false }) + } + /// creates new pocket and sets off timer to go off at `duration` pub fn new(ctx: &Context, duration: u64) -> Result { - let decrement = HashMap::new(); + let decrement = Vec::with_capacity(1); let pocket_instant = pocket_instant(duration)?; let timer = Some(ctx.create_timer( @@ -102,18 +87,18 @@ impl Pocket { let pocket = ctx.open_key_writable(&pocket_name); match pocket.get_value::(&MCAPTCHA_POCKET_TYPE)? { - Some(pocket) => match pocket.decrement.get_mut(&captcha_name) { - Some(count) => *count += 1, + Some(pocket) => match Self::get_mut(&mut pocket.decrement, &captcha_name) { + Some((_name, count)) => *count += 1, None => { - pocket.decrement.insert(captcha_name, 1); + pocket.decrement.push((captcha_name, 1)); } }, None => { let mut counter = Pocket::new(ctx, duration)?; - counter.decrement.insert(captcha_name, 1); + counter.decrement.push((captcha_name, 1)); pocket.set_value(&MCAPTCHA_POCKET_TYPE, counter)?; - pocket.set_expire(Duration::from_secs(duration + 10))?; + // pocket.set_expire(Duration::from_secs(duration + 10))?; } }; @@ -132,7 +117,7 @@ impl Pocket { match val { Some(pocket) => { ctx.log_warning(&format!("entering loop hashmap ")); - for (captcha, count) in pocket.decrement.drain() { + for (captcha, count) in pocket.decrement.iter() { ctx.log_warning(&format!( "reading captcha: {} with decr count {}", &captcha, count @@ -142,7 +127,7 @@ impl Pocket { continue; } - let mut stored_count: usize = + let mut stored_count: u32 = stored_captcha.read().unwrap().unwrap().parse().unwrap(); stored_count -= count; stored_captcha.write(&stored_count.to_string()).unwrap(); @@ -156,16 +141,18 @@ impl Pocket { ctx.log_warning(&format!("loop exited")); let res = key.delete(); - ctx.log_warning(&format!( - "enountered error while deleting hashmap: {:?}", - res - )); - //res.unwrap(); + if res.is_err() { + ctx.log_warning(&format!( + "enountered error while deleting hashmap: {:?}", + res + )); + } + res.unwrap(); } } -static MCAPTCHA_POCKET_TYPE: RedisType = RedisType::new( - "mcaptcha_cache_pocket", +pub static MCAPTCHA_POCKET_TYPE: RedisType = RedisType::new( + "mcaptchac", 0, raw::RedisModuleTypeMethods { version: raw::REDISMODULE_TYPE_METHOD_VERSION as u64, diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..fe4dbd8 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use std::time::{SystemTime, UNIX_EPOCH}; + +use redis_module::RedisError; + +pub const PREFIX_COUNTER: &str = "mcaptcha_cache:captcha:"; +pub const PREFIX_TIME_POCKET: &str = "mcaptcha_cache:pocket:"; + +#[inline] +/// duration in seconds +pub fn get_pocket_name(pocket_instant: u64) -> String { + format!("{}{}", PREFIX_TIME_POCKET, pocket_instant) +} + +#[inline] +pub fn pocket_instant(duration: u64) -> Result { + match SystemTime::now().duration_since(UNIX_EPOCH) { + Ok(val) => Ok(val.as_secs() + duration), + Err(_) => Err(RedisError::String("SystemTime before UNIX EPOCH!".into())), + } +} + +#[inline] +pub fn get_captcha_key(name: &str) -> String { + format!("{}{}", PREFIX_COUNTER, name) +}