use humantime::parse_duration;
use pingap_config::PluginConf;
use pingap_core::PluginStep;
use snafu::Snafu;
use std::fmt::Write;
use std::str::FromStr;
use std::time::Duration;
#[derive(Debug, Snafu)]
pub enum Error {
#[snafu(display("Plugin {category} invalid, message: {message}"))]
Invalid { category: String, message: String },
#[snafu(display("Plugin {category} not found"))]
NotFound { category: String },
#[snafu(display("Plugin {category}, base64 decode error {source}"))]
Base64Decode {
category: String,
source: base64::DecodeError,
},
#[snafu(display("Plugin {category}, exceed limit {value}/{max}"))]
Exceed {
category: String,
max: f64,
value: f64,
},
#[snafu(display("Plugin {category}, regex error {source}"))]
Regex {
category: String,
source: Box<fancy_regex::Error>,
},
#[snafu(display("Plugin {category}, base64 decode error {source}"))]
ParseDuration {
category: String,
source: humantime::DurationError,
},
}
pub fn get_str_conf(value: &PluginConf, key: &str) -> String {
value
.get(key)
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string()
}
pub fn get_duration_conf(value: &PluginConf, key: &str) -> Option<Duration> {
value
.get(key)
.and_then(|v| v.as_str())
.and_then(|s| parse_duration(s).ok())
}
pub(crate) fn get_str_slice_conf(value: &PluginConf, key: &str) -> Vec<String> {
value
.get(key)
.and_then(|v| v.as_array())
.map(|arr| {
arr.iter()
.filter_map(|item| item.as_str())
.map(String::from) .collect()
})
.unwrap_or_default()
}
pub(crate) fn get_bool_conf(value: &PluginConf, key: &str) -> bool {
value.get(key).and_then(|v| v.as_bool()).unwrap_or(false)
}
pub fn get_int_conf(value: &PluginConf, key: &str) -> i64 {
get_int_conf_or_default(value, key, 0)
}
pub fn get_int_conf_or_default(
value: &PluginConf,
key: &str,
default_value: i64,
) -> i64 {
value
.get(key)
.and_then(|v| v.as_integer()) .unwrap_or(default_value)
}
pub(crate) fn get_step_conf(
value: &PluginConf,
default_value: PluginStep,
) -> PluginStep {
value
.get("step")
.and_then(|v| v.as_str())
.and_then(|s| PluginStep::from_str(s).ok())
.unwrap_or(default_value)
}
pub fn get_hash_key(conf: &PluginConf) -> String {
let mut items: Vec<_> = conf.iter().collect();
items.sort_unstable_by_key(|(k, _)| *k);
let mut buf = String::with_capacity(256);
for (i, (key, value)) in items.iter().enumerate() {
if i > 0 {
buf.push('\n');
}
let _ = write!(&mut buf, "{key}:{value}");
}
let hash = crc32fast::hash(buf.as_bytes());
format!("{hash:X}")
}
mod accept_encoding;
mod basic_auth;
mod cache;
mod combined_auth;
mod compression;
mod cors;
mod csrf;
mod directory;
mod ip_restriction;
mod jwt;
mod key_auth;
mod limit;
mod mock;
mod ping;
mod redirect;
mod referer_restriction;
mod request_id;
mod response_headers;
mod sub_filter;
mod traffic_splitting;
mod ua_restriction;
mod plugin;
pub use plugin::get_plugin_factory;