Skip to content

Commit

Permalink
Opening seam for injectable root
Browse files Browse the repository at this point in the history
Signed-off-by: Alex Snaps <[email protected]>
  • Loading branch information
alexsnaps committed Dec 3, 2024
1 parent 7c33b77 commit b816ec3
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 30 deletions.
13 changes: 6 additions & 7 deletions limitador/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,14 +192,13 @@
// TODO this needs review to reduce the bloat pulled in by dependencies
#![allow(clippy::multiple_crate_versions)]

use std::collections::{HashMap, HashSet};
use std::sync::Arc;

use crate::counter::Counter;
use crate::errors::LimitadorError;
use crate::limit::{Limit, Namespace};
use crate::storage::in_memory::InMemoryStorage;
use crate::storage::{AsyncCounterStorage, AsyncStorage, Authorization, CounterStorage, Storage};
use std::collections::{HashMap, HashSet};
use std::sync::Arc;

#[macro_use]
extern crate core;
Expand Down Expand Up @@ -480,10 +479,10 @@ impl RateLimiter {
values: &HashMap<String, String>,
) -> LimitadorResult<Vec<Counter>> {
let limits = self.storage.get_limits(namespace);

let ctx = values.into();
limits
.iter()
.filter(|lim| lim.applies(values))
.filter(|lim| lim.applies(&ctx))
.map(|lim| Counter::new(Arc::clone(lim), values.clone()))
.collect()
}
Expand Down Expand Up @@ -657,10 +656,10 @@ impl AsyncRateLimiter {
values: &HashMap<String, String>,
) -> LimitadorResult<Vec<Counter>> {
let limits = self.storage.get_limits(namespace);

let ctx = values.into();
limits
.iter()
.filter(|lim| lim.applies(values))
.filter(|lim| lim.applies(&ctx))
.map(|lim| Counter::new(Arc::clone(lim), values.clone()))
.collect()
}
Expand Down
30 changes: 15 additions & 15 deletions limitador/src/limit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ impl Limit {
&self,
vars: HashMap<String, String>,
) -> Result<BTreeMap<String, String>, EvaluationError> {
let ctx = Context::new(self, String::default(), &vars);
let ctx = Context::new(String::default(), &vars);
let mut map = BTreeMap::new();
for variable in &self.variables {
let name = variable.source().into();
Expand All @@ -162,17 +162,17 @@ impl Limit {
.any(|v| v.as_str() == var)
}

pub fn applies(&self, values: &HashMap<String, String>) -> bool {
let ctx = Context::new(self, String::default(), values);
pub fn applies(&self, ctx: &Context) -> bool {
let ctx = ctx.for_limit(self);
let all_conditions_apply = self
.conditions
.iter()
.all(|predicate| predicate.test(&ctx).unwrap());
.all(|predicate| predicate.test(&ctx.for_limit(self)).unwrap());

let all_vars_are_set = self
.variables
.iter()
.all(|var| values.contains_key(var.source()));
.all(|var| ctx.has_variable(var.source()));

all_conditions_apply && all_vars_are_set
}
Expand Down Expand Up @@ -252,7 +252,7 @@ mod tests {
values.insert("x".into(), "5".into());
values.insert("y".into(), "1".into());

assert!(limit.applies(&values))
assert!(limit.applies(&(&values).into()))
}

#[test]
Expand All @@ -269,7 +269,7 @@ mod tests {
values.insert("x".into(), "1".into());
values.insert("y".into(), "1".into());

assert!(!limit.applies(&values))
assert!(!limit.applies(&(&values).into()))
}

#[test]
Expand All @@ -287,7 +287,7 @@ mod tests {
values.insert("a".into(), "1".into());
values.insert("y".into(), "1".into());

assert!(!limit.applies(&values))
assert!(!limit.applies(&(&values).into()))
}

#[test]
Expand All @@ -304,7 +304,7 @@ mod tests {
let mut values: HashMap<String, String> = HashMap::new();
values.insert("x".into(), "5".into());

assert!(!limit.applies(&values))
assert!(!limit.applies(&(&values).into()))
}

#[test]
Expand All @@ -325,7 +325,7 @@ mod tests {
values.insert("y".into(), "2".into());
values.insert("z".into(), "1".into());

assert!(limit.applies(&values))
assert!(limit.applies(&(&values).into()))
}

#[test]
Expand All @@ -346,7 +346,7 @@ mod tests {
values.insert("y".into(), "2".into());
values.insert("z".into(), "1".into());

assert!(!limit.applies(&values))
assert!(!limit.applies(&(&values).into()))
}

#[test]
Expand Down Expand Up @@ -410,10 +410,10 @@ mod tests {
.expect("failed parsing!")],
Vec::default(),
);
assert!(!limit.applies(&HashMap::default()));
assert!(!limit.applies(&Context::default()));

limit.set_name("named_limit".to_string());
assert!(limit.applies(&HashMap::default()));
assert!(limit.applies(&Context::default()));

let limit = Limit::with_id(
"my_id",
Expand All @@ -426,7 +426,7 @@ mod tests {
],
Vec::default(),
);
assert!(limit.applies(&HashMap::default()));
assert!(limit.applies(&(&HashMap::default()).into()));

let limit = Limit::with_id(
"my_id",
Expand All @@ -438,6 +438,6 @@ mod tests {
.expect("failed parsing!")],
Vec::default(),
);
assert!(!limit.applies(&HashMap::default()));
assert!(!limit.applies(&Context::default()));
}
}
41 changes: 33 additions & 8 deletions limitador/src/limit/cel.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use crate::limit::Limit;
use cel_interpreter::{ExecutionError, Value};
pub use errors::{EvaluationError, ParseError};
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
use std::hash::{Hash, Hasher};
use std::sync::Arc;

