1use humantime::parse_duration;
16use pingap_config::PluginConf;
17use pingap_core::PluginStep;
18use snafu::Snafu;
19use std::fmt::Write;
20use std::str::FromStr;
21use std::time::Duration;
22
23#[derive(Debug, Snafu)]
24pub enum Error {
25 #[snafu(display("Plugin {category} invalid, message: {message}"))]
26 Invalid { category: String, message: String },
27 #[snafu(display("Plugin {category} not found"))]
28 NotFound { category: String },
29 #[snafu(display("Plugin {category}, base64 decode error {source}"))]
30 Base64Decode {
31 category: String,
32 source: base64::DecodeError,
33 },
34 #[snafu(display("Plugin {category}, exceed limit {value}/{max}"))]
35 Exceed {
36 category: String,
37 max: f64,
38 value: f64,
39 },
40 #[snafu(display("Plugin {category}, regex error {source}"))]
41 Regex {
42 category: String,
43 source: Box<fancy_regex::Error>,
44 },
45 #[snafu(display("Plugin {category}, base64 decode error {source}"))]
46 ParseDuration {
47 category: String,
48 source: humantime::DurationError,
49 },
50}
51
52pub fn get_str_conf(value: &PluginConf, key: &str) -> String {
54 value
55 .get(key)
56 .and_then(|v| v.as_str())
57 .unwrap_or("")
58 .to_string()
59}
60
61pub fn get_duration_conf(value: &PluginConf, key: &str) -> Option<Duration> {
63 value
64 .get(key)
65 .and_then(|v| v.as_str())
66 .and_then(|s| parse_duration(s).ok())
67}
68
69pub(crate) fn get_str_slice_conf(value: &PluginConf, key: &str) -> Vec<String> {
70 value
71 .get(key)
72 .and_then(|v| v.as_array())
73 .map(|arr| {
74 arr.iter()
75 .filter_map(|item| item.as_str())
76 .map(String::from) .collect()
78 })
79 .unwrap_or_default()
80}
81
82pub(crate) fn get_bool_conf(value: &PluginConf, key: &str) -> bool {
83 value.get(key).and_then(|v| v.as_bool()).unwrap_or(false)
84}
85
86pub fn get_int_conf(value: &PluginConf, key: &str) -> i64 {
87 get_int_conf_or_default(value, key, 0)
88}
89
90pub fn get_int_conf_or_default(
91 value: &PluginConf,
92 key: &str,
93 default_value: i64,
94) -> i64 {
95 value
96 .get(key)
97 .and_then(|v| v.as_integer()) .unwrap_or(default_value)
99}
100
101pub(crate) fn get_step_conf(
102 value: &PluginConf,
103 default_value: PluginStep,
104) -> PluginStep {
105 value
106 .get("step")
107 .and_then(|v| v.as_str())
108 .and_then(|s| PluginStep::from_str(s).ok())
109 .unwrap_or(default_value)
110}
111
112pub fn get_hash_key(conf: &PluginConf) -> String {
120 let mut items: Vec<_> = conf.iter().collect();
121 items.sort_unstable_by_key(|(k, _)| *k);
123
124 let mut buf = String::with_capacity(256);
126 for (i, (key, value)) in items.iter().enumerate() {
127 if i > 0 {
128 buf.push('\n');
129 }
130 let _ = write!(&mut buf, "{key}:{value}");
133 }
134
135 let hash = crc32fast::hash(buf.as_bytes());
136 format!("{hash:X}")
137}
138
139mod accept_encoding;
140mod basic_auth;
141mod cache;
142mod combined_auth;
143mod compression;
144mod cors;
145mod csrf;
146mod directory;
147mod ip_restriction;
148mod jwt;
149mod key_auth;
150mod limit;
151mod mock;
152mod ping;
153mod redirect;
154mod referer_restriction;
155mod request_id;
156mod response_headers;
157mod sub_filter;
158mod traffic_splitting;
159mod ua_restriction;
160
161mod plugin;
162
163pub use plugin::get_plugin_factory;