Skip to content

Commit 723ed79

Browse files
sfavotjoelwurtz
authored andcommitted
impact computing
1 parent e940e3a commit 723ed79

File tree

11 files changed

+319
-355
lines changed

11 files changed

+319
-355
lines changed

src/http/request.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ impl Request {
128128
request.remote_addr = Some(IpAddr::from_str(ip).unwrap());
129129
}
130130

131+
if let Some(datetime) = &example.datetime {
132+
request.set_created_at(Some(datetime.to_string()));
133+
}
134+
131135
Ok(request)
132136
}
133137

src/router/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ mod transformer;
1313
use crate::http::Request;
1414
pub use config::RouterConfig;
1515
pub use marker_string::{Marker, MarkerString, StaticOrDynamic};
16-
pub use request_matcher::{HostMatcher, IpMatcher, DateTimeMatcher, WeekdayMatcher, TimeMatcher, MethodMatcher, PathAndQueryMatcher, RequestMatcher, SchemeMatcher};
16+
pub use request_matcher::{HostMatcher, IpMatcher, DateTimeMatcher, MethodMatcher, PathAndQueryMatcher, RequestMatcher, SchemeMatcher};
1717
pub use route::{Route, RouteData};
1818
pub use route_datetime::RouteDateTime;
1919
pub use route_header::{RouteHeader, RouteHeaderKind};
Lines changed: 172 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,91 @@
11
use crate::http::Request;
2+
use crate::router::request_matcher::{MethodMatcher, RequestMatcher};
23
use crate::router::route_datetime::RouteDateTime;
3-
use crate::router::trace::TraceInfo;
4-
use crate::router::{WeekdayMatcher, RequestMatcher, Route, RouteData, Trace};
5-
use std::collections::HashMap;
4+
use crate::router::route_time::RouteTime;
5+
use crate::router::route_weekday::RouteWeekday;
6+
use crate::router::trace::{TraceInfo, TraceInfoDateTimeCondition};
7+
use crate::router::{Route, RouteData, Trace};
8+
use chrono::{DateTime, Utc};
9+
use serde::{Deserialize, Serialize};
10+
use std::collections::BTreeMap;
11+
use std::collections::BTreeSet;
612

713
#[derive(Debug, Clone)]
814
pub struct DateTimeMatcher<T: RouteData> {
9-
matchers: HashMap<RouteDateTime, Box<dyn RequestMatcher<T>>>,
10-
no_matcher: Box<dyn RequestMatcher<T>>,
15+
any_datetime: Box<dyn RequestMatcher<T>>,
16+
conditions: BTreeSet<DateTimeCondition>,
17+
condition_groups: BTreeMap<BTreeSet<DateTimeCondition>, Box<dyn RequestMatcher<T>>>,
1118
count: usize,
1219
}
1320

