mf_state/plugin/
dependency.rs

1use std::collections::{HashMap, HashSet};
2use std::fmt;
3use petgraph::algo::is_cyclic_directed;
4use petgraph::graph::DiGraph;
5use anyhow::Result;
6
7/// 依赖管理器
8#[derive(Debug)]
9pub struct DependencyManager {
10    dependency_graph: DiGraph<String, ()>,
11    node_indices: HashMap<String, petgraph::graph::NodeIndex>,
12}
13
14impl Default for DependencyManager {
15    fn default() -> Self {
16        Self::new()
17    }
18}
19
20impl DependencyManager {
21    pub fn new() -> Self {
22        Self { dependency_graph: DiGraph::new(), node_indices: HashMap::new() }
23    }
24    /// 添加插件节点
25    pub fn add_plugin(
26        &mut self,
27        plugin_name: &str,
28    ) {
29        if !self.node_indices.contains_key(plugin_name) {
30            let idx = self.dependency_graph.add_node(plugin_name.to_string());
31            self.node_indices.insert(plugin_name.to_string(), idx);
32        }
33    }
34    /// 添加依赖关系
35    pub fn add_dependency(
36        &mut self,
37        dependent: &str,
38        dependency: &str,
39    ) -> Result<()> {
40        // 确保节点存在
41        self.add_plugin(dependent);
42        self.add_plugin(dependency);
43
44        // 添加边
45        let dependent_idx = self.node_indices[dependent];
46        let dependency_idx = self.node_indices[dependency];
47        self.dependency_graph.add_edge(dependent_idx, dependency_idx, ());
48
49        Ok(())
50    }
51    /// 检查缺失的依赖 - 直接从图中提取
52    pub fn check_missing_dependencies(&self) -> MissingDependencyReport {
53        let available_plugins: HashSet<String> =
54            self.node_indices.keys().cloned().collect();
55        let mut missing_deps = HashMap::new();
56        let mut total_missing = 0;
57
58        // 遍历图中的所有边,找出缺失的依赖
59        for edge in self.dependency_graph.edge_indices() {
60            // 安全地获取边的端点,理论上不会失败,因为边索引来自图本身
61            let endpoints = match self.dependency_graph.edge_endpoints(edge) {
62                Some(endpoints) => endpoints,
63                None => {
64                    tracing::warn!("无法获取边端点,跳过: {:?}", edge);
65                    continue;
66                },
67            };
68
69            let (source_idx, target_idx) = endpoints;
70            let dependent = self.dependency_graph[source_idx].clone();
71            let dependency = self.dependency_graph[target_idx].clone();
72
73            // 如果依赖节点不存在,说明是缺失的依赖
74            if !available_plugins.contains(&dependency) {
75                missing_deps
76                    .entry(dependent)
77                    .or_insert_with(Vec::new)
78                    .push(dependency.clone());
79                total_missing += 1;
80            }
81        }
82
83        MissingDependencyReport {
84            has_missing_dependencies: !missing_deps.is_empty(),
85            total_missing_count: total_missing,
86            missing_dependencies: missing_deps,
87            available_plugins,
88        }
89    }
90    /// 检查循环依赖
91    pub fn has_circular_dependencies(&self) -> bool {
92        is_cyclic_directed(&self.dependency_graph)
93    }
94    /// 获取循环依赖
95    pub fn get_circular_dependencies(&self) -> Vec<Vec<String>> {
96        if !self.has_circular_dependencies() {
97            return vec![];
98        }
99
100        let mut cycles = Vec::new();
101        let mut visited = HashSet::new();
102        let mut rec_stack = HashSet::new();
103        let mut path = Vec::new();
104
105        // 对每个节点进行深度优先搜索
106        for node in self.dependency_graph.node_indices() {
107            if !visited.contains(&node) {
108                self.dfs_cycles(
109                    node,
110                    &mut visited,
111                    &mut rec_stack,
112                    &mut path,
113                    &mut cycles,
114                );
115            }
116        }
117
118        // 去重和排序
119        self.deduplicate_cycles(cycles)
120    }
121    /// 深度优先搜索查找循环
122    fn dfs_cycles(
123        &self,
124        node: petgraph::graph::NodeIndex,
125        visited: &mut HashSet<petgraph::graph::NodeIndex>,
126        rec_stack: &mut HashSet<petgraph::graph::NodeIndex>,
127        path: &mut Vec<String>,
128        cycles: &mut Vec<Vec<String>>,
129    ) {
130        let node_name = self.dependency_graph[node].clone();
131        visited.insert(node);
132        rec_stack.insert(node);
133        path.push(node_name.clone());
134
135        // 遍历所有邻居节点
136        for neighbor in self.dependency_graph.neighbors(node) {
137            if !visited.contains(&neighbor) {
138                // 继续深度优先搜索
139                self.dfs_cycles(neighbor, visited, rec_stack, path, cycles);
140            } else if rec_stack.contains(&neighbor) {
141                // 找到循环!neighbor 在递归栈中,说明形成了循环
142                let neighbor_name = self.dependency_graph[neighbor].clone();
143
144                // 找到循环的起始位置
145                if let Some(start_idx) =
146                    path.iter().position(|x| x == &neighbor_name)
147                {
148                    // 提取循环路径
149                    let cycle = path[start_idx..].to_vec();
150
151                    // 确保循环是完整的(首尾相连)
152                    if cycle.len() > 1 {
153                        cycles.push(cycle);
154                    }
155                }
156            }
157        }
158
159        // 回溯:从递归栈和路径中移除当前节点
160        rec_stack.remove(&node);
161        path.pop();
162    }
163    /// 去重和排序循环依赖
164    fn deduplicate_cycles(
165        &self,
166        mut cycles: Vec<Vec<String>>,
167    ) -> Vec<Vec<String>> {
168        if cycles.is_empty() {
169            return cycles;
170        }
171
172        // 标准化循环:将每个循环旋转到最小字典序
173        for cycle in &mut cycles {
174            self.normalize_cycle(cycle);
175        }
176
177        // 去重
178        cycles.sort();
179        cycles.dedup();
180
181        cycles
182    }
183    /// 标准化循环:旋转到最小字典序
184    fn normalize_cycle(
185        &self,
186        cycle: &mut [String],
187    ) {
188        if cycle.len() <= 1 {
189            return;
190        }
191
192        // 找到最小字典序的起始位置
193        let min_pos = cycle
194            .iter()
195            .enumerate()
196            .min_by_key(|(_, item)| *item)
197            .map(|(pos, _)| pos)
198            .unwrap_or(0);
199
200        // 旋转到最小字典序位置
201        if min_pos > 0 {
202            cycle.rotate_left(min_pos);
203        }
204    }
205
206    /// 获取拓扑排序
207    pub fn get_topological_order(&self) -> Result<Vec<String>> {
208        if self.has_circular_dependencies() {
209            return Err(anyhow::anyhow!("存在循环依赖,无法进行拓扑排序"));
210        }
211
212        let order = petgraph::algo::toposort(&self.dependency_graph, None)
213            .map_err(|_| anyhow::anyhow!("拓扑排序失败"))?;
214
215        let mut result = Vec::new();
216        for node_idx in order {
217            result.push(self.dependency_graph[node_idx].clone());
218        }
219
220        Ok(result)
221    }
222
223    /// 获取插件的直接依赖
224    pub fn get_direct_dependencies(
225        &self,
226        plugin_name: &str,
227    ) -> Vec<String> {
228        if let Some(&node_idx) = self.node_indices.get(plugin_name) {
229            self.dependency_graph
230                .neighbors(node_idx)
231                .map(|idx| self.dependency_graph[idx].clone())
232                .collect()
233        } else {
234            vec![]
235        }
236    }
237    /// 获取插件的所有依赖(包括间接依赖)
238    pub fn get_all_dependencies(
239        &self,
240        plugin_name: &str,
241    ) -> HashSet<String> {
242        let mut all_deps = HashSet::new();
243        let mut to_visit = std::collections::VecDeque::new();
244
245        to_visit.push_back(plugin_name.to_string());
246
247        while let Some(current) = to_visit.pop_front() {
248            if all_deps.insert(current.clone()) {
249                let deps = self.get_direct_dependencies(&current);
250                to_visit.extend(deps);
251            }
252        }
253
254        all_deps.remove(plugin_name);
255        all_deps
256    }
257    /// 获取循环依赖的详细报告
258    pub fn get_circular_dependency_report(&self) -> CircularDependencyReport {
259        let cycles = self.get_circular_dependencies();
260
261        CircularDependencyReport {
262            has_circular_dependencies: !cycles.is_empty(),
263            cycle_count: cycles.len(),
264            cycles: cycles.clone(),
265            affected_plugins: self.get_affected_plugins(cycles),
266        }
267    }
268    /// 获取受影响的插件
269    fn get_affected_plugins(
270        &self,
271        cycles: Vec<Vec<String>>,
272    ) -> HashSet<String> {
273        let mut affected = HashSet::new();
274
275        for cycle in cycles {
276            for plugin in cycle {
277                affected.insert(plugin.clone());
278            }
279        }
280
281        affected
282    }
283}
284
285/// 缺失依赖报告
286#[derive(Debug, Clone)]
287pub struct MissingDependencyReport {
288    pub has_missing_dependencies: bool,
289    pub total_missing_count: usize,
290    pub missing_dependencies: HashMap<String, Vec<String>>,
291    pub available_plugins: HashSet<String>,
292}
293
294impl fmt::Display for MissingDependencyReport {
295    fn fmt(
296        &self,
297        f: &mut fmt::Formatter<'_>,
298    ) -> fmt::Result {
299        if !self.has_missing_dependencies {
300            return write!(f, "✅ 所有依赖都已满足");
301        }
302
303        writeln!(f, "❌ 检测到 {} 个缺失的依赖", self.total_missing_count)?;
304        writeln!(f, "可用插件: {:?}", self.available_plugins)?;
305        writeln!(f, "\n缺失依赖详情:")?;
306
307        for (plugin_name, missing_deps) in &self.missing_dependencies {
308            writeln!(f, "  {plugin_name} 缺失依赖: {missing_deps:?}")?;
309        }
310
311        Ok(())
312    }
313}
314
315impl MissingDependencyReport {
316    /// 获取所有缺失的依赖名称
317    pub fn get_all_missing_dependency_names(&self) -> HashSet<String> {
318        let mut all_missing = HashSet::new();
319        for missing_deps in self.missing_dependencies.values() {
320            all_missing.extend(missing_deps.iter().cloned());
321        }
322        all_missing
323    }
324}
325
326/// 循环依赖报告
327#[derive(Debug, Clone)]
328pub struct CircularDependencyReport {
329    pub has_circular_dependencies: bool,
330    pub cycle_count: usize,
331    pub cycles: Vec<Vec<String>>,
332    pub affected_plugins: HashSet<String>,
333}
334
335impl fmt::Display for CircularDependencyReport {
336    fn fmt(
337        &self,
338        f: &mut fmt::Formatter<'_>,
339    ) -> fmt::Result {
340        if !self.has_circular_dependencies {
341            return write!(f, "✅ 未检测到循环依赖");
342        }
343
344        writeln!(f, "❌ 检测到 {} 个循环依赖", self.cycle_count)?;
345        writeln!(f, "受影响的插件: {:?}", self.affected_plugins)?;
346        writeln!(f, "\n循环依赖详情:")?;
347
348        for (i, cycle) in self.cycles.iter().enumerate() {
349            write!(f, "  循环 {}: ", i + 1)?;
350
351            for (j, plugin) in cycle.iter().enumerate() {
352                if j > 0 {
353                    write!(f, " -> ")?;
354                }
355                write!(f, "{plugin}")?;
356            }
357
358            // 显示循环的闭合
359            if !cycle.is_empty() {
360                write!(f, " -> {}", cycle[0])?;
361            }
362
363            writeln!(f)?;
364        }
365
366        Ok(())
367    }
368}
369
370impl CircularDependencyReport {}