Skip to content

Commit

Permalink
Merge pull request #50 from GopherJ/feature/watcher-and-cache
Browse files Browse the repository at this point in the history
Feature/watcher and cache
  • Loading branch information
hsluoyz authored Feb 4, 2020
2 parents db25089 + 2fabb42 commit 24613b2
Show file tree
Hide file tree
Showing 15 changed files with 530 additions and 63 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@ description = "An authorization library that supports access control models like
regex = "1.3.1"
rhai = "0.9.1"
ip_network = "0.3.4"
ttl_cache = "0.5.1"
emitbrown = "0.1.8"
lazy_static = "1.4.0"
indexmap = "1.3.1"

4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Add this package to `Cargo.toml` of your project. (Check https://crates.io/crate

```toml
[dependencies]
casbin = "0.1.5"
casbin = "0.1.6"
```

## Get started
Expand All @@ -36,7 +36,7 @@ use casbin::prelude::*;
let model = Model::from_file("path/to/model.conf")?;
let adapter = FileAdapter::new("path/to/policy.csv");

let e = Enforcer::new(model, adapter);
let e = Enforcer::new(model, adapter)?;
```

2. Add an enforcement hook into your code right before the access happens:
Expand Down
2 changes: 1 addition & 1 deletion src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub use memory_adapter::MemoryAdapter;
use crate::model::Model;
use crate::Result;

pub trait Adapter {
pub trait Adapter: Send + Sync {
fn load_policy(&self, m: &mut Model) -> Result<()>;
fn save_policy(&self, m: &mut Model) -> Result<()>;
fn add_policy(&mut self, sec: &str, ptype: &str, rule: Vec<&str>) -> Result<bool>;
Expand Down
2 changes: 1 addition & 1 deletion src/adapter/file_adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl<P: AsRef<Path>> FileAdapter<P> {
}
}

impl<P: AsRef<Path>> Adapter for FileAdapter<P> {
impl<P: AsRef<Path> + Send + Sync> Adapter for FileAdapter<P> {
fn load_policy(&self, m: &mut Model) -> Result<()> {
self.load_policy_file(m, load_policy_line)?;
Ok(())
Expand Down
90 changes: 90 additions & 0 deletions src/cached_enforcer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use crate::adapter::Adapter;
use crate::emitter::{Event, CACHED_EMITTER};
use crate::enforcer::Enforcer;
use crate::model::Model;
use crate::Result;

use emitbrown::Events;
use ttl_cache::TtlCache;

use std::ops::{Deref, DerefMut};
use std::time::Duration;

pub struct CachedEnforcer {
pub(crate) ttl: Duration,
pub(crate) max_cached_items: usize,
pub(crate) enforcer: Enforcer,
pub(crate) cache: Option<TtlCache<Vec<String>, bool>>,
}

impl CachedEnforcer {
pub fn new(m: Model, a: Box<dyn Adapter>) -> Result<CachedEnforcer> {
let cached_enforcer = CachedEnforcer {
ttl: Duration::from_secs(120),
max_cached_items: 1000,
enforcer: Enforcer::new(m, a)?,
cache: None,
};

CACHED_EMITTER.lock().unwrap().on(
Event::PolicyChange,
Box::new(|ce: &mut CachedEnforcer| {
if let Some(ref mut cache) = ce.cache {
cache.clear();
}
}),
);

Ok(cached_enforcer)
}

pub fn set_ttl(&mut self, ttl: Duration) {
self.ttl = ttl;
}

pub fn set_max_cached_items(&mut self, max_cached_items: usize) {
self.max_cached_items = max_cached_items;
}

pub fn enable_cache(&mut self) {
if self.cache.is_none() {
self.cache = Some(TtlCache::new(self.max_cached_items));
}
}

pub fn disable_cache(&mut self) {
if self.cache.is_some() {
self.cache = None;
}
}

pub fn enforce(&mut self, rvals: Vec<&str>) -> Result<bool> {
if let Some(ref mut cache) = self.cache {
let key: Vec<String> = rvals.iter().map(|&x| String::from(x)).collect();

if cache.contains_key(&key) {
Ok(*cache.get(&key).unwrap())
} else {
let result = self.enforcer.enforce(rvals)?;
cache.insert(key, result, self.ttl);
Ok(result)
}
} else {
self.enforcer.enforce(rvals)
}
}
}

impl Deref for CachedEnforcer {
type Target = Enforcer;

fn deref(&self) -> &Self::Target {
&self.enforcer
}
}

impl DerefMut for CachedEnforcer {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.enforcer
}
}
5 changes: 2 additions & 3 deletions src/effector.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pub trait Effector: Send + Sync {
fn merge_effects(&self, expr: String, effects: Vec<EffectKind>, results: Vec<f64>) -> bool;
fn merge_effects(&self, expr: String, effects: Vec<EffectKind>) -> bool;
}

#[derive(PartialEq, Clone)]
Expand All @@ -12,9 +12,8 @@ pub enum EffectKind {
#[derive(Default)]
pub struct DefaultEffector {}

// TODO: can we remove results? seems to be useless
impl Effector for DefaultEffector {
fn merge_effects(&self, expr: String, effects: Vec<EffectKind>, _results: Vec<f64>) -> bool {
fn merge_effects(&self, expr: String, effects: Vec<EffectKind>) -> bool {
if expr == "some(where (p_eft == allow))" {
let mut result = false;
for eft in effects {
Expand Down
19 changes: 19 additions & 0 deletions src/emitter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use crate::cached_enforcer::CachedEnforcer;
use crate::enforcer::Enforcer;

use emitbrown::Emitter;
use lazy_static::lazy_static;

use std::sync::Mutex;

#[derive(Hash, PartialEq, Eq)]
pub(crate) enum Event {
PolicyChange,
}

lazy_static! {
pub(crate) static ref EMITTER: Mutex<Emitter<'static, Event, Enforcer>> =
{ Mutex::new(Emitter::new()) };
pub(crate) static ref CACHED_EMITTER: Mutex<Emitter<'static, Event, CachedEnforcer>> =
{ Mutex::new(Emitter::new()) };
}
Loading

0 comments on commit 24613b2

Please sign in to comment.