1use crate::error::PotError;
2use crate::Result;
3use ipnet::IpNet;
4use std::convert::TryFrom;
5use std::net::IpAddr;
6use std::str::FromStr;
7
8use crate::PotSystemConfig;
9use std::path::PathBuf;
10
11pub fn get_bridges_list(conf: &PotSystemConfig) -> Result<Vec<BridgeConf>> {
12 let path_list = get_bridges_path_list(conf);
13 let mut result = Vec::new();
14 for f in path_list {
15 if let Ok(conf_str) = std::fs::read_to_string(f.as_path()) {
16 if let Ok(bridge_conf) = conf_str.parse() {
17 result.push(bridge_conf);
18 }
19 }
20 }
21 Ok(result)
22}
23
24fn get_bridges_path_list(conf: &PotSystemConfig) -> Vec<PathBuf> {
25 let mut result = Vec::new();
26 let bridges_path = std::path::Path::new(&conf.fs_root).join("bridges");
27 walkdir::WalkDir::new(bridges_path)
28 .max_depth(1)
29 .min_depth(1)
30 .into_iter()
31 .filter_map(std::result::Result::ok)
32 .filter(|x| x.file_type().is_file())
33 .for_each(|x| result.push(x.into_path()));
34 result
35}
36#[derive(Debug)]
37pub struct BridgeConf {
38 pub name: String,
39 pub network: IpNet,
40 pub gateway: IpAddr,
41}
42
43impl FromStr for BridgeConf {
44 type Err = crate::error::PotError;
45 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
46 let partial = PartialBridgeConf::from_str(s).unwrap();
47 BridgeConf::try_from(partial)
48 }
49}
50
51impl TryFrom<PartialBridgeConf> for BridgeConf {
52 type Error = PotError;
53
54 fn try_from(value: PartialBridgeConf) -> std::result::Result<Self, Self::Error> {
55 if !value.is_valid() {
56 Err(PotError::BridgeConfError)
57 } else {
58 let network = value.network.unwrap();
59 let gateway = value.gateway.unwrap();
60 if !network.contains(&gateway) {
61 Err(PotError::BridgeConfError)
62 } else {
63 Ok(BridgeConf {
64 name: value.name.unwrap(),
65 network: value.network.unwrap(),
66 gateway: value.gateway.unwrap(),
67 })
68 }
69 }
70 }
71}
72
73#[derive(Default, Debug)]
74struct PartialBridgeConf {
75 name: Option<String>,
76 network: Option<IpNet>,
77 gateway: Option<IpAddr>,
78}
79
80impl FromStr for PartialBridgeConf {
81 type Err = std::convert::Infallible;
82 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
83 use crate::util::get_value;
84 let lines: Vec<String> = s
85 .to_string()
86 .lines()
87 .map(|x| x.trim().to_string())
88 .filter(|x| !x.starts_with('#'))
89 .collect();
90 let mut result = PartialBridgeConf::default();
91 for linestr in &lines {
92 if linestr.starts_with("name=") {
93 result.name = get_value(linestr);
94 }
95 if linestr.starts_with("net=") {
96 result.network = get_value(linestr);
97 }
98 if linestr.starts_with("gateway=") {
99 result.gateway = get_value(linestr);
100 }
101 }
102 Ok(result)
103 }
104}
105
106impl PartialBridgeConf {
107 fn is_valid(&self) -> bool {
108 self.name.is_some() && self.network.is_some() && self.gateway.is_some()
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[test]
117 fn bridge_conf_fromstr_001() {
118 let uut = BridgeConf::from_str("");
119 assert_eq!(uut.is_ok(), false);
120 }
121
122 #[test]
123 fn bridge_conf_fromstr_002() {
124 let uut = BridgeConf::from_str("net=10.192.0.24/29");
125 assert_eq!(uut.is_ok(), false);
126 }
127
128 #[test]
129 fn bridge_conf_fromstr_003() {
130 let uut = BridgeConf::from_str("gateway=10.192.0.24");
131 assert_eq!(uut.is_ok(), false);
132 }
133
134 #[test]
135 fn bridge_conf_fromstr_004() {
136 let uut = BridgeConf::from_str("name=test-bridge");
137 assert_eq!(uut.is_ok(), false);
138 }
139
140 #[test]
141 fn bridge_conf_fromstr_005() {
142 let uut = BridgeConf::from_str("net=10.192.0.24/29\ngateway=10.192.1.25\nname=test-bridge");
143 assert_eq!(uut.is_ok(), false);
144 }
145
146 #[test]
147 fn bridge_conf_fromstr_020() {
148 let uut = BridgeConf::from_str("net=10.192.0.24/29\ngateway=10.192.0.25\nname=test-bridge");
149 assert_eq!(uut.is_ok(), true);
150 }
151}