use crate::filters::{
LinesFilter, RegexFilter, SimilarityFilter, SizeFilter, StatusCodeFilter, WildcardFilter,
WordsFilter,
};
use crate::response::FeroxResponse;
use crate::utils::status_colorizer;
use anyhow::Result;
use crossterm::style::{style, Stylize};
use serde::Serialize;
use std::any::Any;
use std::fmt::{self, Debug, Display, Formatter};
pub trait FeroxFilter: Debug + Send + Sync {
fn should_filter_response(&self, response: &FeroxResponse) -> bool;
fn box_eq(&self, other: &dyn Any) -> bool;
fn as_any(&self) -> &dyn Any;
}
impl Display for dyn FeroxFilter {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
if let Some(filter) = self.as_any().downcast_ref::<LinesFilter>() {
write!(f, "Line count: {}", style(filter.line_count).cyan())
} else if let Some(filter) = self.as_any().downcast_ref::<WordsFilter>() {
write!(f, "Word count: {}", style(filter.word_count).cyan())
} else if let Some(filter) = self.as_any().downcast_ref::<SizeFilter>() {
write!(f, "Response size: {}", style(filter.content_length).cyan())
} else if let Some(filter) = self.as_any().downcast_ref::<RegexFilter>() {
write!(f, "Regex: {}", style(&filter.raw_string).cyan())
} else if let Some(filter) = self.as_any().downcast_ref::<WildcardFilter>() {
let mut msg = format!(
"{} requests with {} responses ",
style(&filter.method).cyan(),
status_colorizer(&filter.status_code.to_string())
);
match (filter.content_length, filter.word_count, filter.line_count) {
(None, None, None) => {
unreachable!("wildcard filter without any filters set");
}
(None, None, Some(lc)) => {
msg.push_str(&format!("containing {lc} lines"));
}
(None, Some(wc), None) => {
msg.push_str(&format!("containing {wc} words"));
}
(None, Some(wc), Some(lc)) => {
msg.push_str(&format!("containing {wc} words and {lc} lines"));
}
(Some(cl), None, None) => {
msg.push_str(&format!("containing {cl} bytes"));
}
(Some(cl), None, Some(lc)) => {
msg.push_str(&format!("containing {cl} bytes and {lc} lines"));
}
(Some(cl), Some(wc), None) => {
msg.push_str(&format!("containing {cl} bytes and {wc} words"));
}
(Some(cl), Some(wc), Some(lc)) => {
msg.push_str(&format!(
"containing {cl} bytes, {wc} words, and {lc} lines"
));
}
}
write!(f, "{msg}")
} else if let Some(filter) = self.as_any().downcast_ref::<StatusCodeFilter>() {
write!(f, "Status code: {}", style(filter.filter_code).cyan())
} else if let Some(filter) = self.as_any().downcast_ref::<SimilarityFilter>() {
write!(
f,
"Pages similar to: {}",
style(&filter.original_url).cyan()
)
} else {
write!(f, "Filter: {self:?}")
}
}
}
impl PartialEq for Box<dyn FeroxFilter> {
fn eq(&self, other: &Box<dyn FeroxFilter>) -> bool {
self.box_eq(other.as_any())
}
}
pub trait FeroxSerialize: Serialize {
fn as_str(&self) -> String;
fn as_json(&self) -> Result<String>;
}