docs
This commit is contained in:
parent
07f124fb82
commit
86b3f2cd95
6 changed files with 36 additions and 47 deletions
|
@ -99,36 +99,6 @@ impl From<MCaptcha> for Counter {
|
||||||
Counter(m)
|
Counter(m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl Counter {
|
|
||||||
// /// increments the visitor count by one
|
|
||||||
// pub fn add_visitor(&mut self) {
|
|
||||||
// self.visitor_threshold += 1;
|
|
||||||
// if self.visitor_threshold > self.defense.visitor_threshold() {
|
|
||||||
// self.defense.tighten_up();
|
|
||||||
// } else {
|
|
||||||
// self.defense.loosen_up();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /// decrements the visitor count by one
|
|
||||||
// pub fn decrement_visitor(&mut self) {
|
|
||||||
// if self.visitor_threshold > 0 {
|
|
||||||
// self.visitor_threshold -= 1;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /// get current difficulty factor
|
|
||||||
// pub fn get_difficulty(&self) -> u32 {
|
|
||||||
// self.defense.get_difficulty()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /// get [Counter]'s lifetime
|
|
||||||
// pub fn get_duration(&self) -> u64 {
|
|
||||||
// self.duration
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
impl Actor for Counter {
|
impl Actor for Counter {
|
||||||
type Context = Context<Self>;
|
type Context = Context<Self>;
|
||||||
}
|
}
|
||||||
|
@ -151,15 +121,6 @@ impl Handler<DeleteVisitor> for Counter {
|
||||||
#[rtype(result = "AddVisitorResult")]
|
#[rtype(result = "AddVisitorResult")]
|
||||||
pub struct AddVisitor;
|
pub struct AddVisitor;
|
||||||
|
|
||||||
//impl AddVisitorResult {
|
|
||||||
// fn new(m: &Counter) -> Self {
|
|
||||||
// AddVisitorResult {
|
|
||||||
// duration: m.0.get_duration(),
|
|
||||||
// difficulty_factor: m.0.get_difficulty(),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
impl Handler<AddVisitor> for Counter {
|
impl Handler<AddVisitor> for Counter {
|
||||||
type Result = MessageResult<AddVisitor>;
|
type Result = MessageResult<AddVisitor>;
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
//! [Master] actor module that manages [Counter] actors
|
//! Embedded [Master] actor module that manages [Counter] actors
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::sync::mpsc::channel;
|
use std::sync::mpsc::channel;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
|
@ -15,6 +15,6 @@
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
//! Embedded master actor: manages counter and all mCaptcha stuff in-memory
|
||||||
pub mod counter;
|
pub mod counter;
|
||||||
pub mod master;
|
pub mod master;
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
//! [Master] actor module that manages [MCaptcha] actors
|
//! [Master] actor module that manages [MCaptcha] actors
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::mcaptcha::*;
|
use crate::mcaptcha::*;
|
||||||
|
@ -34,6 +33,8 @@ pub trait Master:
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
/// [mCaptcha Redis module](https://github.com/mCaptcha/cache) uses this datatype for CAPTCHA
|
||||||
|
/// registration
|
||||||
pub struct CreateMCaptcha {
|
pub struct CreateMCaptcha {
|
||||||
pub levels: Vec<crate::defense::Level>,
|
pub levels: Vec<crate::defense::Level>,
|
||||||
pub duration: u64,
|
pub duration: u64,
|
||||||
|
@ -49,6 +50,7 @@ pub struct AddVisitorResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddVisitorResult {
|
impl AddVisitorResult {
|
||||||
|
/// create new [AddVisitorResult] from [MCaptcha]
|
||||||
pub fn new(m: &MCaptcha) -> Self {
|
pub fn new(m: &MCaptcha) -> Self {
|
||||||
AddVisitorResult {
|
AddVisitorResult {
|
||||||
duration: m.get_duration(),
|
duration: m.get_duration(),
|
||||||
|
@ -59,6 +61,7 @@ impl AddVisitorResult {
|
||||||
|
|
||||||
#[cfg(feature = "full")]
|
#[cfg(feature = "full")]
|
||||||
pub mod messages {
|
pub mod messages {
|
||||||
|
//! Messages that a [super::Master] should respond to
|
||||||
use std::sync::mpsc::Receiver;
|
use std::sync::mpsc::Receiver;
|
||||||
|
|
||||||
use actix::dev::*;
|
use actix::dev::*;
|
||||||
|
|
|
@ -28,7 +28,7 @@ use crate::redis::RedisConnection;
|
||||||
/// Redis instance with mCaptcha Redis module loaded
|
/// Redis instance with mCaptcha Redis module loaded
|
||||||
pub struct MCaptchaRedis(Redis);
|
pub struct MCaptchaRedis(Redis);
|
||||||
|
|
||||||
/// Redis instance with mCaptcha Redis module loaded
|
/// Connection to Redis instance with mCaptcha Redis module loaded
|
||||||
pub struct MCaptchaRedisConnection(RedisConnection);
|
pub struct MCaptchaRedisConnection(RedisConnection);
|
||||||
|
|
||||||
const GET: &str = "MCAPTCHA_CACHE.GET";
|
const GET: &str = "MCAPTCHA_CACHE.GET";
|
||||||
|
@ -40,6 +40,10 @@ const CAPTCHA_EXISTS: &str = "MCAPTCHA_CACHE.CAPTCHA_EXISTS";
|
||||||
const MODULE_NAME: &str = "mcaptcha_cahce";
|
const MODULE_NAME: &str = "mcaptcha_cahce";
|
||||||
|
|
||||||
impl MCaptchaRedis {
|
impl MCaptchaRedis {
|
||||||
|
/// Get new [MCaptchaRedis]. Use this when executing commands that are
|
||||||
|
/// only supported by mCaptcha Redis module. Internally, when object
|
||||||
|
/// is created, checks are performed to check if the module is loaded and if
|
||||||
|
/// the required commands are available
|
||||||
pub async fn new(redis: RedisConfig) -> CaptchaResult<Self> {
|
pub async fn new(redis: RedisConfig) -> CaptchaResult<Self> {
|
||||||
let redis = Redis::new(redis).await?;
|
let redis = Redis::new(redis).await?;
|
||||||
let m = MCaptchaRedis(redis);
|
let m = MCaptchaRedis(redis);
|
||||||
|
@ -47,13 +51,16 @@ impl MCaptchaRedis {
|
||||||
Ok(m)
|
Ok(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get connection to a Redis instance with mCaptcha Redis module loaded
|
||||||
|
///
|
||||||
|
/// Uses interior mutability so look out for panics!
|
||||||
pub fn get_client(&self) -> MCaptchaRedisConnection {
|
pub fn get_client(&self) -> MCaptchaRedisConnection {
|
||||||
MCaptchaRedisConnection(self.0.get_client())
|
MCaptchaRedisConnection(self.0.get_client())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MCaptchaRedisConnection {
|
impl MCaptchaRedisConnection {
|
||||||
pub async fn is_module_loaded(&self) -> CaptchaResult<()> {
|
async fn is_module_loaded(&self) -> CaptchaResult<()> {
|
||||||
let modules: Vec<Vec<String>> = self
|
let modules: Vec<Vec<String>> = self
|
||||||
.0
|
.0
|
||||||
.exec(redis::cmd("MODULE").arg(&["LIST"]))
|
.exec(redis::cmd("MODULE").arg(&["LIST"]))
|
||||||
|
@ -94,12 +101,14 @@ impl MCaptchaRedisConnection {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add visitor
|
||||||
pub async fn add_visitor(&self, msg: AddVisitor) -> CaptchaResult<Option<AddVisitorResult>> {
|
pub async fn add_visitor(&self, msg: AddVisitor) -> CaptchaResult<Option<AddVisitorResult>> {
|
||||||
let res: String = self.0.exec(redis::cmd(ADD_VISITOR).arg(&[msg.0])).await?;
|
let res: String = self.0.exec(redis::cmd(ADD_VISITOR).arg(&[msg.0])).await?;
|
||||||
let res: AddVisitorResult = serde_json::from_str(&res).unwrap();
|
let res: AddVisitorResult = serde_json::from_str(&res).unwrap();
|
||||||
Ok(Some(res))
|
Ok(Some(res))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Register new mCaptcha with Redis
|
||||||
pub async fn add_mcaptcha(&self, msg: AddSite) -> CaptchaResult<()> {
|
pub async fn add_mcaptcha(&self, msg: AddSite) -> CaptchaResult<()> {
|
||||||
let name = msg.id;
|
let name = msg.id;
|
||||||
let captcha: CreateMCaptcha = msg.mcaptcha.into();
|
let captcha: CreateMCaptcha = msg.mcaptcha.into();
|
||||||
|
@ -110,6 +119,7 @@ impl MCaptchaRedisConnection {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if an mCaptcha object is available in Redis
|
||||||
pub async fn check_captcha_exists(&self, captcha: &str) -> CaptchaResult<bool> {
|
pub async fn check_captcha_exists(&self, captcha: &str) -> CaptchaResult<bool> {
|
||||||
let exists: usize = self
|
let exists: usize = self
|
||||||
.0
|
.0
|
||||||
|
@ -129,11 +139,13 @@ impl MCaptchaRedisConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Delete an mCaptcha object from Redis
|
||||||
pub async fn delete_captcha(&self, captcha: &str) -> CaptchaResult<()> {
|
pub async fn delete_captcha(&self, captcha: &str) -> CaptchaResult<()> {
|
||||||
self.0.exec(redis::cmd(DEL).arg(&[captcha])).await?;
|
self.0.exec(redis::cmd(DEL).arg(&[captcha])).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get number of visitors of an mCaptcha object from Redis
|
||||||
pub async fn get_visitors(&self, captcha: &str) -> CaptchaResult<usize> {
|
pub async fn get_visitors(&self, captcha: &str) -> CaptchaResult<usize> {
|
||||||
let visitors: usize = self.0.exec(redis::cmd(GET).arg(&[captcha])).await?;
|
let visitors: usize = self.0.exec(redis::cmd(GET).arg(&[captcha])).await?;
|
||||||
Ok(visitors)
|
Ok(visitors)
|
||||||
|
|
19
src/redis.rs
19
src/redis.rs
|
@ -15,25 +15,28 @@
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
//! Redis Client/Connection manager that can handle both single and clustered Redis Instances
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use redis::cluster::ClusterClient;
|
use redis::cluster::ClusterClient;
|
||||||
use redis::FromRedisValue;
|
|
||||||
//use redis::cluster::ClusterConnection;
|
|
||||||
use redis::Client;
|
use redis::Client;
|
||||||
//use redis::Connection;
|
use redis::FromRedisValue;
|
||||||
use redis::{aio::Connection, cluster::ClusterConnection};
|
use redis::{aio::Connection, cluster::ClusterConnection};
|
||||||
|
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
|
|
||||||
|
/// Client configuration
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum RedisConfig {
|
pub enum RedisConfig {
|
||||||
|
/// Redis server URL
|
||||||
Single(String),
|
Single(String),
|
||||||
|
/// List of URL of Redis nodes in cluster mode
|
||||||
Cluster(Vec<String>),
|
Cluster(Vec<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RedisConfig {
|
impl RedisConfig {
|
||||||
|
/// Create Redis connection
|
||||||
pub fn connect(&self) -> RedisClient {
|
pub fn connect(&self) -> RedisClient {
|
||||||
match self {
|
match self {
|
||||||
Self::Single(url) => {
|
Self::Single(url) => {
|
||||||
|
@ -48,6 +51,7 @@ impl RedisConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Redis connection - manages both single and clustered deployments
|
||||||
pub enum RedisConnection {
|
pub enum RedisConnection {
|
||||||
Single(Rc<RefCell<Connection>>),
|
Single(Rc<RefCell<Connection>>),
|
||||||
Cluster(Rc<RefCell<ClusterConnection>>),
|
Cluster(Rc<RefCell<ClusterConnection>>),
|
||||||
|
@ -55,6 +59,7 @@ pub enum RedisConnection {
|
||||||
|
|
||||||
impl RedisConnection {
|
impl RedisConnection {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
/// Get client. Uses interior mutability, so lookout for panics
|
||||||
pub fn get_client(&self) -> Self {
|
pub fn get_client(&self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::Single(con) => Self::Single(Rc::clone(&con)),
|
Self::Single(con) => Self::Single(Rc::clone(&con)),
|
||||||
|
@ -62,6 +67,7 @@ impl RedisConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
/// execute a redis command against a [Self]
|
||||||
pub async fn exec<T: FromRedisValue>(&self, cmd: &mut redis::Cmd) -> redis::RedisResult<T> {
|
pub async fn exec<T: FromRedisValue>(&self, cmd: &mut redis::Cmd) -> redis::RedisResult<T> {
|
||||||
match self {
|
match self {
|
||||||
RedisConnection::Single(con) => cmd.query_async(&mut *con.borrow_mut()).await,
|
RedisConnection::Single(con) => cmd.query_async(&mut *con.borrow_mut()).await,
|
||||||
|
@ -71,17 +77,21 @@ impl RedisConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
/// Client Configuration that can be used to get new connection shuld [RedisConnection] fail
|
||||||
pub enum RedisClient {
|
pub enum RedisClient {
|
||||||
Single(Client),
|
Single(Client),
|
||||||
Cluster(ClusterClient),
|
Cluster(ClusterClient),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A Redis Client Object that encapsulates [RedisClient] and [RedisConnection].
|
||||||
|
/// Use this when you need a Redis Client
|
||||||
pub struct Redis {
|
pub struct Redis {
|
||||||
_client: RedisClient,
|
_client: RedisClient,
|
||||||
connection: RedisConnection,
|
connection: RedisConnection,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Redis {
|
impl Redis {
|
||||||
|
/// create new [Redis]. Will try to connect to Redis instance specified in [RedisConfig]
|
||||||
pub async fn new(redis: RedisConfig) -> CaptchaResult<Self> {
|
pub async fn new(redis: RedisConfig) -> CaptchaResult<Self> {
|
||||||
let (_client, connection) = Self::connect(redis).await;
|
let (_client, connection) = Self::connect(redis).await;
|
||||||
let master = Self {
|
let master = Self {
|
||||||
|
@ -91,6 +101,9 @@ impl Redis {
|
||||||
Ok(master)
|
Ok(master)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get client to do interact with Redis server.
|
||||||
|
///
|
||||||
|
/// Uses Interior mutability so look out for panics
|
||||||
pub fn get_client(&self) -> RedisConnection {
|
pub fn get_client(&self) -> RedisConnection {
|
||||||
self.connection.get_client()
|
self.connection.get_client()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue