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 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
}
fn spawn_background_task(&self) -> Option<tokio::task::JoinHandle<()>> {
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<()>;
}
pub trait BackgroundTask: Send + Sync {
fn background_task_interval(&self) -> std::time::Duration;
fn run_background_task(&self);
fn background_task_name(&self) -> &str;
fn spawn_background_task(self: Arc<Self>) -> tokio::task::JoinHandle<()>
where
Self: 'static,
{
let interval = self.background_task_interval();
let name = self.background_task_name().to_string();
tokio::spawn(async move {
let mut timer = tokio::time::interval(interval);
loop {
timer.tick().await;
tracing::trace!(task = %name, "Running background task");
self.run_background_task();
}
})
}
}
#[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,
}
#[async_trait]
impl Plugin for TestPlugin {
async fn execute(&self, _ctx: &mut Context) -> Result<()> {
Ok(())
}
fn name(&self) -> &str {
&self.name
}
}
#[tokio::test]
async fn test_plugin_trait() {
let plugin = TestPlugin {
name: "test".to_string(),
};
assert_eq!(plugin.name(), "test");
let request = Message::new();
let mut ctx = Context::new(request);
assert!(plugin.should_execute(&ctx));
assert!(plugin.execute(&mut ctx).await.is_ok());
}
}