parser.rs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::collections::hash_map::Entry;
  19. use async_std::sync::Arc;
  20. use log::{debug, error, info};
  21. use serde_json::Value;
  22. use smol::Executor;
  23. use url::Url;
  24. use darkfi::util::{async_util, time::NanoTimestamp};
  25. use crate::{
  26. config::{DnvConfig, Node, NodeType},
  27. error::{DnetViewError, DnetViewResult},
  28. model::{
  29. LilithInfo, Model, NetworkInfo, NodeInfo, SelectableObject, Session, SessionInfo, SlotInfo,
  30. },
  31. rpc::RpcConnect,
  32. util::{make_empty_id, make_info_id, make_node_id, make_session_id},
  33. };
  34. pub struct DataParser {
  35. model: Arc<Model>,
  36. config: DnvConfig,
  37. }
  38. impl DataParser {
  39. pub fn new(model: Arc<Model>, config: DnvConfig) -> Arc<Self> {
  40. Arc::new(Self { model, config })
  41. }
  42. pub async fn start_connect_slots(self: Arc<Self>, ex: Arc<Executor<'_>>) -> DnetViewResult<()> {
  43. debug!(target: "dnetview", "start_connect_slots() START");
  44. for node in &self.config.nodes {
  45. debug!(target: "dnetview", "attempting to spawn...");
  46. ex.clone().spawn(self.clone().try_connect(node.clone())).detach();
  47. }
  48. Ok(())
  49. }
  50. async fn try_connect(self: Arc<Self>, node: Node) -> DnetViewResult<()> {
  51. debug!(target: "dnetview", "try_connect() START");
  52. loop {
  53. info!("Attempting to poll {}, RPC URL: {}", node.name, node.rpc_url);
  54. // Parse node config and execute poll.
  55. // On any failure, sleep and retry.
  56. match RpcConnect::new(Url::parse(&node.rpc_url)?, node.name.clone()).await {
  57. Ok(client) => {
  58. if let Err(e) = self.poll(&node, client).await {
  59. error!("Poll execution error: {:?}", e);
  60. }
  61. }
  62. Err(e) => {
  63. error!("RPC client creation error: {:?}", e);
  64. }
  65. }
  66. self.parse_offline(node.name.clone()).await?;
  67. async_util::sleep(2000).await;
  68. }
  69. }
  70. async fn poll(&self, node: &Node, client: RpcConnect) -> DnetViewResult<()> {
  71. loop {
  72. // Ping the node to verify if its online.
  73. if let Err(e) = client.ping().await {
  74. return Err(DnetViewError::Darkfi(e))
  75. }
  76. // Retrieve node info, based on its type
  77. let response = match &node.node_type {
  78. NodeType::LILITH => client.lilith_spawns().await,
  79. NodeType::NORMAL => client.dnet_info().await,
  80. NodeType::CONSENSUS => client.get_consensus_info().await,
  81. };
  82. // Parse response
  83. match response {
  84. Ok(reply) => {
  85. debug!("dnetview:: poll() reply {:?}", reply);
  86. if reply.as_object().is_none() || reply.as_object().unwrap().is_empty() {
  87. return Err(DnetViewError::EmptyRpcReply)
  88. }
  89. match &node.node_type {
  90. NodeType::LILITH => {
  91. self.parse_lilith_data(
  92. reply.as_object().unwrap().clone(),
  93. node.name.clone(),
  94. )
  95. .await?
  96. }
  97. _ => self.parse_data(reply.as_object().unwrap(), node.name.clone()).await?,
  98. };
  99. }
  100. Err(e) => return Err(e),
  101. }
  102. // Sleep until next poll
  103. async_util::sleep(2000).await;
  104. }
  105. }
  106. // If poll times out, inititalize data structures with empty values.
  107. async fn parse_offline(&self, node_name: String) -> DnetViewResult<()> {
  108. debug!(target: "dnetview", "parse_offline() START");
  109. let name = "Offline".to_string();
  110. let session_type = Session::Offline;
  111. let mut sessions: Vec<SessionInfo> = Vec::new();
  112. let hosts = Vec::new();
  113. let node_id = make_node_id(&node_name)?;
  114. let dnet_id = make_empty_id(&node_id, &session_type, 0)?;
  115. let addr = "Null".to_string();
  116. let state = None;
  117. let random_id = 0;
  118. let remote_id = "Null".to_string();
  119. let log = Vec::new();
  120. let is_empty = true;
  121. let slot = SlotInfo::new(
  122. dnet_id.clone(),
  123. node_id.clone(),
  124. addr.clone(),
  125. random_id,
  126. remote_id,
  127. log,
  128. is_empty,
  129. );
  130. let session_info = SessionInfo::new(
  131. dnet_id,
  132. node_id.clone(),
  133. //name.clone(),
  134. addr.clone(),
  135. state,
  136. slot,
  137. is_empty,
  138. );
  139. sessions.push(session_info);
  140. // TODO: clean this up
  141. let node = NodeInfo::new(
  142. node_id.clone(),
  143. name.clone(),
  144. hosts,
  145. sessions.clone(),
  146. sessions.clone(),
  147. is_empty,
  148. );
  149. self.update_selectables(node).await?;
  150. Ok(())
  151. }
  152. async fn parse_data(
  153. &self,
  154. reply: &serde_json::Map<String, Value>,
  155. name: String,
  156. ) -> DnetViewResult<()> {
  157. let hosts = &reply["hosts"];
  158. let inbound = &reply["inbound"];
  159. let outbound = &reply["outbound"];
  160. let node_id = make_node_id(&name)?;
  161. let hosts = self.parse_hosts(hosts).await?;
  162. let inbound = self.parse_session(inbound, &node_id, Session::Inbound).await?;
  163. let outbound = self.parse_session(outbound, &node_id, Session::Outbound).await?;
  164. let node = NodeInfo::new(node_id, name, hosts, inbound.clone(), outbound.clone(), false);
  165. self.update_selectables(node).await?;
  166. self.update_msgs(inbound.clone(), outbound.clone()).await?;
  167. Ok(())
  168. }
  169. async fn parse_lilith_data(
  170. &self,
  171. reply: serde_json::Map<String, Value>,
  172. name: String,
  173. ) -> DnetViewResult<()> {
  174. let spawns: Vec<serde_json::Map<String, Value>> =
  175. serde_json::from_value(reply.get("spawns").unwrap().clone()).unwrap();
  176. let mut networks = vec![];
  177. for spawn in spawns {
  178. let name = spawn.get("name").unwrap().as_str().unwrap().to_string();
  179. let id = make_node_id(&name)?;
  180. let urls: Vec<String> =
  181. serde_json::from_value(spawn.get("urls").unwrap().clone()).unwrap();
  182. let nodes: Vec<String> =
  183. serde_json::from_value(spawn.get("hosts").unwrap().clone()).unwrap();
  184. let network = NetworkInfo::new(id, name, urls, nodes);
  185. networks.push(network);
  186. }
  187. let id = make_node_id(&name)?;
  188. let lilith = LilithInfo::new(id.clone(), name, networks);
  189. let lilith_obj = SelectableObject::Lilith(lilith.clone());
  190. self.model.selectables.lock().await.insert(id, lilith_obj);
  191. for network in lilith.networks {
  192. let network_obj = SelectableObject::Network(network.clone());
  193. self.model.selectables.lock().await.insert(network.id, network_obj);
  194. }
  195. Ok(())
  196. }
  197. async fn update_msgs(
  198. &self,
  199. inbounds: Vec<SessionInfo>,
  200. outbounds: Vec<SessionInfo>,
  201. ) -> DnetViewResult<()> {
  202. for inbound in inbounds {
  203. if !self.model.msg_map.lock().await.contains_key(&inbound.info.dnet_id) {
  204. // we don't have this ID: it is a new node
  205. self.model
  206. .msg_map
  207. .lock()
  208. .await
  209. .insert(inbound.info.dnet_id, inbound.info.log.clone());
  210. } else {
  211. // we have this id: append the msg values
  212. match self.model.msg_map.lock().await.entry(inbound.info.dnet_id) {
  213. Entry::Vacant(e) => {
  214. e.insert(inbound.info.log);
  215. }
  216. Entry::Occupied(mut e) => {
  217. for msg in inbound.info.log {
  218. e.get_mut().push(msg);
  219. }
  220. }
  221. }
  222. }
  223. }
  224. for outbound in outbounds {
  225. if !self.model.msg_map.lock().await.contains_key(&outbound.info.dnet_id) {
  226. // we don't have this ID: it is a new node
  227. self.model
  228. .msg_map
  229. .lock()
  230. .await
  231. .insert(outbound.info.dnet_id, outbound.info.log.clone());
  232. } else {
  233. // we have this id: append the msg values
  234. match self.model.msg_map.lock().await.entry(outbound.info.dnet_id) {
  235. Entry::Vacant(e) => {
  236. e.insert(outbound.info.log);
  237. }
  238. Entry::Occupied(mut e) => {
  239. for msg in outbound.info.log {
  240. e.get_mut().push(msg);
  241. }
  242. }
  243. }
  244. }
  245. }
  246. Ok(())
  247. }
  248. async fn update_selectables(&self, node: NodeInfo) -> DnetViewResult<()> {
  249. if node.is_offline {
  250. let node_obj = SelectableObject::Node(node.clone());
  251. self.model.selectables.lock().await.insert(node.dnet_id.clone(), node_obj.clone());
  252. } else {
  253. let node_obj = SelectableObject::Node(node.clone());
  254. self.model.selectables.lock().await.insert(node.dnet_id.clone(), node_obj.clone());
  255. for inbound in node.inbound {
  256. if !inbound.is_empty {
  257. let inbound_obj = SelectableObject::Session(inbound.clone());
  258. self.model
  259. .selectables
  260. .lock()
  261. .await
  262. .insert(inbound.clone().dnet_id, inbound_obj.clone());
  263. let info_obj = SelectableObject::Connect(inbound.info.clone());
  264. self.model
  265. .selectables
  266. .lock()
  267. .await
  268. .insert(inbound.info.clone().dnet_id, info_obj.clone());
  269. }
  270. }
  271. for outbound in node.outbound {
  272. if !outbound.is_empty {
  273. let outbound_obj = SelectableObject::Session(outbound.clone());
  274. self.model
  275. .selectables
  276. .lock()
  277. .await
  278. .insert(outbound.clone().dnet_id, outbound_obj.clone());
  279. let info_obj = SelectableObject::Connect(outbound.info.clone());
  280. self.model
  281. .selectables
  282. .lock()
  283. .await
  284. .insert(outbound.info.clone().dnet_id, info_obj.clone());
  285. }
  286. }
  287. }
  288. Ok(())
  289. }
  290. async fn parse_session(
  291. &self,
  292. reply: &Value,
  293. node_id: &String,
  294. prefix: Session,
  295. ) -> DnetViewResult<Vec<SessionInfo>> {
  296. let session_id = make_session_id(&node_id, &prefix)?;
  297. let mut session_info: Vec<SessionInfo> = Vec::new();
  298. // TODO: improve this ugly hack.
  299. let mut slot_count = 0;
  300. // Dnetview is not enabled.
  301. if reply.is_null() {
  302. debug!(target: "dnetview", "parse_outbound() reply.is_null() == True");
  303. slot_count += 1;
  304. let info_id = make_empty_id(&node_id, &prefix, slot_count)?;
  305. let node_id = node_id.to_string();
  306. let addr = "Null".to_string();
  307. let random_id = 0;
  308. let remote_id = "Null".to_string();
  309. let log = Vec::new();
  310. let is_empty = false;
  311. let slot = SlotInfo::new(
  312. info_id.clone(),
  313. node_id.clone(),
  314. addr,
  315. random_id,
  316. remote_id,
  317. log,
  318. is_empty,
  319. );
  320. let is_empty = true;
  321. let addr = "Null".to_string();
  322. let state = None;
  323. let session =
  324. SessionInfo::new(session_id.clone(), node_id.clone(), addr, state, slot, is_empty);
  325. session_info.push(session);
  326. return Ok(session_info)
  327. }
  328. let sessions = reply.as_array().unwrap();
  329. debug!(target: "dnetview", "parse_outbound() len session{:?}", sessions.len());
  330. for session in sessions {
  331. match session.as_object() {
  332. Some(obj) => {
  333. debug!(target: "dnetview", "parse_outbound() obj {:?}", session);
  334. let addr = obj.get("addr").unwrap().as_str().unwrap().to_string();
  335. let state: Option<String> = match obj.get("state") {
  336. Some(state) => Some(state.as_str().unwrap().to_string()),
  337. None => None,
  338. };
  339. let info: serde_json::Map<String, Value> =
  340. serde_json::from_value(obj.get("info").unwrap().clone()).unwrap();
  341. let slot_addr = info.get("addr").unwrap().as_str().unwrap().to_string();
  342. let random_id = info.get("random_id").unwrap().as_u64().unwrap();
  343. let remote_id = info.get("remote_id").unwrap().as_str().unwrap().to_string();
  344. let info_id = make_info_id(&random_id)?;
  345. let log: Vec<(NanoTimestamp, String, String)> =
  346. serde_json::from_value(info.get("log").unwrap().clone()).unwrap();
  347. // ...
  348. let node_id = node_id.to_string();
  349. let is_empty = false;
  350. let slot = SlotInfo::new(
  351. info_id.clone(),
  352. node_id.clone(),
  353. slot_addr,
  354. random_id,
  355. remote_id,
  356. log,
  357. is_empty,
  358. );
  359. let session = SessionInfo::new(
  360. session_id.clone(),
  361. node_id.clone(),
  362. addr.clone(),
  363. state,
  364. slot,
  365. is_empty,
  366. );
  367. session_info.push(session);
  368. }
  369. None => {
  370. // TODO: clean up empty info boilerplate.
  371. slot_count += 1;
  372. let info_id = make_empty_id(node_id, &prefix, slot_count)?;
  373. let node_id = node_id.to_string();
  374. let addr = "Null".to_string();
  375. let random_id = 0;
  376. let remote_id = "Null".to_string();
  377. let log = Vec::new();
  378. let is_empty = true;
  379. let slot = SlotInfo::new(
  380. info_id.clone(),
  381. node_id.clone(),
  382. addr.clone(),
  383. random_id,
  384. remote_id,
  385. log,
  386. is_empty,
  387. );
  388. let is_empty = true;
  389. let state = None;
  390. let session = SessionInfo::new(
  391. session_id.clone(),
  392. node_id.clone(),
  393. addr.clone(),
  394. state,
  395. slot,
  396. is_empty,
  397. );
  398. session_info.push(session);
  399. }
  400. }
  401. }
  402. Ok(session_info)
  403. }
  404. async fn parse_hosts(&self, hosts: &Value) -> DnetViewResult<Vec<String>> {
  405. match hosts.as_array() {
  406. Some(h) => match h.is_empty() {
  407. true => Ok(Vec::new()),
  408. false => {
  409. let hosts: Vec<String> =
  410. h.iter().map(|addr| addr.as_str().unwrap().to_string()).collect();
  411. Ok(hosts)
  412. }
  413. },
  414. None => {
  415. if hosts.is_null() {
  416. // TODO: this should probs just say null
  417. let h = Vec::new();
  418. return Ok(h)
  419. }
  420. debug!("dnetview::parse_hosts() hosts returns None and !is_null() {}", hosts);
  421. Err(DnetViewError::ValueIsNotObject)
  422. }
  423. }
  424. }
  425. }