use std::sync::Arc;
use async_trait::async_trait;
use alun_core::{Plugin, Result as CoreResult};
use alun_config::SerialConfig;
use alun_utils::{SerialGenerator, SerialRule, MemorySerialBackend, CyclePeriod, IncrementStrategy};
use tracing::info;
pub struct SerialPlugin {
config: SerialConfig,
generator: parking_lot::RwLock<Option<Arc<dyn SerialGenerator>>>,
preset_generator: Option<Arc<dyn SerialGenerator>>,
}
impl SerialPlugin {
pub fn new(config: SerialConfig, generator: Arc<dyn SerialGenerator>) -> Self {
Self {
preset_generator: Some(generator),
generator: parking_lot::RwLock::new(None),
config,
}
}
pub fn with_memory(config: SerialConfig) -> Self {
Self {
config,
generator: parking_lot::RwLock::new(None),
preset_generator: None,
}
}
pub fn generator(&self) -> Arc<dyn SerialGenerator> {
self.generator.read().clone()
.expect("SerialPlugin 尚未启动,请确保插件已注册并启动")
}
fn convert_rule(rc: &alun_config::SerialRuleConfig) -> SerialRule {
let cycle = match rc.cycle.as_str() {
"daily" => CyclePeriod::Daily,
"monthly" => CyclePeriod::Monthly,
"yearly" => CyclePeriod::Yearly,
_ => CyclePeriod::NoCycle,
};
let step = if let Some(max_str) = rc.step.strip_prefix("random:") {
let max: u64 = max_str.parse().unwrap_or(1);
IncrementStrategy::Random { max }
} else {
IncrementStrategy::Sequential
};
SerialRule {
key: rc.key.clone(),
format: rc.format.clone(),
cycle,
initial_value: rc.initial_value,
step,
is_enabled: true,
}
}
}
#[async_trait]
impl Plugin for SerialPlugin {
fn name(&self) -> &str { "serial" }
async fn start(&self) -> CoreResult<()> {
let gen = self.preset_generator.clone()
.unwrap_or_else(|| {
info!("单号生成器使用 memory 后端(默认)");
Arc::new(MemorySerialBackend::new())
});
for rc in &self.config.rules {
let rule = Self::convert_rule(rc);
gen.register_rule(rule.clone()).await
.map_err(|e| alun_core::Error::Msg(
format!("注册单号规则 '{}' 失败: {}", rule.key, e)
))?;
info!("单号规则已注册: key={}, format={}", rule.key, rule.format);
}
*self.generator.write() = Some(gen);
let rule_count = self.config.rules.len();
info!("单号生成器就绪,后端={}, 规则数={}", self.config.backend, rule_count);
Ok(())
}
async fn stop(&self) -> CoreResult<()> {
info!("单号生成器插件已停止");
Ok(())
}
}