21+
#[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
22+
#[serde(rename_all = "snake_case")]
23+
#[serde(tag = "type", content = "date_time_type")]
24+
pub enum DateTimeCondition {
25+
DateTimeRange(Vec<RouteDateTime>),
26+
TimeRange(Vec<RouteTime>),
27+
Weekdays(RouteWeekday),
28+
}
29+
1430
impl<T: RouteData> RequestMatcher<T> for DateTimeMatcher<T> {
1531
fn insert(&mut self, route: Route<T>) {
1632
self.count += 1;
1733

34+
let mut condition_group = BTreeSet::new();
35+
let mut conditions = BTreeSet::new();
36+
1837
match route.datetime() {
19-
Some(route_datetimes) => {
20-
for route_datetime in route_datetimes {
21-
self.matchers
22-
.entry(route_datetime.clone())
23-
.or_insert_with(|| Self::create_sub_matcher())
24-
.insert(route.clone());
25-
}
38+
Some(route_datetime) => {
39+
let condition = DateTimeCondition::DateTimeRange(route_datetime.clone());
40+
condition_group.insert(condition.clone());
41+
conditions.insert(condition);
2642
}
27-
None => {
28-
self.no_matcher.insert(route);
43+
None => (),
44+
}
45+
46+
match route.weekdays() {
47+
Some(route_weekdays) => {
48+
let condition = DateTimeCondition::Weekdays(route_weekdays.clone());
49+
condition_group.insert(condition.clone());
50+
conditions.insert(condition);
2951
}
52+
None => (),
3053
}
31-
}
3254

33-
fn remove(&mut self, id: &str) -> bool {
34-
let mut removed = false;
55+
match route.time() {
56+
Some(route_time) => {
57+
let condition = DateTimeCondition::TimeRange(route_time.clone());
58+
condition_group.insert(condition.clone());
59+
conditions.insert(condition);
60+
}
61+
None => (),
62+
}
3563

36-
if self.no_matcher.remove(id) {
37-
self.count -= 1;
64+
if conditions.is_empty() {
65+
self.any_datetime.insert(route);
66+
67+
return;
68+
}
69+
70+
self.conditions.extend(conditions);
3871

39-
return true;
72+
if !self.condition_groups.contains_key(&condition_group) {
73+
self.condition_groups.insert(condition_group.clone(), Self::create_sub_matcher());
4074
}
4175

42-
self.matchers.retain(|_, matcher| {
76+
let matcher = self.condition_groups.get_mut(&condition_group).unwrap();
77+
78+
matcher.insert(route)
79+
}
80+
81+
fn remove(&mut self, id: &str) -> bool {
82+
let mut removed = false;
83+
84+
for matcher in self.condition_groups.values_mut() {
4385
removed = removed || matcher.remove(id);
86+
}
4487

45-
matcher.len() > 0
46-
});
88+
removed = removed || self.any_datetime.remove(id);
4789

4890
if removed {
4991
self.count -= 1;
@@ -53,63 +95,108 @@ impl<T: RouteData> RequestMatcher<T> for DateTimeMatcher<T> {
5395
}
5496

5597
fn match_request(&self, request: &Request) -> Vec<&Route<T>> {
56-
let mut routes = self.no_matcher.match_request(request);
98+
let mut rules = self.any_datetime.match_request(request);
99+
let mut execute_conditions = BTreeMap::new();
57100

58101
if let Some(datetime) = request.created_at.as_ref() {
59-
for (datetime_matcher, matcher) in &self.matchers {
60-
if datetime_matcher.match_datetime(datetime) {
61-
routes.extend(matcher.match_request(request));
102+
'group: for (conditions, matcher) in &self.condition_groups {
103+
for condition in conditions {
104+
match execute_conditions.get(condition) {
105+
None => {
106+
// Execute condition
107+
let result = condition.match_value(datetime);
108+
109+
// Save result
110+
execute_conditions.insert(condition.clone(), result);
111+
112+
if !result {
113+
continue 'group;
114+
}
115+
}
116+
Some(result) => {
117+
if !result {
118+
continue 'group;
119+
}
120+
}
121+
}
62122
}
123+
124+
rules.extend(matcher.match_request(request));
63125
}
64126
}
65127

66-
routes
128+
rules
67129
}
68130

69131
fn trace(&self, request: &Request) -> Vec<Trace<T>> {
70-
let mut traces = self.no_matcher.trace(request);
132+
let mut traces = self.any_datetime.trace(request);
133+
let mut execute_conditions = BTreeMap::new();
71134

72135
if let Some(datetime) = request.created_at.as_ref() {
73-
for (datetime_matcher, matcher) in &self.matchers {
74-
if datetime_matcher.match_datetime(datetime) {
75-
let datetime_traces = matcher.trace(request);
76-
77-
traces.push(Trace::new(
78-
true,
79-
true,
80-
matcher.len() as u64,
81-
datetime_traces,
82-
TraceInfo::DateTime {
83-
request: datetime.to_string(),
84-
against: datetime_matcher.to_string(),
85-
},
86-
));
87-
} else {
88-
traces.push(Trace::new(
89-
false,
90-
true,
91-
matcher.len() as u64,
92-
Vec::new(),
93-
TraceInfo::DateTime {
94-
request: datetime.to_string(),
95-
against: datetime_matcher.to_string(),
96-
},
97-
))
136+
for (conditions, matcher) in &self.condition_groups {
137+
let mut matched = true;
138+
let mut executed = true;
139+
let mut traces_info_datetime = Vec::new();
140+
141+
for condition in conditions {
142+
match execute_conditions.get(condition) {
143+
None => {
144+
// Execute condition
145+
let result = condition.match_value(datetime);
146+
matched = matched && result;
147+
148+
// Save result (only if executed to mimic cache behavior)
149+
if executed {
150+
execute_conditions.insert(condition.clone(), matched);
151+
}
152+
153+
traces_info_datetime.push(TraceInfoDateTimeCondition {
154+
result: if executed { Some(result) } else { None },
155+
condition: condition.clone(),
156+
against: datetime.clone(),
157+
cached: false,
158+
});
159+
160+
executed = matched;
161+
}
162+
Some(result) => {
163+
matched = matched && *result;
164+
165+
traces_info_datetime.push(TraceInfoDateTimeCondition {
166+
result: if executed { Some(*result) } else { None },
167+
condition: condition.clone(),
168+
against: datetime.clone(),
169+
cached: true,
170+
});
171+
172+
executed = matched;
173+
}
174+
}
98175
}
176+
177+
traces.push(Trace::new(
178+
matched,
179+
true,
180+
matcher.len() as u64,
181+
if matched { matcher.trace(request) } else { Vec::new() },
182+
TraceInfo::DateTimeGroup {
183+
conditions: traces_info_datetime,
184+
},
185+
));
99186
}
100187
}
101188

102189
traces
103190
}
104191

105192
fn cache(&mut self, limit: u64, level: u64) -> u64 {
106-
let mut new_limit = self.no_matcher.cache(limit, level);
193+
let mut new_limit = limit;
107194

108-
for matcher in self.matchers.values_mut() {
195+
for matcher in self.condition_groups.values_mut() {
109196
new_limit = matcher.cache(new_limit, level);
110197
}
111198

112-
new_limit
199+
self.any_datetime.cache(new_limit, level)
113200
}
114201

115202
fn len(&self) -> usize {
@@ -128,15 +215,40 @@ impl<T: RouteData> RequestMatcher<T> for DateTimeMatcher<T> {
128215
impl<T: RouteData> Default for DateTimeMatcher<T> {
129216
fn default() -> Self {
130217
DateTimeMatcher {
131-
matchers: HashMap::new(),
132-
no_matcher: Self::create_sub_matcher(),
218+
any_datetime: DateTimeMatcher::create_sub_matcher(),
219+
conditions: BTreeSet::new(),
220+
condition_groups: BTreeMap::new(),
133221
count: 0,
134222
}
135223
}
136224
}
137225

138226
impl<T: RouteData> DateTimeMatcher<T> {
139227
pub fn create_sub_matcher() -> Box<dyn RequestMatcher<T>> {
140-
Box::<WeekdayMatcher<T>>::default()
228+
Box::<MethodMatcher<T>>::default()
229+
}
230+
}
231+
232+
impl DateTimeCondition {
233+
pub fn match_value(&self, datetime: &DateTime<Utc>) -> bool {
234+
match self {
235+
DateTimeCondition::DateTimeRange(route_date_time) => {
236+
for range in route_date_time {
237+
if range.match_datetime(datetime) {
238+
return true;
239+
}
240+
}
241+
return false;
242+
},
243+
DateTimeCondition::TimeRange(route_time) => {
244+
for range in route_time {
245+
if range.match_datetime(datetime) {
246+
return true;
247+
}
248+
}
249+
return false;
250+
},
251+
DateTimeCondition::Weekdays(route_weekday) => route_weekday.match_datetime(datetime),
252+
}
141253
}
142254
}

src/router/request_matcher/mod.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,19 @@ mod method;
77
mod path_and_query;
88
mod route_matcher;
99
mod scheme;
10-
mod time;
11-
mod weekday;
1210

1311
use crate::http::Request;
1412
use crate::router::{Route, RouteData, Trace};
1513
use std::fmt::Debug;
1614

17-
pub use datetime::DateTimeMatcher;
15+
pub use datetime::{DateTimeMatcher, DateTimeCondition};
1816
pub use header::{HeaderMatcher, ValueCondition as HeaderValueCondition};
1917
pub use host::HostMatcher;
2018
pub use ip::IpMatcher;
2119
pub use method::MethodMatcher;
2220
pub use path_and_query::PathAndQueryMatcher;
2321
pub use route_matcher::RouteMatcher;
2422
pub use scheme::SchemeMatcher;
25-
pub use time::TimeMatcher;
26-
pub use weekday::WeekdayMatcher;
2723

2824
pub trait RequestMatcher<T: RouteData>: Debug + Send + Sync {
2925
fn insert(&mut self, route: Route<T>);

0 commit comments

Comments
 (0)