use crate::comm::ExecuteContext;
use crate::interceptor::{InterceptorConfig, InterceptorConfigItem};
use crate::interceptor_err;
use akita_core::{InterceptorType, OperationType};
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
pub trait InterceptorBase: Send + Sync {
fn name(&self) -> &'static str;
fn interceptor_type(&self) -> InterceptorType;
fn order(&self) -> i32 {
0
}
fn supports_operation(&self, operation: &OperationType) -> bool {
match operation {
OperationType::Call => false,
_ => true,
}
}
fn will_ignore_table(&self, _table_name: &str) -> bool {
false
}
}
pub fn sort_interceptors_by_order(interceptors: &mut [Arc<dyn InterceptorBase>]) {
interceptors.sort_by(|a, b| a.order().cmp(&b.order()));
}
pub fn should_skip_interceptor(interceptor: &dyn InterceptorBase, ctx: &ExecuteContext) -> bool {
if interceptor.will_ignore_table(&ctx.table_info().name) {
return true;
}
if !interceptor.supports_operation(&ctx.operation_type()) {
return true;
}
if ctx
.skip_next_interceptors()
.contains(&interceptor.interceptor_type())
{
return true;
}
false
}
pub fn check_depth_limit(
depth: &mut usize,
config: &InterceptorConfig,
) -> crate::errors::Result<()> {
*depth += 1;
if *depth > config.max_interceptor_depth {
return Err(interceptor_err!("Interceptor chain too deep".to_string()));
}
Ok(())
}
pub struct InterceptorEntry {
pub interceptor: Arc<dyn InterceptorBase>,
pub config: InterceptorConfigItem,
}
pub mod builder_helpers {
use super::*;
pub fn register_interceptor(
interceptors: &mut HashMap<String, InterceptorEntry>,
interceptor: Arc<dyn InterceptorBase>,
) {
let name = interceptor.name().to_string();
let config_item = InterceptorConfigItem {
enabled: false,
order: interceptor.order(),
ignored_tables: HashSet::new(),
supported_operations: HashSet::new(),
};
interceptors.insert(
name,
InterceptorEntry {
interceptor,
config: config_item,
},
);
}
pub fn enable_interceptor(
interceptors: &mut HashMap<String, InterceptorEntry>,
name: &str,
) -> crate::errors::Result<()> {
if let Some(entry) = interceptors.get_mut(name) {
entry.config.enabled = true;
Ok(())
} else {
Err(interceptor_err!(format!(
"Interceptor '{}' not found",
name
)))
}
}
pub fn disable_interceptor(
interceptors: &mut HashMap<String, InterceptorEntry>,
name: &str,
) -> crate::errors::Result<()> {
if let Some(entry) = interceptors.get_mut(name) {
entry.config.enabled = false;
Ok(())
} else {
Err(interceptor_err!(format!(
"Interceptor '{}' not found",
name
)))
}
}
pub fn set_interceptor_order(
interceptors: &mut HashMap<String, InterceptorEntry>,
name: &str,
order: i32,
) -> crate::errors::Result<()> {
if let Some(entry) = interceptors.get_mut(name) {
entry.config.order = order;
Ok(())
} else {
Err(interceptor_err!(format!(
"Interceptor '{}' not found",
name
)))
}
}
pub fn ignore_table(
interceptors: &mut HashMap<String, InterceptorEntry>,
name: &str,
table: &str,
) -> crate::errors::Result<()> {
if let Some(entry) = interceptors.get_mut(name) {
entry.config.ignored_tables.insert(table.to_string());
Ok(())
} else {
Err(interceptor_err!(format!(
"Interceptor '{}' not found",
name
)))
}
}
pub fn set_operations(
interceptors: &mut HashMap<String, InterceptorEntry>,
name: &str,
operations: &[OperationType],
) -> crate::errors::Result<()> {
if let Some(entry) = interceptors.get_mut(name) {
entry.config.supported_operations = operations.iter().cloned().collect();
Ok(())
} else {
Err(interceptor_err!(format!(
"Interceptor '{}' not found",
name
)))
}
}
pub fn get_enabled_interceptors(
interceptors: &HashMap<String, InterceptorEntry>,
) -> Vec<(Arc<dyn InterceptorBase>, InterceptorConfigItem)> {
let mut enabled: Vec<_> = interceptors
.iter()
.filter(|(_, entry)| entry.config.enabled)
.map(|(_, entry)| (entry.interceptor.clone(), entry.config.clone()))
.collect();
enabled.sort_by(|(_, a), (_, b)| a.order.cmp(&b.order));
enabled
}
pub fn registered_interceptors(interceptors: &HashMap<String, InterceptorEntry>) -> Vec<&str> {
interceptors.keys().map(|s| s.as_str()).collect()
}
pub fn is_registered(interceptors: &HashMap<String, InterceptorEntry>, name: &str) -> bool {
interceptors.contains_key(name)
}
pub fn is_enabled(interceptors: &HashMap<String, InterceptorEntry>, name: &str) -> bool {
interceptors
.get(name)
.map(|entry| entry.config.enabled)
.unwrap_or(false)
}
}
pub mod presets {
use super::InterceptorConfig;
pub fn development() -> InterceptorConfig {
InterceptorConfig {
enable_async: true,
enable_metrics: true,
enable_tracing: true,
max_interceptor_depth: 20,
timeout_ms: 10000,
}
}
pub fn production() -> InterceptorConfig {
InterceptorConfig {
enable_async: true,
enable_metrics: true,
enable_tracing: false,
max_interceptor_depth: 10,
timeout_ms: 5000,
}
}
pub fn high_security() -> InterceptorConfig {
InterceptorConfig {
enable_async: true,
enable_metrics: true,
enable_tracing: true,
max_interceptor_depth: 15,
timeout_ms: 8000,
}
}
}