use async_trait::async_trait;
use alun_core::{Plugin, Result};
use std::collections::HashMap;
use std::sync::Arc;
use parking_lot::RwLock;
type JobFn = Box<dyn Fn() -> tokio::task::JoinHandle<()> + Send + Sync>;
pub struct SchedulerPlugin {
jobs: Arc<RwLock<HashMap<String, ScheduledJob>>>,
}
struct ScheduledJob {
cron: String,
description: String,
runner: JobFn,
}
impl SchedulerPlugin {
pub fn new() -> Self {
Self { jobs: Arc::new(RwLock::new(HashMap::new())) }
}
pub fn register<F>(
&self,
name: &str,
cron: &str,
desc: &str,
runner: F,
) where
F: Fn() -> tokio::task::JoinHandle<()> + Send + Sync + 'static,
{
self.jobs.write().insert(name.to_string(), ScheduledJob {
cron: cron.to_string(),
description: desc.to_string(),
runner: Box::new(runner),
});
}
pub fn remove(&self, name: &str) {
self.jobs.write().remove(name);
}
pub fn list(&self) -> Vec<(String, String, String)> {
self.jobs.read()
.iter()
.map(|(k, v)| (k.clone(), v.cron.clone(), v.description.clone()))
.collect()
}
pub fn trigger(&self, name: &str) -> Option<tokio::task::JoinHandle<()>> {
let guard = self.jobs.read();
guard.get(name).map(|job| (job.runner)())
}
}
#[async_trait]
impl Plugin for SchedulerPlugin {
fn name(&self) -> &str { "scheduler" }
async fn start(&self) -> Result<()> {
let count = self.jobs.read().len();
tracing::info!("定时任务插件: {} 个任务已注册", count);
for (name, job) in self.jobs.read().iter() {
tracing::info!(" - {} [{}] {}", name, job.cron, job.description);
}
Ok(())
}
async fn stop(&self) -> Result<()> {
tracing::info!("定时任务插件: 已停止");
Ok(())
}
}
impl Default for SchedulerPlugin {
fn default() -> Self { Self::new() }
}