1use async_trait::async_trait;
2use crate::error::Result;
3
4#[async_trait]
32pub trait Plugin: Send + Sync {
33 fn name(&self) -> &str;
35
36 async fn start(&self) -> Result<()>;
41
42 async fn stop(&self) -> Result<()>;
47
48 fn depends_on(&self) -> &[&str] {
52 &[]
53 }
54}
55
56use std::collections::{HashMap, HashSet, VecDeque};
57use tracing::{info, error};
58
59pub struct PluginManager {
72 plugins: Vec<Box<dyn Plugin>>,
73}
74
75impl PluginManager {
76 pub fn new() -> Self {
78 Self { plugins: Vec::new() }
79 }
80
81 pub fn add<P: Plugin + 'static>(mut self, plugin: P) -> Self {
91 self.plugins.push(Box::new(plugin));
92 self
93 }
94
95 pub fn add_discovered(mut self, plugins: Vec<Box<dyn Plugin>>) -> Self {
99 self.plugins.extend(plugins);
100 self
101 }
102
103 pub async fn start_all(&self) -> Result<()> {
107 let ordered = self.topological_sort()?;
108
109 for plugin in ordered {
110 info!("启动插件: {}", plugin.name());
111 if let Err(e) = plugin.start().await {
112 error!("插件 {} 启动失败: {}", plugin.name(), e);
113 return Err(e);
114 }
115 }
116
117 Ok(())
118 }
119
120 pub async fn stop_all(&self) {
124 for plugin in self.plugins.iter().rev() {
125 info!("停止插件: {}", plugin.name());
126 if let Err(e) = plugin.stop().await {
127 error!("插件 {} 停止异常: {}", plugin.name(), e);
128 }
129 }
130 }
131
132 fn topological_sort(&self) -> Result<Vec<&Box<dyn Plugin>>> {
136 let name_to_idx: HashMap<&str, usize> = self.plugins
137 .iter()
138 .enumerate()
139 .map(|(i, p)| (p.name(), i))
140 .collect();
141
142 let count = self.plugins.len();
143 let mut in_degree = vec![0usize; count];
144 let mut adj = vec![Vec::new(); count];
145
146 for (i, plugin) in self.plugins.iter().enumerate() {
147 for dep in plugin.depends_on() {
148 if let Some(&j) = name_to_idx.get(dep) {
149 adj[j].push(i);
150 in_degree[i] += 1;
151 }
152 }
153 }
154
155 let mut queue: VecDeque<usize> = (0..count)
156 .filter(|&i| in_degree[i] == 0)
157 .collect();
158
159 let mut sorted = Vec::with_capacity(count);
160 while let Some(u) = queue.pop_front() {
161 sorted.push(&self.plugins[u]);
162 for &v in &adj[u] {
163 in_degree[v] -= 1;
164 if in_degree[v] == 0 {
165 queue.push_back(v);
166 }
167 }
168 }
169
170 if sorted.len() != count {
171 let cycle: Vec<&str> = self.plugins.iter()
173 .enumerate()
174 .filter(|(i, _)| in_degree[*i] > 0)
175 .map(|(_, p)| p.name())
176 .collect();
177 return Err(crate::error::Error::Config(
178 format!("插件循环依赖: {:?}", cycle)
179 ));
180 }
181
182 Ok(sorted)
183 }
184
185 pub fn check_duplicate_names(&self) -> std::result::Result<(), String> {
187 let mut seen = HashSet::new();
188 for p in &self.plugins {
189 if !seen.insert(p.name()) {
190 return Err(format!("插件名重复: {}", p.name()));
191 }
192 }
193 Ok(())
194 }
195}
196
197impl Default for PluginManager {
198 fn default() -> Self {
199 Self::new()
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206 use async_trait::async_trait;
207 use parking_lot::Mutex;
208 use std::sync::Arc;
209
210 struct TestPlugin {
211 name: &'static str,
212 deps: &'static [&'static str],
213 order: Arc<Mutex<Vec<String>>>,
214 }
215
216 #[async_trait]
217 impl Plugin for TestPlugin {
218 fn name(&self) -> &str { self.name }
219 async fn start(&self) -> Result<()> {
220 self.order.lock().push(format!("start:{}", self.name));
221 Ok(())
222 }
223 async fn stop(&self) -> Result<()> {
224 self.order.lock().push(format!("stop:{}", self.name));
225 Ok(())
226 }
227 fn depends_on(&self) -> &[&str] { self.deps }
228 }
229
230 #[tokio::test]
231 async fn test_topological_start() {
232 let order = Arc::new(Mutex::new(Vec::new()));
233
234 let mgr = PluginManager::new()
235 .add(TestPlugin {
236 name: "c", deps: &["a", "b"],
237 order: order.clone(),
238 })
239 .add(TestPlugin {
240 name: "b", deps: &["a"],
241 order: order.clone(),
242 })
243 .add(TestPlugin {
244 name: "a", deps: &[],
245 order: order.clone(),
246 });
247
248 mgr.start_all().await.unwrap();
249
250 let log = order.lock();
251 assert_eq!(log[0], "start:a");
252 assert_eq!(log[1], "start:b");
253 assert_eq!(log[2], "start:c");
254 }
255
256 #[tokio::test]
257 async fn test_cycle_detection() {
258 let order = Arc::new(Mutex::new(Vec::new()));
259
260 let mgr = PluginManager::new()
261 .add(TestPlugin {
262 name: "x", deps: &["y"],
263 order: order.clone(),
264 })
265 .add(TestPlugin {
266 name: "y", deps: &["x"],
267 order: order.clone(),
268 });
269
270 let result = mgr.start_all().await;
271 assert!(result.is_err());
272 }
273}