1use redis::{self, cmd, AsyncCommands};
2use std::collections::{HashMap, HashSet};
3
4use crate::{
5 error::{FCallError, FCallResult},
6 model::{NetdoxReader, Node},
7};
8
9const QUALIFY_DNS_NAME_FN: &str = "netdox_qualify_dns_names";
10
11const META_KEY: &str = "meta";
12const DNS_KEY: &str = "dns";
13const NODES_KEY: &str = "nodes";
14const PROC_NODES_KEY: &str = "proc_nodes";
15const DEFAULT_NETWORK_KEY: &str = "default_network";
16
17impl NetdoxReader for redis::aio::MultiplexedConnection {
18 async fn get_default_network(&mut self) -> FCallResult<String> {
19 Ok(self.get(DEFAULT_NETWORK_KEY).await?)
20 }
21
22 async fn qualify_dns_names(&mut self, names: Vec<String>) -> FCallResult<Vec<String>> {
23 Ok(cmd(QUALIFY_DNS_NAME_FN)
24 .arg(names.len() as u32)
25 .arg(&names)
26 .query_async(self)
27 .await?)
28 }
29
30 async fn get_dns_names(&mut self) -> FCallResult<HashSet<String>> {
31 Ok(self.smembers(DNS_KEY).await?)
32 }
33
34 async fn get_nodes(&mut self) -> FCallResult<Vec<Node>> {
35 let mut nodes = Vec::new();
36 let link_ids: Vec<String> = self.smembers(PROC_NODES_KEY).await?;
37 for link_id in link_ids {
38 nodes.push(self.get_node(&link_id).await?);
39 }
40 Ok(nodes)
41 }
42
43 async fn get_node(&mut self, link_id: &str) -> FCallResult<Node> {
44 let name: String = self.get(format!("{PROC_NODES_KEY};{link_id}")).await?;
45 let alt_names: HashSet<String> = self
46 .smembers(format!("{PROC_NODES_KEY};{link_id};alt_names"))
47 .await?;
48 let dns_names: HashSet<String> = self
49 .smembers(format!("{PROC_NODES_KEY};{link_id};dns_names"))
50 .await?;
51 let raw_ids: HashSet<String> = self
52 .smembers(format!("{PROC_NODES_KEY};{link_id};raw_ids"))
53 .await?;
54 let plugins: HashSet<String> = self
55 .smembers(format!("{PROC_NODES_KEY};{link_id};plugins"))
56 .await?;
57
58 Ok(Node {
59 name,
60 link_id: link_id.to_string(),
61 alt_names,
62 dns_names,
63 raw_ids,
64 plugins,
65 })
66 }
67
68 async fn get_dns_metadata(&mut self, name: &str) -> FCallResult<HashMap<String, String>> {
69 let qualified_name = match self
70 .qualify_dns_names(vec![name.to_string()])
71 .await?
72 .into_iter()
73 .next()
74 {
75 Some(qn) => qn,
76 None => {
77 return Err(FCallError::Logic(
78 "Tried to qualify one DNS name but got zero back.",
79 ))
80 }
81 };
82
83 Ok(self
84 .hgetall(format!("{META_KEY};{DNS_KEY};{qualified_name}"))
85 .await?)
86 }
87
88 async fn get_node_metadata(&mut self, node: &Node) -> FCallResult<HashMap<String, String>> {
89 let mut meta = HashMap::new();
90 for raw_id in &node.raw_ids {
91 let raw_meta: HashMap<String, String> = self
92 .hgetall(format!("{META_KEY};{NODES_KEY};{raw_id}"))
93 .await?;
94 meta.extend(raw_meta);
95 }
96 let proc_meta: HashMap<String, String> = self
97 .hgetall(format!("{META_KEY};{PROC_NODES_KEY};{}", node.link_id))
98 .await?;
99 meta.extend(proc_meta);
100 Ok(meta)
101 }
102}