Jelajahi Sumber

dnetview: if the RPC cannot connect, render the node as offline.

lunar-mining 4 tahun lalu
induk
melakukan
40b41b527a
3 mengubah file dengan 119 tambahan dan 72 penghapusan
  1. 45 23
      bin/dnetview/src/main.rs
  2. 4 4
      bin/dnetview/src/model.rs
  3. 70 45
      bin/dnetview/src/view.rs

+ 45 - 23
bin/dnetview/src/main.rs

@@ -16,7 +16,7 @@ use tui::{
 use url::Url;
 use url::Url;
 
 
 use darkfi::{
 use darkfi::{
-    error::Result,
+    error::{Error, Result},
     rpc::{jsonrpc, rpcclient::RpcClient},
     rpc::{jsonrpc, rpcclient::RpcClient},
     util::{
     util::{
         async_util,
         async_util,
@@ -34,7 +34,7 @@ use dnetview::{
     view::{IdListView, NodeInfoView, View},
     view::{IdListView, NodeInfoView, View},
 };
 };
 
 
-use log::debug;
+use log::{debug, error};
 
 
 struct DnetView {
 struct DnetView {
     name: String,
     name: String,
@@ -58,7 +58,10 @@ impl DnetView {
     // <-- {"jsonrpc": "2.0", "result": {"nodeID": [], "nodeinfo" [], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": {"nodeID": [], "nodeinfo" [], "id": 42}
     async fn get_info(&self) -> Result<Value> {
     async fn get_info(&self) -> Result<Value> {
         let req = jsonrpc::request(json!("get_info"), json!([]));
         let req = jsonrpc::request(json!("get_info"), json!([]));
-        Ok(self.rpc_client.request(req).await?)
+        match self.rpc_client.request(req).await {
+            Ok(req) => return Ok(req),
+            Err(_e) => return Err(Error::OperationFailed),
+        }
     }
     }
 }
 }
 
 
@@ -128,17 +131,33 @@ async fn poll_and_update_model(
 
 
 async fn poll(client: DnetView, model: Arc<Model>) -> DnetViewResult<()> {
 async fn poll(client: DnetView, model: Arc<Model>) -> DnetViewResult<()> {
     loop {
     loop {
-        let reply = client.get_info().await?;
-
-        if reply.as_object().is_some() && !reply.as_object().unwrap().is_empty() {
-            parse_data(reply.as_object().unwrap(), &client, model.clone()).await?;
-        } else {
-            return Err(DnetViewError::EmptyRpcReply)
+        match client.get_info().await {
+            Ok(reply) => {
+                if reply.as_object().is_some() && !reply.as_object().unwrap().is_empty() {
+                    parse_data(reply.as_object().unwrap(), &client, model.clone()).await?;
+                } else {
+                    return Err(DnetViewError::EmptyRpcReply)
+                }
+            }
+            Err(e) => {
+                parse_offline(&client, model.clone()).await?;
+                error!("{:?}", e);
+            }
         }
         }
         async_util::sleep(2).await;
         async_util::sleep(2).await;
     }
     }
 }
 }
 
 
+async fn parse_offline(client: &DnetView, model: Arc<Model>) -> DnetViewResult<()> {
+    let node_name = &client.name;
+    let node_id = make_node_id(node_name)?;
+    let node = NodeInfo::new(node_id.clone(), node_name.to_string(), None, None);
+
+    update_node(model.clone(), node.clone(), node_id.clone()).await;
+    update_selectable_and_ids(model.clone(), None, node.clone()).await?;
+    Ok(())
+}
+
 async fn parse_data(
 async fn parse_data(
     reply: &serde_json::Map<String, Value>,
     reply: &serde_json::Map<String, Value>,
     client: &DnetView,
     client: &DnetView,
@@ -164,10 +183,11 @@ async fn parse_data(
     sessions.push(out_session.clone());
     sessions.push(out_session.clone());
     sessions.push(man_session.clone());
     sessions.push(man_session.clone());
 
 
-    let node = NodeInfo::new(node_id.clone(), node_name.to_string(), sessions.clone(), ext_addr);
+    let node =
+        NodeInfo::new(node_id.clone(), node_name.to_string(), Some(sessions.clone()), ext_addr);
 
 
     update_node(model.clone(), node.clone(), node_id.clone()).await;
     update_node(model.clone(), node.clone(), node_id.clone()).await;
-    update_selectable_and_ids(model.clone(), sessions.clone(), node.clone()).await?;
+    update_selectable_and_ids(model.clone(), Some(sessions.clone()), node.clone()).await?;
     update_msgs(model.clone(), sessions.clone()).await?;
     update_msgs(model.clone(), sessions.clone()).await?;
 
 
     //debug!("IDS: {:?}", model.ids.lock().await);
     //debug!("IDS: {:?}", model.ids.lock().await);
@@ -209,30 +229,32 @@ async fn update_node(model: Arc<Model>, node: NodeInfo, id: String) {
 
 
 async fn update_selectable_and_ids(
 async fn update_selectable_and_ids(
     model: Arc<Model>,
     model: Arc<Model>,
-    sessions: Vec<SessionInfo>,
+    sessions: Option<Vec<SessionInfo>>,
     node: NodeInfo,
     node: NodeInfo,
 ) -> DnetViewResult<()> {
 ) -> DnetViewResult<()> {
     let node_obj = SelectableObject::Node(node.clone());
     let node_obj = SelectableObject::Node(node.clone());
     model.selectables.lock().await.insert(node.id.clone(), node_obj);
     model.selectables.lock().await.insert(node.id.clone(), node_obj);
     update_ids(model.clone(), node.id.clone()).await;
     update_ids(model.clone(), node.id.clone()).await;
-    for session in sessions.clone() {
-        let session_obj = SelectableObject::Session(session.clone());
-        model.selectables.lock().await.insert(session.clone().id, session_obj);
-        update_ids(model.clone(), session.clone().id).await;
-        for connect in session.children {
-            let connect_obj = SelectableObject::Connect(connect.clone());
-            model.selectables.lock().await.insert(connect.clone().id, connect_obj);
-            update_ids(model.clone(), connect.clone().id).await;
+    if sessions.is_some() {
+        for session in sessions.unwrap().clone() {
+            let session_obj = SelectableObject::Session(session.clone());
+            model.selectables.lock().await.insert(session.clone().id, session_obj);
+            update_ids(model.clone(), session.clone().id).await;
+            for connect in session.children {
+                let connect_obj = SelectableObject::Connect(connect.clone());
+                model.selectables.lock().await.insert(connect.clone().id, connect_obj);
+                update_ids(model.clone(), connect.clone().id).await;
+            }
         }
         }
     }
     }
     Ok(())
     Ok(())
 }
 }
 
 
-async fn parse_external_addr(addr: &Option<&Value>) -> DnetViewResult<String> {
+async fn parse_external_addr(addr: &Option<&Value>) -> DnetViewResult<Option<String>> {
     match addr {
     match addr {
         Some(addr) => match addr.as_str() {
         Some(addr) => match addr.as_str() {
-            Some(addr) => return Ok(addr.to_string()),
-            None => return Ok("null".to_string()),
+            Some(addr) => return Ok(Some(addr.to_string())),
+            None => return Ok(None),
         },
         },
         None => Err(DnetViewError::NoExternalAddr),
         None => Err(DnetViewError::NoExternalAddr),
     }
     }

+ 4 - 4
bin/dnetview/src/model.rs

@@ -39,16 +39,16 @@ impl Model {
 pub struct NodeInfo {
 pub struct NodeInfo {
     pub id: String,
     pub id: String,
     pub name: String,
     pub name: String,
-    pub children: Vec<SessionInfo>,
-    pub external_addr: String,
+    pub children: Option<Vec<SessionInfo>>,
+    pub external_addr: Option<String>,
 }
 }
 
 
 impl NodeInfo {
 impl NodeInfo {
     pub fn new(
     pub fn new(
         id: String,
         id: String,
         name: String,
         name: String,
-        children: Vec<SessionInfo>,
-        external_addr: String,
+        children: Option<Vec<SessionInfo>>,
+        external_addr: Option<String>,
     ) -> NodeInfo {
     ) -> NodeInfo {
         NodeInfo { id, name, children, external_addr }
         NodeInfo { id, name, children, external_addr }
     }
     }

+ 70 - 45
bin/dnetview/src/view.rs

@@ -5,7 +5,7 @@ use tui::widgets::ListState;
 use tui::{
 use tui::{
     backend::Backend,
     backend::Backend,
     layout::{Constraint, Direction, Layout, Rect},
     layout::{Constraint, Direction, Layout, Rect},
-    style::Style,
+    style::{Color, Modifier, Style},
     text::{Span, Spans},
     text::{Span, Spans},
     widgets::{Block, Borders, List, ListItem, Paragraph},
     widgets::{Block, Borders, List, ListItem, Paragraph},
     Frame,
     Frame,
@@ -64,11 +64,13 @@ impl View {
     fn update_active_ids(&mut self) {
     fn update_active_ids(&mut self) {
         for info in self.nodes.infos.values() {
         for info in self.nodes.infos.values() {
             self.active_ids.ids.insert(info.id.to_string());
             self.active_ids.ids.insert(info.id.to_string());
-            for child in &info.children {
-                if !child.is_empty == true {
-                    self.active_ids.ids.insert(child.id.to_string());
-                    for child in &child.children {
+            if info.children.is_some() {
+                for child in info.children.as_ref().unwrap() {
+                    if !child.is_empty == true {
                         self.active_ids.ids.insert(child.id.to_string());
                         self.active_ids.ids.insert(child.id.to_string());
+                        for child in &child.children {
+                            self.active_ids.ids.insert(child.id.to_string());
+                        }
                     }
                     }
                 }
                 }
             }
             }
@@ -126,49 +128,68 @@ impl View {
         let mut ids: Vec<String> = Vec::new();
         let mut ids: Vec<String> = Vec::new();
 
 
         for info in self.nodes.infos.values() {
         for info in self.nodes.infos.values() {
-            let name_span = Span::raw(&info.name);
-            let lines = vec![Spans::from(name_span)];
-            let names = ListItem::new(lines);
-            nodes.push(names);
-            ids.push(info.id.clone());
-            for session in &info.children {
-                if !session.is_empty == true {
-                    let name = Span::styled(format!("    {}", session.name), style);
-                    let lines = vec![Spans::from(name)];
+            match &info.children {
+                Some(children) => {
+                    let name_span = Span::raw(&info.name);
+                    let lines = vec![Spans::from(name_span)];
                     let names = ListItem::new(lines);
                     let names = ListItem::new(lines);
                     nodes.push(names);
                     nodes.push(names);
-                    ids.push(session.id.clone());
-                    for connection in &session.children {
-                        let mut info = Vec::new();
-                        let name = Span::styled(format!("        {}", connection.addr), style);
-                        info.push(name);
-                        match connection.last_status.as_str() {
-                            "recv" => {
-                                let msg = Span::styled(
-                                    format!("                    [R: {}]", connection.last_msg),
-                                    style,
-                                );
-                                info.push(msg);
-                            }
-                            "sent" => {
-                                let msg = Span::styled(
-                                    format!("                    [S: {}]", connection.last_msg),
-                                    style,
-                                );
-                                info.push(msg);
-                            }
-                            "Null" => {
-                                // Empty msg log. Do nothing
+                    ids.push(info.id.clone());
+                    for session in children {
+                        if !session.is_empty == true {
+                            let name = Span::styled(format!("    {}", session.name), style);
+                            let lines = vec![Spans::from(name)];
+                            let names = ListItem::new(lines);
+                            nodes.push(names);
+                            ids.push(session.id.clone());
+                            for connection in &session.children {
+                                let mut info = Vec::new();
+                                let name =
+                                    Span::styled(format!("        {}", connection.addr), style);
+                                info.push(name);
+                                match connection.last_status.as_str() {
+                                    "recv" => {
+                                        let msg = Span::styled(
+                                            format!(
+                                                "                    [R: {}]",
+                                                connection.last_msg
+                                            ),
+                                            style,
+                                        );
+                                        info.push(msg);
+                                    }
+                                    "sent" => {
+                                        let msg = Span::styled(
+                                            format!(
+                                                "                    [S: {}]",
+                                                connection.last_msg
+                                            ),
+                                            style,
+                                        );
+                                        info.push(msg);
+                                    }
+                                    "Null" => {
+                                        // Empty msg log. Do nothing
+                                    }
+                                    data => {
+                                        return Err(DnetViewError::UnexpectedData(data.to_string()))
+                                    }
+                                }
                             }
                             }
-                            data => return Err(DnetViewError::UnexpectedData(data.to_string())),
                         }
                         }
-
-                        let lines = vec![Spans::from(info)];
-                        let names = ListItem::new(lines);
-                        nodes.push(names);
-                        ids.push(connection.id.clone());
                     }
                     }
                 }
                 }
+                None => {
+                    let style = Style::default().fg(Color::Blue).add_modifier(Modifier::ITALIC);
+                    let mut name = String::new();
+                    name.push_str(&info.name);
+                    name.push_str("(Offline)");
+                    let name_span = Span::styled(name, style);
+                    let lines = vec![Spans::from(name_span)];
+                    let names = ListItem::new(lines);
+                    nodes.push(names);
+                    ids.push(info.id.clone());
+                }
             }
             }
         }
         }
 
 
@@ -197,9 +218,13 @@ impl View {
 
 
             match info {
             match info {
                 Some(SelectableObject::Node(node)) => {
                 Some(SelectableObject::Node(node)) => {
-                    let node_info =
-                        Span::styled(format!("External addr: {}", node.external_addr), style);
-                    lines.push(Spans::from(node_info));
+                    if node.external_addr.is_some() {
+                        let node_info = Span::styled(
+                            format!("External addr: {}", node.external_addr.as_ref().unwrap()),
+                            style,
+                        );
+                        lines.push(Spans::from(node_info));
+                    }
                 }
                 }
                 Some(SelectableObject::Session(session)) => {
                 Some(SelectableObject::Session(session)) => {
                     if session.accept_addr.is_some() {
                     if session.accept_addr.is_some() {