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("FCALL")
24 .arg(QUALIFY_DNS_NAME_FN)
25 .arg(names.len() as u32)
26 .arg(&names)
27 .query_async(self)
28 .await?)
29 }
30
31 async fn get_dns_names(&mut self) -> FCallResult<HashSet<String>> {
32 Ok(self.smembers(DNS_KEY).await?)
33 }
34
35 async fn get_nodes(&mut self) -> FCallResult<Vec<Node>> {
36 let mut nodes = Vec::new();
37 let link_ids: Vec<String> = self.smembers(PROC_NODES_KEY).await?;
38 for link_id in link_ids {
39 nodes.push(self.get_node(&link_id).await?);
40 }
41 Ok(nodes)
42 }
43
44 async fn get_node(&mut self, link_id: &str) -> FCallResult<Node> {
45 let name: String = self.get(format!("{PROC_NODES_KEY};{link_id}")).await?;
46 let alt_names: HashSet<String> = self
47 .smembers(format!("{PROC_NODES_KEY};{link_id};alt_names"))
48 .await?;
49 let dns_names: HashSet<String> = self
50 .smembers(format!("{PROC_NODES_KEY};{link_id};dns_names"))
51 .await?;
52 let raw_ids: HashSet<String> = self
53 .smembers(format!("{PROC_NODES_KEY};{link_id};raw_ids"))
54 .await?;
55 let plugins: HashSet<String> = self
56 .smembers(format!("{PROC_NODES_KEY};{link_id};plugins"))
57 .await?;
58
59 Ok(Node {
60 name,
61 link_id: link_id.to_string(),
62 alt_names,
63 dns_names,
64 raw_ids,
65 plugins,
66 })
67 }
68
69 async fn get_dns_metadata(&mut self, name: &str) -> FCallResult<HashMap<String, String>> {
70 let qualified_name = match self
71 .qualify_dns_names(vec![name.to_string()])
72 .await?
73 .into_iter()
74 .next()
75 {
76 Some(qn) => qn,
77 None => {
78 return Err(FCallError::Logic(
79 "Tried to qualify one DNS name but got zero back.",
80 ))
81 }
82 };
83
84 Ok(self
85 .hgetall(format!("{META_KEY};{DNS_KEY};{qualified_name}"))
86 .await?)
87 }
88
89 async fn get_node_metadata(&mut self, node: &Node) -> FCallResult<HashMap<String, String>> {
90 let mut meta = HashMap::new();
91 for raw_id in &node.raw_ids {
92 let raw_meta: HashMap<String, String> = self
93 .hgetall(format!("{META_KEY};{NODES_KEY};{raw_id}"))
94 .await?;
95 meta.extend(raw_meta);
96 }
97 let proc_meta: HashMap<String, String> = self
98 .hgetall(format!("{META_KEY};{PROC_NODES_KEY};{}", node.link_id))
99 .await?;
100 meta.extend(proc_meta);
101 Ok(meta)
102 }
103}