xref: /DragonReach/src/parse/graph/mod.rs (revision ea330323f68db57353801959d67cbd8e0031aa18)
1 use crate::{
2     error::parse_error::{ParseError, ParseErrorType},
3     unit::UnitType,
4 };
5 
6 use std::io::BufRead;
7 use std::string::{String, ToString};
8 use std::vec::Vec;
9 
10 use super::UnitParser;
11 
12 pub struct GraphNode {
13     value: String,
14     edges: Vec<usize>,
15     incoming_edges: Vec<usize>,
16 }
17 
18 pub struct Graph {
19     total_edge: u32,
20     max_edge: u32,
21     nodes: Vec<GraphNode>,
22     value: Vec<String>,
23 }
24 
25 impl Graph {
26     fn new() -> Self {
27         return Graph {
28             max_edge: 0,
29             total_edge: 0,
30             nodes: Vec::new(),
31             value: Vec::new(),
32         };
33     }
34 
35     pub fn add_node(&mut self, value: &String) -> usize {
36         let index = self.nodes.len();
37         //如果nodes中已经有了这个value则无需重复添加,直接返回nodes中的value对应的index
38         if let Some(idx) = self.value.iter().position(|x| *x == *value) {
39             return idx;
40         }
41         //如果value在nodes中不存在,则添加value
42         self.nodes.push(GraphNode {
43             value: value.to_string(),
44             edges: Vec::new(),
45             incoming_edges: Vec::new(),
46         });
47         self.value.push(value.to_string());
48         return index;
49     }
50     pub fn add_edge(&mut self, from: usize, to: usize) {
51         self.total_edge += 1;
52         self.nodes[from].edges.push(to);
53         self.nodes[to].incoming_edges.push(from);
54     }
55     pub fn topological_sort(&mut self) -> Result<Vec<String>, ParseError> {
56         let mut result = Vec::new();
57         let mut visited = Vec::new();
58         let mut stack = Vec::new();
59         for (i, node) in self.nodes.iter().enumerate() {
60             if node.incoming_edges.len() == 0 {
61                 stack.push(i);
62             }
63         }
64         while stack.len() > 0 {
65             let index = stack.pop().unwrap();
66             if visited.contains(&index) {
67                 continue;
68             }
69             visited.push(index);
70             result.push(self.nodes[index].value.clone());
71             let len = self.nodes[index].edges.len();
72             for i in 0..len {
73                 let edge = self.nodes[index].edges[i];
74                 self.nodes[edge].incoming_edges.retain(|&x| x != index);
75                 if self.nodes[edge].incoming_edges.len() == 0 {
76                     stack.push(edge);
77                 }
78             }
79         }
80         if result.len() != self.nodes.len() {
81             return Err(ParseError::new(
82                 ParseErrorType::ECircularDependency,
83                 "".to_string(),
84                 0,
85             ));
86         }
87         result.reverse();
88         return Ok(result);
89     }
90 
91     fn add_edges(&mut self, path: &String, after: Vec<String>) {
92         //因为service的依赖关系规模不会很大,故先使用递归实现
93         //TODO:改递归
94         for target in after {
95             let s = self.add_node(&path);
96             let t = self.add_node(&target);
97             self.add_edge(s, t);
98             if self.total_edge > self.max_edge {
99                 return;
100             }
101             self.add_edges(&target, Self::parse_after(&target));
102         }
103     }
104 
105     // TODO: 完善这里,目前还是可能会有循环依赖的问题,因为目前只判断了After字段,其他字段也有可能导致循环依赖问题
106     pub fn construct_graph(unit: String) -> Result<Graph, ParseError> {
107         //计算整个依赖图中的节点数
108         let mut node_num = 1;
109         let mut dep = Vec::new();
110         Self::get_node_num(&unit, &mut dep, &mut node_num)?;
111 
112         let mut graph: Graph = Graph::new();
113         graph.max_edge = node_num * (node_num - 1);
114 
115         graph.add_node(&unit);
116         let after = Self::parse_after(&unit);
117         //递归添加边来构建图
118         graph.add_edges(&unit, after);
119 
120         if graph.max_edge < graph.total_edge {
121             return Err(ParseError::new(
122                 ParseErrorType::ECircularDependency,
123                 unit,
124                 0,
125             ));
126         }
127 
128         return Ok(graph);
129     }
130 
131     pub fn parse_after(path: &String) -> Vec<String> {
132         let mut ret = Vec::new();
133 
134         let reader = UnitParser::get_reader(path, UnitType::Unknown).unwrap();
135 
136         let mut lines_with_after = Vec::new();
137 
138         for line_result in reader.lines() {
139             if let Ok(line) = line_result {
140                 if line.starts_with("After") {
141                     lines_with_after.push(line);
142                 }
143             }
144         }
145 
146         for line in lines_with_after {
147             let after = &line.split('=').collect::<Vec<&str>>()[1];
148             let units = after.split_whitespace().collect::<Vec<&str>>();
149 
150             for unit in units {
151                 ret.push(String::from(unit));
152             }
153         }
154 
155         ret
156     }
157 
158     /// ## 获取到unit文件依赖图节点数
159     ///
160     /// ### param file_path unit文件路径
161     ///
162     /// ### dependencies 缓存after依赖的容器
163     ///
164     /// ### total_after_count 返回节点数
165     ///
166     /// ### return
167     fn get_node_num(
168         file_path: &str,
169         dependencies: &mut Vec<String>,
170         total_after_count: &mut u32,
171     ) -> Result<(), ParseError> {
172         let reader = UnitParser::get_reader(file_path, UnitType::Unknown)?;
173 
174         let mut current_after_count = 0;
175 
176         for line_result in reader.lines() {
177             if let Ok(line) = line_result {
178                 if line.starts_with("After=") {
179                     let dependencies_str = &line[6..];
180                     let dependency_list: Vec<&str> = dependencies_str.split_whitespace().collect();
181 
182                     for dependency in dependency_list {
183                         if dependencies.contains(&dependency.to_string()) {
184                             // 循环依赖检查
185                             continue;
186                         }
187 
188                         dependencies.push(dependency.to_string());
189 
190                         // 递归解析依赖链
191                         Self::get_node_num(dependency, dependencies, total_after_count)?;
192                     }
193 
194                     current_after_count += 1;
195                 }
196             }
197         }
198 
199         *total_after_count += current_after_count;
200 
201         Ok(())
202     }
203 }
204