grapl_graph_descriptions/
process_inbound_connection.rs

1use std::convert::TryFrom;
2
3use log::warn;
4use serde_json::{json, Value};
5use uuid::Uuid;
6
7use crate::error::Error;
8use crate::graph_description::ProcessInboundConnection;
9use crate::node::NodeT;
10
11pub enum ProcessInboundConnectionState {
12    Bound,
13    Existing,
14    Closed,
15}
16
17impl From<ProcessInboundConnectionState> for u32 {
18    fn from(p: ProcessInboundConnectionState) -> u32 {
19        match p {
20            ProcessInboundConnectionState::Bound => 1,
21            ProcessInboundConnectionState::Closed => 2,
22            ProcessInboundConnectionState::Existing => 3,
23        }
24    }
25}
26
27impl TryFrom<u32> for ProcessInboundConnectionState {
28    type Error = Error;
29
30    fn try_from(p: u32) -> Result<ProcessInboundConnectionState, Error> {
31        match p {
32            1 => Ok(ProcessInboundConnectionState::Bound),
33            2 => Ok(ProcessInboundConnectionState::Closed),
34            3 => Ok(ProcessInboundConnectionState::Existing),
35            _ => Err(Error::InvalidProcessInboundConnectionState(p)),
36        }
37    }
38}
39
40impl ProcessInboundConnection {
41    pub fn new(
42        asset_id: impl Into<Option<String>>,
43        hostname: impl Into<Option<String>>,
44        state: ProcessInboundConnectionState,
45        port: u16,
46        ip_address: impl Into<String>,
47        protocol: impl Into<String>,
48        created_timestamp: u64,
49        terminated_timestamp: u64,
50        last_seen_timestamp: u64,
51    ) -> Self {
52        let asset_id = asset_id.into();
53        let hostname = hostname.into();
54        let protocol = protocol.into();
55
56        if hostname.is_none() && asset_id.is_none() {
57            panic!("ProcessInboundConnection must have at least asset_id or hostname");
58        }
59
60        let ip_address = ip_address.into();
61
62        Self {
63            node_key: Uuid::new_v4().to_string(),
64            ip_address,
65            asset_id,
66            hostname,
67            protocol,
68            created_timestamp,
69            terminated_timestamp,
70            last_seen_timestamp,
71            port: port as u32,
72            state: state.into(),
73        }
74    }
75
76    pub fn into_json(self) -> Value {
77        let mut j = json!({
78            "node_key": self.node_key,
79            "dgraph.type": "ProcessInboundConnection",
80            "protocol": self.protocol,
81            "port": self.port,
82        });
83
84        if self.created_timestamp != 0 {
85            j["created_timestamp"] = self.created_timestamp.into();
86        }
87        if self.terminated_timestamp != 0 {
88            j["terminated_timestamp"] = self.terminated_timestamp.into();
89        }
90        if self.last_seen_timestamp != 0 {
91            j["last_seen_timestamp"] = self.last_seen_timestamp.into();
92        }
93
94        j
95    }
96}
97
98impl NodeT for ProcessInboundConnection {
99    fn get_asset_id(&self) -> Option<&str> {
100        self.asset_id.as_ref().map(String::as_str)
101    }
102
103    fn set_asset_id(&mut self, asset_id: impl Into<String>) {
104        self.asset_id = Some(asset_id.into());
105    }
106
107    fn get_node_key(&self) -> &str {
108        &self.node_key
109    }
110
111    fn set_node_key(&mut self, node_key: impl Into<String>) {
112        self.node_key = node_key.into();
113    }
114
115    fn merge(&mut self, other: &Self) -> bool {
116        if self.node_key != other.node_key {
117            warn!("Attempted to merge two ProcessInboundConnection Nodes with differing node_keys");
118            return false;
119        }
120
121        if self.ip_address != other.ip_address {
122            warn!("Attempted to merge two ProcessInboundConnection Nodes with differing IPs");
123            return false;
124        }
125
126        let mut merged = false;
127
128        if self.asset_id.is_none() && other.asset_id.is_some() {
129            self.asset_id = other.asset_id.clone();
130        }
131
132        if self.hostname.is_none() && other.hostname.is_some() {
133            self.hostname = other.hostname.clone();
134        }
135
136        if self.created_timestamp != 0 && self.created_timestamp > other.created_timestamp {
137            self.created_timestamp = other.created_timestamp;
138            merged = true;
139        }
140
141        if self.terminated_timestamp != 0 && self.terminated_timestamp < other.terminated_timestamp
142        {
143            self.terminated_timestamp = other.terminated_timestamp;
144            merged = true;
145        }
146
147        if self.last_seen_timestamp != 0 && self.last_seen_timestamp < other.last_seen_timestamp {
148            self.last_seen_timestamp = other.last_seen_timestamp;
149            merged = true;
150        }
151
152        merged
153    }
154
155    fn merge_into(&mut self, other: Self) -> bool {
156        self.merge(&other)
157    }
158}