pub use errors::{EvaluationError, ParseError};

pub(super) mod errors {
use cel_interpreter::ExecutionError;
use std::error::Error;
Expand Down Expand Up @@ -78,8 +77,8 @@ pub struct Context<'a> {
ctx: cel_interpreter::Context<'a>,
}

impl Context<'_> {
pub(crate) fn new(limit: &Limit, root: String, values: &HashMap<String, String>) -> Self {
impl<'a> Context<'a> {
pub(crate) fn new(root: String, values: &HashMap<String, String>) -> Self {
let mut ctx = cel_interpreter::Context::default();

if root.is_empty() {
Expand All @@ -91,6 +90,17 @@ impl Context<'_> {
ctx.add_variable_from_value(root, Value::Map(map));
}

Self {
variables: values.keys().cloned().collect(),
ctx,
}
}

pub(crate) fn for_limit<'b>(&'b self, limit: &Limit) -> Self
where
'b: 'a,
{
let mut inner = self.ctx.new_inner_scope();
let limit_data = cel_interpreter::objects::Map::from(HashMap::from([
(
"name",
Expand All @@ -109,13 +119,28 @@ impl Context<'_> {
.unwrap_or(Value::Null),
),
]));
ctx.add_variable_from_value("limit", Value::Map(limit_data));

inner.add_variable_from_value("limit", Value::Map(limit_data));
Self {
variables: values.keys().cloned().collect(),
ctx,
variables: self.variables.clone(),
ctx: inner,
}
}

pub(crate) fn has_variable(&self, name: &str) -> bool {
self.variables.contains(name)
}
}

impl Default for Context<'_> {
fn default() -> Self {
Self::new(String::default(), &HashMap::default())
}
}

impl From<&HashMap<String, String>> for Context<'_> {
fn from(value: &HashMap<String, String>) -> Self {
Self::new(String::default(), value)
}
}

#[derive(Clone, Debug, Serialize, Deserialize)]
Expand Down

0 comments on commit b816ec3

Please sign in to comment.