use std::hash::Hash;
use std::hash::Hasher;
use std::{hash::DefaultHasher, path::PathBuf, time::Duration};
pub use rswappalyzer_engine::RegexCacheConfig;
pub use rswappalyzer_engine::regex_cache_config::RegexCache;
#[derive(Debug, Clone, PartialEq)]
pub enum RuleSource {
Embedded, LocalFile(PathBuf), RemoteOfficial, RemoteCustom(String), }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RuleStage {
Raw, Compiled, Cached, }
#[derive(Debug, Clone)]
pub struct RuleOrigin {
pub source: RuleSource,
pub stage: RuleStage,
}
impl RuleOrigin {
pub fn embedded() -> Self {
Self {
source: RuleSource::Embedded,
stage: RuleStage::Compiled, }
}
pub fn local_file(path: impl Into<PathBuf>) -> Self {
Self {
source: RuleSource::LocalFile(path.into()),
stage: RuleStage::Raw, }
}
pub fn remote_official() -> Self {
Self {
source: RuleSource::RemoteOfficial,
stage: RuleStage::Raw, }
}
pub fn remote_custom(url: impl Into<String>) -> Self {
Self {
source: RuleSource::RemoteCustom(url.into()),
stage: RuleStage::Raw, }
}
pub fn local_compiled_file(path: impl Into<PathBuf>) -> Self {
Self {
source: RuleSource::LocalFile(path.into()),
stage: RuleStage::Compiled,
}
}
pub fn local_cached_file(path: impl Into<PathBuf>) -> Self {
Self {
source: RuleSource::LocalFile(path.into()),
stage: RuleStage::Cached, }
}
}
#[derive(Debug, Clone)]
pub enum RuleLoadMethod {
Embedded, CacheDir(PathBuf), }
#[derive(Debug, Clone)]
pub struct RemoteOptions {
pub urls: Vec<String>, pub timeout: Duration, pub retry: RetryPolicy, }
#[derive(Debug, Clone)]
pub enum RetryPolicy {
Never, Times(u8), }
#[derive(Debug, Clone)]
pub struct RuleOptions {
pub check_update: bool,
pub cache_dir: PathBuf,
pub cache_file_name: Option<PathBuf>,
}
impl Default for RuleOptions {
fn default() -> Self {
Self {
check_update: true,
cache_dir: PathBuf::from(".cache/rswappalyzer"),
cache_file_name: None, }
}
}
#[derive(Debug, Clone)]
pub struct RuleConfig {
pub origin: RuleOrigin,
pub load_method: RuleLoadMethod,
pub options: RuleOptions,
pub remote_options: Option<RemoteOptions>,
pub regex_cache_config: RegexCacheConfig,
}
impl Default for RuleConfig {
fn default() -> Self {
Self {
origin: RuleOrigin::embedded(),
load_method: RuleLoadMethod::Embedded,
options: RuleOptions::default(),
remote_options: None,
regex_cache_config: RegexCacheConfig::default(),
}
}
}
impl RuleConfig {
pub fn empty() -> Self {
Self {
origin: RuleOrigin::embedded(), load_method: RuleLoadMethod::Embedded,
options: RuleOptions {
check_update: false, ..RuleOptions::default()
},
remote_options: None,
regex_cache_config: RegexCacheConfig::default(),
}
}
pub fn embedded() -> Self {
Self::default()
}
pub fn local_file(path: impl Into<PathBuf>) -> Self {
let path_buf = path.into();
let cache_dir = RuleOptions::default().cache_dir;
Self {
origin: RuleOrigin::local_file(path_buf),
load_method: RuleLoadMethod::CacheDir(cache_dir),
options: RuleOptions::default(),
remote_options: None,
regex_cache_config: RegexCacheConfig::default(),
}
}
pub fn local_file_with_regex_cache_config(
path: impl Into<PathBuf>,
cache_settings: RegexCacheConfig,
) -> Self {
let mut config = Self::local_file(path);
config.regex_cache_config = cache_settings;
config
}
pub fn local_compiled_file(path: impl Into<PathBuf>) -> Self {
let path_buf = path.into();
let cache_dir = RuleOptions::default().cache_dir;
Self {
origin: RuleOrigin::local_compiled_file(path_buf),
load_method: RuleLoadMethod::CacheDir(cache_dir),
options: RuleOptions {
check_update: false, ..RuleOptions::default()
},
remote_options: None,
regex_cache_config: RegexCacheConfig::default(),
}
}
pub fn local_cached_file(path: impl Into<PathBuf>) -> Self {
let path_buf = path.into();
let cache_dir = RuleOptions::default().cache_dir;
Self {
origin: RuleOrigin::local_cached_file(path_buf),
load_method: RuleLoadMethod::CacheDir(cache_dir),
options: RuleOptions {
check_update: false, ..RuleOptions::default()
},
remote_options: None,
regex_cache_config: RegexCacheConfig::default(),
}
}
pub fn remote_official(timeout: Duration, retry: RetryPolicy) -> Self {
let url = "https://official.source/rules.json".to_string();
let cache_dir = RuleOptions::default().cache_dir;
Self {
origin: RuleOrigin::remote_official(),
load_method: RuleLoadMethod::CacheDir(cache_dir.clone()),
options: RuleOptions::default(),
remote_options: Some(RemoteOptions {
urls: vec![url],
timeout,
retry,
}),
regex_cache_config: RegexCacheConfig::default(),
}
}
pub fn remote_custom(url: impl Into<String>, timeout: Duration, retry: RetryPolicy) -> Self {
let url = url.into();
let cache_dir = RuleOptions::default().cache_dir;
Self {
origin: RuleOrigin::remote_custom(url.clone()),
load_method: RuleLoadMethod::CacheDir(cache_dir.clone()),
options: RuleOptions::default(),
remote_options: Some(RemoteOptions {
urls: vec![url],
timeout,
retry,
}),
regex_cache_config: RegexCacheConfig::default(),
}
}
pub fn get_cache_file_path(&self) -> PathBuf {
if let Some(ref file_name) = self.options.cache_file_name {
return self.options.cache_dir.join(file_name);
}
let file_name = match &self.origin.source {
RuleSource::Embedded => {
PathBuf::from("embedded_rules_unsupported.json")
}
RuleSource::LocalFile(_) => {
match self.origin.stage {
RuleStage::Raw => PathBuf::from("rswappalyzer_rules_cache.json"),
RuleStage::Compiled => PathBuf::from("compiled_rules_unsupported.json"),
RuleStage::Cached => PathBuf::from("cached_rules_unsupported.json"), }
}
RuleSource::RemoteOfficial => PathBuf::from("official_rules.json"),
RuleSource::RemoteCustom(url) => {
let mut hasher = DefaultHasher::new();
url.hash(&mut hasher);
let hash = hasher.finish();
PathBuf::from(format!("custom_{:x}.json", hash))
}
};
self.options.cache_dir.join(file_name)
}
pub fn with_regex_cache_config(mut self, cache_settings: RegexCacheConfig) -> Self {
self.regex_cache_config = cache_settings;
self
}
}
#[derive(Debug, Clone)]
pub struct CustomConfigBuilder {
config: RuleConfig,
}
impl CustomConfigBuilder {
pub fn new() -> Self {
Self {
config: RuleConfig::default(),
}
}
fn apply_load_method(&mut self) {
let cache_dir = self.config.options.cache_dir.clone();
self.config.load_method = match &self.config.origin.source {
RuleSource::Embedded => RuleLoadMethod::Embedded,
RuleSource::LocalFile(_) => RuleLoadMethod::CacheDir(cache_dir),
RuleSource::RemoteOfficial => RuleLoadMethod::CacheDir(cache_dir),
RuleSource::RemoteCustom(_) => RuleLoadMethod::CacheDir(cache_dir),
};
}
pub fn check_update(mut self, check: bool) -> Self {
self.config.options.check_update = check;
self
}
pub fn cache_dir(mut self, path: PathBuf) -> Self {
self.config.options.cache_dir = path;
self
}
pub fn cache_file_name<P: Into<PathBuf>>(mut self, file_name: P) -> Self {
self.config.options.cache_file_name = Some(file_name.into());
self
}
pub fn origin(mut self, origin: RuleOrigin) -> Self {
self.config.origin = origin;
self.apply_load_method();
self
}
pub fn stage(mut self, stage: RuleStage) -> Self {
self.config.origin.stage = stage;
self
}
pub fn local_compiled_file(mut self, path: impl Into<PathBuf>) -> Self {
self.config.origin = RuleOrigin::local_compiled_file(path);
self.config.options.check_update = false;
self.apply_load_method();
self
}
pub fn local_cached_file(mut self, path: impl Into<PathBuf>) -> Self {
self.config.origin = RuleOrigin::local_cached_file(path);
self.config.options.check_update = false;
self.apply_load_method();
self
}
pub fn remote_options(mut self, remote_opts: RemoteOptions) -> Self {
self.config.remote_options = Some(remote_opts);
self
}
pub fn regex_cache_config(mut self, cache_settings: RegexCacheConfig) -> Self {
self.config.regex_cache_config = cache_settings;
self
}
pub fn regex_cache_params(mut self, max_size: usize, ttl_seconds: u64) -> Self {
self.config.regex_cache_config = RegexCacheConfig::new(max_size, ttl_seconds);
self
}
pub fn build(mut self) -> RuleConfig {
self.apply_load_method();
self.config
}
}