use crate::Result;
use crate::config::PluginConfig;
use crate::plugin::Context;
use async_trait::async_trait;
use std::any::Any;
use std::fmt::Debug;
use std::sync::Arc;
#[async_trait]
pub trait Plugin: Send + Sync + Debug + Any + 'static {
async fn execute(&self, _ctx: &mut Context) -> Result<()> {
Ok(())
}
fn name(&self) -> &str;
fn tag(&self) -> Option<&str> {
None
}
fn display_name(&self) -> &str {
self.tag().unwrap_or(self.name())
}
fn should_execute(&self, _ctx: &Context) -> bool {
true
}
fn priority(&self) -> i32 {
100
}
fn as_any(&self) -> &dyn Any {
&()
}
fn init(_config: &PluginConfig) -> Result<Arc<dyn Plugin>>
where
Self: Sized,
{
Err(crate::Error::Config(format!(
"no builder for plugin {}",
std::any::type_name::<Self>()
)))
}
fn aliases() -> &'static [&'static str]
where
Self: Sized,
{
&[]
}
fn as_shutdown(&self) -> Option<&dyn Shutdown> {
None
}
}
pub trait ExecPlugin: Plugin {
fn quick_setup(prefix: &str, exec_str: &str) -> Result<Arc<dyn Plugin>>
where
Self: Sized;
}
#[async_trait]
pub trait Shutdown: Send + Sync {
async fn shutdown(&self) -> Result<()>;
}
#[async_trait]
pub trait Matcher: Plugin {
fn matches_context(&self, ctx: &Context) -> bool;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::dns::Message;
#[derive(Debug)]
struct TestPlugin {
name: String,
priority: i32,
}
#[async_trait]
impl Plugin for TestPlugin {
async fn execute(&self, _ctx: &mut Context) -> Result<()> {
Ok(())
}
fn name(&self) -> &str {
&self.name
}
fn priority(&self) -> i32 {
self.priority
}
}
#[tokio::test]
async fn test_plugin_trait() {
let plugin = TestPlugin {
name: "test".to_string(),
priority: 50,
};
assert_eq!(plugin.name(), "test");
assert_eq!(plugin.priority(), 50);
let request = Message::new();
let mut ctx = Context::new(request);
assert!(plugin.should_execute(&ctx));
assert!(plugin.execute(&mut ctx).await.is_ok());
}
#[test]
fn test_default_priority() {
let plugin = TestPlugin {
name: "test".to_string(),
priority: 100,
};
assert_eq!(plugin.priority(), 100);
}
}