netdox_plugin_rs/
model.rs

1use std::{
2    collections::{HashMap, HashSet},
3    future::Future,
4};
5
6use redis::{Cmd, ToRedisArgs};
7use serde::Deserialize;
8
9use crate::error::FCallResult;
10
11// CLI
12
13/// Struct for modeling the redis connection details argument each plugin receives.
14#[derive(Debug, Deserialize)]
15pub struct RedisArgs {
16    /// Hostname of the redis server to use.
17    pub host: String,
18    /// Port of the redis server to use.
19    pub port: usize,
20    /// Logical database in the redis instance to use.
21    pub db: usize,
22    /// Username to use when authenticating with redis - if any.
23    pub username: Option<String>,
24    /// Password to use when authenticating with redis - if any.
25    pub password: Option<String>,
26}
27
28impl RedisArgs {
29    /// Return a redis client object using these connection  details.
30    pub fn to_client(self) -> FCallResult<redis::Client> {
31        let client =
32            redis::Client::open(format!("redis://{}:{}/{}", self.host, self.port, self.db))?;
33
34        if let Some(username) = self.username {
35            redis::cmd("AUTH")
36                .arg(username)
37                .arg(self.password.unwrap())
38                .exec(&mut client.get_connection()?)?;
39        }
40
41        Ok(client)
42    }
43}
44
45// Data
46
47/// Models a datum that can be attached to an object.
48pub enum PluginData<'a> {
49    Hash {
50        title: &'a str,
51        items: HashMap<&'a str, &'a str>,
52    },
53    List {
54        title: &'a str,
55        items: Vec<(&'a str, &'a str, &'a str)>,
56    },
57    String {
58        title: &'a str,
59        content_type: StringContentType,
60        content: &'a str,
61    },
62    Table {
63        title: &'a str,
64        num_columns: usize,
65        rows: Vec<Vec<&'a str>>,
66    },
67}
68
69impl<'a> PluginData<'a> {
70    /// Adds the necessary args to a redis command in order to complete
71    /// a plugin data creation fcall with this data.
72    pub fn add_as_args(&'a self, cmd: &mut Cmd) {
73        match self {
74            PluginData::Hash { title, items } => {
75                cmd.arg("hash").arg(title);
76                for (key, val) in items {
77                    cmd.arg(key).arg(val);
78                }
79            }
80            PluginData::List { title, items } => {
81                cmd.arg("list").arg(title).arg(items);
82            }
83            PluginData::String {
84                title,
85                content_type,
86                content,
87            } => {
88                cmd.arg("string").arg(title).arg(content_type).arg(content);
89            }
90            PluginData::Table {
91                title,
92                num_columns,
93                rows,
94            } => {
95                cmd.arg("table").arg(title).arg(num_columns);
96                for row in rows {
97                    for col in row {
98                        cmd.arg(col);
99                    }
100                }
101            }
102        };
103    }
104}
105
106/// The different content types a string datum can be tagged as.
107pub enum StringContentType {
108    HTML,
109    Markdown,
110    Plain,
111}
112
113impl ToRedisArgs for StringContentType {
114    fn write_redis_args<W>(&self, out: &mut W)
115    where
116        W: ?Sized + redis::RedisWrite,
117    {
118        match self {
119            StringContentType::HTML => out.write_arg("html".as_bytes()),
120            StringContentType::Markdown => out.write_arg("markdown".as_bytes()),
121            StringContentType::Plain => out.write_arg("plain".as_bytes()),
122        }
123    }
124}
125
126/// Models a node.
127pub struct Node {
128    pub name: String,
129    pub link_id: String,
130    pub alt_names: HashSet<String>,
131    pub dns_names: HashSet<String>,
132    pub raw_ids: HashSet<String>,
133    pub plugins: HashSet<String>,
134}
135
136// Behaviour
137
138/// Defines the read API.
139pub trait NetdoxReader {
140    /// Fetch the default network namespace.
141    fn get_default_network(&mut self) -> impl Future<Output = FCallResult<String>> + Send;
142    /// Prepend the default network qualifier to a list of DNS names.
143    fn qualify_dns_names(
144        &mut self,
145        names: Vec<String>,
146    ) -> impl Future<Output = FCallResult<Vec<String>>> + Send;
147    /// Fetch all the DNS names from the datastore.
148    fn get_dns_names(&mut self) -> impl Future<Output = FCallResult<HashSet<String>>> + Send;
149    /// Fetch all the nodes from the datastore.
150    fn get_nodes(&mut self) -> impl Future<Output = FCallResult<Vec<Node>>> + Send;
151    /// Fetch a processed node using its link ID.
152    fn get_node(&mut self, link_id: &str) -> impl Future<Output = FCallResult<Node>> + Send;
153    /// Fetch the metadata for a DNS name.
154    fn get_dns_metadata(
155        &mut self,
156        name: &str,
157    ) -> impl Future<Output = FCallResult<HashMap<String, String>>> + Send;
158    /// Fetch the metadata for a node.
159    fn get_node_metadata(
160        &mut self,
161        node: &Node,
162    ) -> impl Future<Output = FCallResult<HashMap<String, String>>> + Send;
163}
164
165/// Defines the write API.
166pub trait NetdoxWriter {
167    /// Create a DNS name and optionally attach a record.
168    fn put_dns(
169        &mut self,
170        plugin: &str,
171        name: &str,
172        rtype: Option<&str>,
173        value: Option<&str>,
174    ) -> impl Future<Output = FCallResult<()>> + Send;
175
176    /// Attach plugin data to a DNS name.
177    fn put_dns_plugin_data<'a>(
178        &mut self,
179        plugin: &str,
180        name: &str,
181        pdata_id: &str,
182        data: PluginData<'a>,
183    ) -> impl Future<Output = FCallResult<()>> + Send;
184
185    /// Attach metadata to a DNS name.
186    fn put_dns_metadata(
187        &mut self,
188        plugin: &str,
189        name: &str,
190        metadata: &HashMap<&str, &str>,
191    ) -> impl Future<Output = FCallResult<()>> + Send;
192
193    /// Create a node.
194    fn put_node(
195        &mut self,
196        plugin: &str,
197        name: &str,
198        dns_names: Vec<&str>,
199        exclusive: bool,
200        link_id: Option<&str>,
201    ) -> impl Future<Output = FCallResult<()>> + Send;
202
203    /// Attach plugin data to a node.
204    fn put_node_plugin_data<'a>(
205        &mut self,
206        plugin: &str,
207        dns_names: Vec<&str>,
208        pdata_id: &str,
209        data: PluginData<'a>,
210    ) -> impl Future<Output = FCallResult<()>> + Send;
211
212    /// Attach plugin data to a processed node by link ID.
213    fn put_proc_node_plugin_data<'a>(
214        &mut self,
215        plugin: &str,
216        link_id: &str,
217        pdata_id: &str,
218        data: PluginData<'a>,
219    ) -> impl Future<Output = FCallResult<()>> + Send;
220
221    /// Attach metadata to a node.
222    fn put_node_metadata(
223        &mut self,
224        plugin: &str,
225        dns_names: Vec<&str>,
226        metadata: &HashMap<&str, &str>,
227    ) -> impl Future<Output = FCallResult<()>> + Send;
228
229    /// Attach metadata to a processed node by link ID.
230    fn put_proc_node_metadata(
231        &mut self,
232        plugin: &str,
233        link_id: &str,
234        metadata: &HashMap<&str, &str>,
235    ) -> impl Future<Output = FCallResult<()>> + Send;
236
237    /// Create a report.
238    fn put_report(
239        &mut self,
240        plugin: &str,
241        report_id: &str,
242        title: &str,
243        length: usize,
244    ) -> impl Future<Output = FCallResult<()>> + Send;
245
246    /// Attach data to a report.
247    fn put_report_data<'a>(
248        &mut self,
249        plugin: &str,
250        report_id: &str,
251        index: usize,
252        data: PluginData<'a>,
253    ) -> impl Future<Output = FCallResult<()>> + Send;
254}