working free

This commit is contained in:
realaravinth 2021-06-02 17:20:06 +05:30
parent 158f518449
commit 7bc8d4fcfb
3 changed files with 73 additions and 41 deletions

View file

@ -18,6 +18,10 @@ use redis_module::{redis_command, redis_module};
use redis_module::{Context, NextArg, RedisResult}; use redis_module::{Context, NextArg, RedisResult};
mod pocket; mod pocket;
mod utils;
use pocket::MCAPTCHA_POCKET_TYPE;
fn timer_create(ctx: &Context, args: Vec<String>) -> RedisResult { fn timer_create(ctx: &Context, args: Vec<String>) -> RedisResult {
let mut args = args.into_iter().skip(1); let mut args = args.into_iter().skip(1);
// mcaptcha captcha key name // mcaptcha captcha key name
@ -35,8 +39,8 @@ fn timer_create(ctx: &Context, args: Vec<String>) -> RedisResult {
redis_module! { redis_module! {
name: "mcaptcha_cahce", name: "mcaptcha_cahce",
version: 1, version: 1,
data_types: [], data_types: [MCAPTCHA_POCKET_TYPE,],
commands: [ commands: [
["mcaptcha_cahce.create", timer_create, "", 0, 0, 0], ["mcaptcha_cahce.create", timer_create, "write", 1, 1, 1],
], ],
} }

View file

@ -15,48 +15,33 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
use std::collections::HashMap;
use std::os::raw::c_void; 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::native_types::RedisType;
use redis_module::raw::KeyType; use redis_module::raw::KeyType;
use redis_module::RedisError; use redis_module::RedisError;
use redis_module::{raw, Context}; use redis_module::{raw, Context};
pub const PREFIX_COUNTER: &str = "mcaptcha_cache:captcha:"; use crate::utils::*;
pub const PREFIX_TIME_POCKET: &str = "mcaptcha_cache:pocket:";
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Pocket { pub struct Pocket {
timer: Option<u64>, timer: Option<u64>,
pocket_instant: u64, pocket_instant: u64,
decrement: HashMap<String, usize>, decrement: Vec<(String, u32)>,
}
#[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<u64, RedisError> {
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)
} }
impl Pocket { 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` /// creates new pocket and sets off timer to go off at `duration`
pub fn new(ctx: &Context, duration: u64) -> Result<Self, RedisError> { pub fn new(ctx: &Context, duration: u64) -> Result<Self, RedisError> {
let decrement = HashMap::new(); let decrement = Vec::with_capacity(1);
let pocket_instant = pocket_instant(duration)?; let pocket_instant = pocket_instant(duration)?;
let timer = Some(ctx.create_timer( let timer = Some(ctx.create_timer(
@ -102,18 +87,18 @@ impl Pocket {
let pocket = ctx.open_key_writable(&pocket_name); let pocket = ctx.open_key_writable(&pocket_name);
match pocket.get_value::<Pocket>(&MCAPTCHA_POCKET_TYPE)? { match pocket.get_value::<Pocket>(&MCAPTCHA_POCKET_TYPE)? {
Some(pocket) => match pocket.decrement.get_mut(&captcha_name) { Some(pocket) => match Self::get_mut(&mut pocket.decrement, &captcha_name) {
Some(count) => *count += 1, Some((_name, count)) => *count += 1,
None => { None => {
pocket.decrement.insert(captcha_name, 1); pocket.decrement.push((captcha_name, 1));
} }
}, },
None => { None => {
let mut counter = Pocket::new(ctx, duration)?; 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_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 { match val {
Some(pocket) => { Some(pocket) => {
ctx.log_warning(&format!("entering loop hashmap ")); 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!( ctx.log_warning(&format!(
"reading captcha: {} with decr count {}", "reading captcha: {} with decr count {}",
&captcha, count &captcha, count
@ -142,7 +127,7 @@ impl Pocket {
continue; continue;
} }
let mut stored_count: usize = let mut stored_count: u32 =
stored_captcha.read().unwrap().unwrap().parse().unwrap(); stored_captcha.read().unwrap().unwrap().parse().unwrap();
stored_count -= count; stored_count -= count;
stored_captcha.write(&stored_count.to_string()).unwrap(); stored_captcha.write(&stored_count.to_string()).unwrap();
@ -156,16 +141,18 @@ impl Pocket {
ctx.log_warning(&format!("loop exited")); ctx.log_warning(&format!("loop exited"));
let res = key.delete(); let res = key.delete();
if res.is_err() {
ctx.log_warning(&format!( ctx.log_warning(&format!(
"enountered error while deleting hashmap: {:?}", "enountered error while deleting hashmap: {:?}",
res res
)); ));
//res.unwrap(); }
res.unwrap();
} }
} }
static MCAPTCHA_POCKET_TYPE: RedisType = RedisType::new( pub static MCAPTCHA_POCKET_TYPE: RedisType = RedisType::new(
"mcaptcha_cache_pocket", "mcaptchac",
0, 0,
raw::RedisModuleTypeMethods { raw::RedisModuleTypeMethods {
version: raw::REDISMODULE_TYPE_METHOD_VERSION as u64, version: raw::REDISMODULE_TYPE_METHOD_VERSION as u64,

41
src/utils.rs Normal file
View file

@ -0,0 +1,41 @@
/*
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
*
* 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 <https://www.gnu.org/licenses/>.
*/
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<u64, RedisError> {
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)
}