Explorar el Código

dnetview: improve NodeInfo data type + re-enable view

Pass inbound and outbound as two Vec<SessionInfo> into NodeInfo.
Update and re-enable UI.
lunar-mining hace 3 años
padre
commit
c80f53a322
Se han modificado 4 ficheros con 302 adiciones y 195 borrados
  1. 7 5
      bin/dnetview/src/model.rs
  2. 213 136
      bin/dnetview/src/parser.rs
  3. 3 2
      bin/dnetview/src/util.rs
  4. 79 52
      bin/dnetview/src/view.rs

+ 7 - 5
bin/dnetview/src/model.rs

@@ -63,7 +63,8 @@ pub struct NodeInfo {
     pub dnet_id: String,
     pub name: String,
     pub hosts: Vec<String>,
-    pub info: Vec<SessionInfo>,
+    pub inbound: Vec<SessionInfo>,
+    pub outbound: Vec<SessionInfo>,
     pub is_offline: bool,
 }
 
@@ -72,10 +73,11 @@ impl NodeInfo {
         dnet_id: String,
         name: String,
         hosts: Vec<String>,
-        info: Vec<SessionInfo>,
+        inbound: Vec<SessionInfo>,
+        outbound: Vec<SessionInfo>,
         is_offline: bool,
     ) -> Self {
-        Self { dnet_id, name, hosts, info, is_offline }
+        Self { dnet_id, name, hosts, inbound, outbound, is_offline }
     }
 }
 
@@ -109,7 +111,7 @@ pub struct SlotInfo {
     pub dnet_id: String,
     pub node_id: String,
     pub addr: String,
-    pub random_id: String,
+    pub random_id: u64,
     pub remote_id: String,
     pub log: Vec<(NanoTimestamp, String, String)>,
     pub is_empty: bool,
@@ -121,7 +123,7 @@ impl SlotInfo {
         dnet_id: String,
         node_id: String,
         addr: String,
-        random_id: String,
+        random_id: u64,
         remote_id: String,
         log: Vec<(NanoTimestamp, String, String)>,
         is_empty: bool,

+ 213 - 136
bin/dnetview/src/parser.rs

@@ -33,7 +33,7 @@ use crate::{
         LilithInfo, Model, NetworkInfo, NodeInfo, SelectableObject, Session, SessionInfo, SlotInfo,
     },
     rpc::RpcConnect,
-    util::{is_empty_session, make_connect_id, make_empty_id, make_node_id, make_session_id},
+    util::{is_empty_session, make_empty_id, make_info_id, make_node_id, make_session_id},
 };
 
 pub struct DataParser {
@@ -118,19 +118,19 @@ impl DataParser {
     }
 
     // If poll times out, inititalize data structures with empty values.
-    async fn parse_offline(&self, name: String) -> DnetViewResult<()> {
+    async fn parse_offline(&self, node_name: String) -> DnetViewResult<()> {
         let name = "Offline".to_string();
         let session_type = Session::Offline;
 
         let mut slots: Vec<SlotInfo> = Vec::new();
-        let mut info: Vec<SessionInfo> = Vec::new();
+        let mut sessions: Vec<SessionInfo> = Vec::new();
         let hosts = Vec::new();
 
-        let node_id = make_node_id(&name)?;
+        let node_id = make_node_id(&node_name)?;
         let dnet_id = make_empty_id(&node_id, &session_type, 0)?;
         let addr = "Null".to_string();
         let state = "Null".to_string();
-        let random_id = "Null".to_string();
+        let random_id = 0;
         let remote_id = "Null".to_string();
         let log = Vec::new();
         let is_empty = true;
@@ -155,11 +155,19 @@ impl DataParser {
             slots,
             is_empty,
         );
-        info.push(session_info);
+        sessions.push(session_info);
 
-        let node = NodeInfo::new(node_id.clone(), name.clone(), hosts, info.clone(), is_empty);
+        // TODO: clean this up
+        let node = NodeInfo::new(
+            node_id.clone(),
+            name.clone(),
+            hosts,
+            sessions.clone(),
+            sessions.clone(),
+            is_empty,
+        );
 
-        self.update_selectables(info, node).await?;
+        self.update_selectables(node).await?;
         Ok(())
     }
 
@@ -178,14 +186,10 @@ impl DataParser {
         let inbound = self.parse_inbound(inbound, &dnet_id).await?;
         let outbound = self.parse_outbound(outbound, &dnet_id).await?;
 
-        let mut info: Vec<SessionInfo> = Vec::new();
-        info.push(inbound.clone());
-        info.push(outbound.clone());
-
-        let node = NodeInfo::new(dnet_id, name, hosts, info.clone(), false);
+        let node = NodeInfo::new(dnet_id, name, hosts, inbound.clone(), outbound.clone(), false);
 
-        self.update_selectables(info.clone(), node).await?;
-        self.update_msgs(info.clone()).await?;
+        self.update_selectables(node).await?;
+        self.update_msgs(inbound.clone(), outbound.clone()).await?;
 
         Ok(())
     }
@@ -222,24 +226,24 @@ impl DataParser {
         Ok(())
     }
 
-    async fn update_msgs(&self, sessions: Vec<SessionInfo>) -> DnetViewResult<()> {
-        for session in sessions {
-            for connection in session.info {
-                if !self.model.msg_map.lock().await.contains_key(&connection.dnet_id) {
+    async fn update_msgs(
+        &self,
+        inbounds: Vec<SessionInfo>,
+        outbounds: Vec<SessionInfo>,
+    ) -> DnetViewResult<()> {
+        for inbound in inbounds {
+            for info in inbound.info {
+                if !self.model.msg_map.lock().await.contains_key(&info.dnet_id) {
                     // we don't have this ID: it is a new node
-                    self.model
-                        .msg_map
-                        .lock()
-                        .await
-                        .insert(connection.dnet_id, connection.log.clone());
+                    self.model.msg_map.lock().await.insert(info.dnet_id, info.log.clone());
                 } else {
                     // we have this id: append the msg values
-                    match self.model.msg_map.lock().await.entry(connection.dnet_id) {
+                    match self.model.msg_map.lock().await.entry(info.dnet_id) {
                         Entry::Vacant(e) => {
-                            e.insert(connection.log);
+                            e.insert(info.log);
                         }
                         Entry::Occupied(mut e) => {
-                            for msg in connection.log {
+                            for msg in info.log {
                                 e.get_mut().push(msg);
                             }
                         }
@@ -247,35 +251,70 @@ impl DataParser {
                 }
             }
         }
+        for outbound in outbounds {
+            for info in outbound.info {
+                if !self.model.msg_map.lock().await.contains_key(&info.dnet_id) {
+                    // we don't have this ID: it is a new node
+                    self.model.msg_map.lock().await.insert(info.dnet_id, info.log.clone());
+                } else {
+                    // we have this id: append the msg values
+                    match self.model.msg_map.lock().await.entry(info.dnet_id) {
+                        Entry::Vacant(e) => {
+                            e.insert(info.log);
+                        }
+                        Entry::Occupied(mut e) => {
+                            for msg in info.log {
+                                e.get_mut().push(msg);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
         Ok(())
     }
 
-    async fn update_selectables(
-        &self,
-        sessions: Vec<SessionInfo>,
-        node: NodeInfo,
-    ) -> DnetViewResult<()> {
+    async fn update_selectables(&self, node: NodeInfo) -> DnetViewResult<()> {
         if node.is_offline {
             let node_obj = SelectableObject::Node(node.clone());
             self.model.selectables.lock().await.insert(node.dnet_id.clone(), node_obj.clone());
         } else {
             let node_obj = SelectableObject::Node(node.clone());
             self.model.selectables.lock().await.insert(node.dnet_id.clone(), node_obj.clone());
-            for session in sessions {
-                if !session.is_empty {
-                    let session_obj = SelectableObject::Session(session.clone());
+            for inbound in node.inbound {
+                if !inbound.is_empty {
+                    let inbound_obj = SelectableObject::Session(inbound.clone());
+                    self.model
+                        .selectables
+                        .lock()
+                        .await
+                        .insert(inbound.clone().dnet_id, inbound_obj.clone());
+                    for info in inbound.info {
+                        let info_obj = SelectableObject::Connect(info.clone());
+                        self.model
+                            .selectables
+                            .lock()
+                            .await
+                            .insert(info.clone().dnet_id, info_obj.clone());
+                    }
+                }
+            }
+            for outbound in node.outbound {
+                if !outbound.is_empty {
+                    let outbound_obj = SelectableObject::Session(outbound.clone());
                     self.model
                         .selectables
                         .lock()
                         .await
-                        .insert(session.clone().dnet_id, session_obj.clone());
-                    for connect in session.info {
-                        let connect_obj = SelectableObject::Connect(connect.clone());
+                        .insert(outbound.clone().dnet_id, outbound_obj.clone());
+                    for info in outbound.info {
+                        let info_obj = SelectableObject::Connect(info.clone());
                         self.model
                             .selectables
                             .lock()
                             .await
-                            .insert(connect.clone().dnet_id, connect_obj.clone());
+                            .insert(info.clone().dnet_id, info_obj.clone());
                     }
                 }
             }
@@ -283,35 +322,43 @@ impl DataParser {
         Ok(())
     }
 
-    async fn _parse_external_addr(&self, addr: &Option<&Value>) -> DnetViewResult<Option<String>> {
-        match addr {
-            Some(addr) => match addr.as_str() {
-                Some(addr) => Ok(Some(addr.to_string())),
-                None => Ok(None),
-            },
-            None => Err(DnetViewError::NoExternalAddr),
-        }
-    }
-
-    async fn parse_inbound(&self, reply: &Value, node_id: &String) -> DnetViewResult<SessionInfo> {
+    //async fn _parse_external_addr(&self, addr: &Option<&Value>) -> DnetViewResult<Option<String>> {
+    //    match addr {
+    //        Some(addr) => match addr.as_str() {
+    //            Some(addr) => Ok(Some(addr.to_string())),
+    //            None => Ok(None),
+    //        },
+    //        None => Err(DnetViewError::NoExternalAddr),
+    //    }
+    //}
+
+    async fn parse_inbound(
+        &self,
+        reply: &Value,
+        node_id: &String,
+    ) -> DnetViewResult<Vec<SessionInfo>> {
         let name = "Inbound".to_string();
         let session_type = Session::Inbound;
-        let dnet_id = make_session_id(node_id, &session_type)?;
-        let mut info: Vec<SlotInfo> = Vec::new();
+        let session_id = make_session_id(node_id, &session_type)?;
+        let mut slots: Vec<SlotInfo> = Vec::new();
+        let mut sessions: Vec<SessionInfo> = Vec::new();
 
         // TODO: improve this ugly hack.
-        let slot_count = 0;
+        let mut slot_count = 0;
 
         // Dnetview is not enabled.
+        // TODO: print warning on view
         if reply.is_null() {
+            slot_count += 1;
             let dnet_id = make_empty_id(node_id, &session_type, slot_count)?;
             let node_id = node_id.to_string();
             let addr = "Null".to_string();
-            let random_id = "Null".to_string();
+            let random_id = 0;
             let remote_id = "Null".to_string();
             let log = Vec::new();
             let is_empty = true;
 
+            // info_id
             let slot = SlotInfo::new(
                 dnet_id.clone(),
                 node_id.clone(),
@@ -321,47 +368,51 @@ impl DataParser {
                 log,
                 is_empty,
             );
-            info.push(slot);
+            slots.push(slot);
             // Check whether the session is empty.
-            let is_empty = is_empty_session(&info);
+            // TODO
+            // let is_empty = is_empty_session(&slot);
+            let is_empty = true;
 
             let addr = "Null".to_string();
             let state = "Null".to_string();
             let session = SessionInfo::new(
-                dnet_id.clone(),
+                session_id.clone(),
                 node_id.clone(),
-                name,
+                name.clone(),
                 addr,
                 state,
-                info,
+                slots.clone(),
                 is_empty,
             );
-
-            return Ok(session)
+            sessions.push(session);
         }
 
         match reply.get("inbound") {
             Some(session) => {
                 let inbound: Vec<serde_json::Map<String, Value>> =
                     serde_json::from_value(session.clone()).unwrap();
-                for slot in inbound {
-                    let addr = slot.get("addr").unwrap().as_str().unwrap().to_string();
-                    let slot_info: serde_json::Map<String, Value> =
-                        serde_json::from_value(slot.get("info").unwrap().clone()).unwrap();
+                for session in inbound {
+                    let addr = session.get("addr").unwrap().as_str().unwrap().to_string();
+                    let info: serde_json::Map<String, Value> =
+                        serde_json::from_value(session.get("info").unwrap().clone()).unwrap();
 
-                    let slot_addr = slot_info.get("addr").unwrap().as_str().unwrap().to_string();
-                    let random_id =
-                        slot_info.get("random_id").unwrap().as_str().unwrap().to_string();
-                    let remote_id =
-                        slot_info.get("remote_id").unwrap().as_str().unwrap().to_string();
+                    let slot_addr = info.get("addr").unwrap().as_str().unwrap().to_string();
+                    let random_id = info.get("random_id").unwrap().as_u64().unwrap();
+                    let remote_id = info.get("remote_id").unwrap().as_str().unwrap().to_string();
+                    let info_id = make_info_id(&random_id)?;
 
                     let log: Vec<(NanoTimestamp, String, String)> =
-                        serde_json::from_value(slot_info.get("log").unwrap().clone()).unwrap();
+                        serde_json::from_value(info.get("log").unwrap().clone()).unwrap();
+
+                    // ...
                     let node_id = node_id.to_string();
                     let is_empty = false;
+                    // TODO: make this an option
+                    let state = String::new();
 
                     let slot = SlotInfo::new(
-                        dnet_id.clone(),
+                        info_id.clone(),
                         node_id.clone(),
                         slot_addr,
                         random_id,
@@ -369,80 +420,88 @@ impl DataParser {
                         log,
                         is_empty,
                     );
-                    info.push(slot);
-                }
+                    slots.push(slot);
 
-                // TODO: fixme
-                let addr = String::new();
-                // TODO: this should be an option
-                let state = String::new();
-                let node_id = node_id.to_string();
-                let is_empty = false;
-                let session =
-                    SessionInfo::new(dnet_id, node_id.clone(), name, addr, state, info, is_empty);
-                Ok(session)
+                    let session = SessionInfo::new(
+                        session_id.clone(),
+                        node_id.clone(),
+                        name.clone(),
+                        addr,
+                        state,
+                        slots.clone(),
+                        is_empty,
+                    );
+                    sessions.push(session);
+                }
             }
             None => {
                 // Empty data. Initialize empty values.
                 // TODO: clean up empty info boilerplate.
-                let dnet_id = make_empty_id(node_id, &session_type, slot_count)?;
+                slot_count += 1;
+                let info_id = make_empty_id(node_id, &session_type, slot_count)?;
                 let node_id = node_id.to_string();
                 let addr = "Null".to_string();
-                let random_id = "Null".to_string();
+                let random_id = 0;
                 let remote_id = "Null".to_string();
                 let log = Vec::new();
                 let is_empty = true;
 
                 let slot = SlotInfo::new(
-                    dnet_id.clone(),
+                    info_id.clone(),
                     node_id.clone(),
-                    addr,
+                    addr.clone(),
                     random_id,
                     remote_id,
                     log,
                     is_empty,
                 );
-                info.push(slot);
+                slots.push(slot);
                 // Check whether the session is empty.
-                let is_empty = is_empty_session(&info);
+                let is_empty = is_empty_session(&slots);
 
-                let addr = "Null".to_string();
                 let state = "Null".to_string();
                 let session = SessionInfo::new(
-                    dnet_id.clone(),
+                    session_id.clone(),
                     node_id.clone(),
                     name,
                     addr,
                     state,
-                    info,
+                    slots,
                     is_empty,
                 );
-                return Ok(session)
+                sessions.push(session);
             }
         }
+        Ok(sessions)
     }
 
-    async fn parse_outbound(&self, reply: &Value, node_id: &String) -> DnetViewResult<SessionInfo> {
+    async fn parse_outbound(
+        &self,
+        reply: &Value,
+        node_id: &String,
+    ) -> DnetViewResult<Vec<SessionInfo>> {
         let name = "Outbound".to_string();
         let session_type = Session::Outbound;
-        let dnet_id = make_session_id(node_id, &session_type)?;
-        let mut info: Vec<SlotInfo> = Vec::new();
+        let session_id = make_session_id(node_id, &session_type)?;
+        let mut slots: Vec<SlotInfo> = Vec::new();
+        let mut sessions: Vec<SessionInfo> = Vec::new();
 
         // TODO: improve this ugly hack.
         let mut slot_count = 0;
 
         // Dnetview is not enabled.
         if reply.is_null() {
-            let dnet_id = make_empty_id(&node_id, &session_type, slot_count)?;
+            slot_count += 1;
+            let info_id = make_empty_id(&node_id, &session_type, slot_count)?;
             let node_id = node_id.to_string();
             let addr = "Null".to_string();
-            let random_id = "Null".to_string();
+            let random_id = 0;
             let remote_id = "Null".to_string();
             let log = Vec::new();
             let is_empty = false;
 
             let slot = SlotInfo::new(
-                dnet_id.clone(),
+                info_id.clone(),
                 node_id.clone(),
                 addr,
                 random_id,
@@ -450,32 +509,48 @@ impl DataParser {
                 log,
                 is_empty,
             );
-            info.push(slot);
+            slots.push(slot);
+            // Check whether the session is empty.
+            let is_empty = is_empty_session(&slots);
+
+            let addr = "Null".to_string();
+            let state = "Null".to_string();
+            let session = SessionInfo::new(
+                session_id.clone(),
+                node_id.clone(),
+                name.clone(),
+                addr,
+                state,
+                slots.clone(),
+                is_empty,
+            );
+            sessions.push(session);
         }
 
         match reply.get("outbound") {
             Some(session) => {
-                let inbound: Vec<serde_json::Map<String, Value>> =
+                let outbound: Vec<serde_json::Map<String, Value>> =
                     serde_json::from_value(session.clone()).unwrap();
-                for slot in inbound {
-                    let addr = slot.get("addr").unwrap().as_str().unwrap().to_string();
-                    let state = slot.get("state").unwrap().as_str().unwrap().to_string();
-                    let slot_info: serde_json::Map<String, Value> =
-                        serde_json::from_value(slot.get("info").unwrap().clone()).unwrap();
-
-                    let slot_addr = slot_info.get("addr").unwrap().as_str().unwrap().to_string();
-                    let random_id =
-                        slot_info.get("random_id").unwrap().as_str().unwrap().to_string();
-                    let remote_id =
-                        slot_info.get("remote_id").unwrap().as_str().unwrap().to_string();
+                for session in outbound {
+                    let addr = session.get("addr").unwrap().as_str().unwrap().to_string();
+                    let state = session.get("state").unwrap().as_str().unwrap().to_string();
+                    let info: serde_json::Map<String, Value> =
+                        serde_json::from_value(session.get("info").unwrap().clone()).unwrap();
+
+                    let slot_addr = info.get("addr").unwrap().as_str().unwrap().to_string();
+                    let random_id = info.get("random_id").unwrap().as_u64().unwrap();
+                    let remote_id = info.get("remote_id").unwrap().as_str().unwrap().to_string();
+                    let info_id = make_info_id(&random_id)?;
 
                     let log: Vec<(NanoTimestamp, String, String)> =
-                        serde_json::from_value(slot_info.get("log").unwrap().clone()).unwrap();
+                        serde_json::from_value(info.get("log").unwrap().clone()).unwrap();
+
+                    // ...
                     let node_id = node_id.to_string();
                     let is_empty = false;
 
                     let slot = SlotInfo::new(
-                        dnet_id.clone(),
+                        info_id.clone(),
                         node_id.clone(),
                         slot_addr,
                         random_id,
@@ -483,57 +558,59 @@ impl DataParser {
                         log,
                         is_empty,
                     );
-                    info.push(slot);
-                }
+                    slots.push(slot);
 
-                // TODO: fixme
-                let addr = String::new();
-                // TODO: this should be an option
-                let state = String::new();
-                let node_id = node_id.to_string();
-                let is_empty = false;
-                let session =
-                    SessionInfo::new(dnet_id, node_id.clone(), name, addr, state, info, is_empty);
-                Ok(session)
+                    let session = SessionInfo::new(
+                        session_id.clone(),
+                        node_id.clone(),
+                        name.clone(),
+                        addr.clone(),
+                        state,
+                        slots.clone(),
+                        is_empty,
+                    );
+                    sessions.push(session);
+                }
             }
             None => {
                 // Empty data. Initialize empty values.
                 // TODO: clean up empty info boilerplate.
-                let dnet_id = make_empty_id(node_id, &session_type, slot_count)?;
+                slot_count += 1;
+                let info_id = make_empty_id(node_id, &session_type, slot_count)?;
                 let node_id = node_id.to_string();
                 let addr = "Null".to_string();
-                let random_id = "Null".to_string();
+                let random_id = 0;
                 let remote_id = "Null".to_string();
                 let log = Vec::new();
                 let is_empty = true;
 
                 let slot = SlotInfo::new(
-                    dnet_id.clone(),
+                    info_id.clone(),
                     node_id.clone(),
-                    addr,
+                    addr.clone(),
                     random_id,
                     remote_id,
                     log,
                     is_empty,
                 );
-                info.push(slot);
+                slots.push(slot);
                 // Check whether the session is empty.
-                let is_empty = is_empty_session(&info);
+                let is_empty = is_empty_session(&slots);
 
-                let addr = "Null".to_string();
                 let state = "Null".to_string();
                 let session = SessionInfo::new(
-                    dnet_id.clone(),
+                    session_id.clone(),
                     node_id.clone(),
                     name,
-                    addr,
+                    addr.clone(),
                     state,
-                    info,
+                    slots,
                     is_empty,
                 );
-                return Ok(session)
+                sessions.push(session);
             }
         }
+        Ok(sessions)
     }
 
     async fn parse_hosts(&self, hosts: &Value) -> DnetViewResult<Vec<String>> {

+ 3 - 2
bin/dnetview/src/util.rs

@@ -49,9 +49,9 @@ pub fn make_session_id(node_id: &str, session: &Session) -> Result<String> {
     Ok(id)
 }
 
-pub fn make_connect_id(id: &u64) -> Result<String> {
+pub fn make_info_id(id: &u64) -> Result<String> {
     let mut id = hex::encode(id.to_ne_bytes());
-    id.insert_str(0, "CONNECT");
+    id.insert_str(0, "INFO");
     Ok(id)
 }
 
@@ -118,6 +118,7 @@ pub fn make_empty_id(node_id: &str, session: &Session, count: u64) -> Result<Str
     Ok(id)
 }
 
+// TODO: Rename to is empty slot.
 pub fn is_empty_session(connects: &[SlotInfo]) -> bool {
     return connects.iter().all(|conn| conn.is_empty)
 }

+ 79 - 52
bin/dnetview/src/view.rs

@@ -17,6 +17,7 @@
  */
 
 use std::collections::HashMap;
+//use log::debug;
 
 use tui::{
     backend::Backend,
@@ -92,14 +93,26 @@ impl<'a> View {
                         self.ordered_list.push(node.dnet_id.clone());
                     }
                     if !node.is_offline {
-                        for session in &node.info {
-                            if !session.is_empty {
-                                if !self.ordered_list.iter().any(|i| i == &session.dnet_id) {
-                                    self.ordered_list.push(session.dnet_id.clone());
+                        for inbound in &node.inbound {
+                            if !inbound.is_empty {
+                                if !self.ordered_list.iter().any(|i| i == &inbound.dnet_id) {
+                                    self.ordered_list.push(inbound.dnet_id.clone());
                                 }
-                                for connection in &session.info {
-                                    if !self.ordered_list.iter().any(|i| i == &connection.dnet_id) {
-                                        self.ordered_list.push(connection.dnet_id.clone());
+                                for info in &inbound.info {
+                                    if !self.ordered_list.iter().any(|i| i == &info.dnet_id) {
+                                        self.ordered_list.push(info.dnet_id.clone());
+                                    }
+                                }
+                            }
+                        }
+                        for outbound in &node.outbound {
+                            if !outbound.is_empty {
+                                if !self.ordered_list.iter().any(|i| i == &outbound.dnet_id) {
+                                    self.ordered_list.push(outbound.dnet_id.clone());
+                                }
+                                for info in &outbound.info {
+                                    if !self.ordered_list.iter().any(|i| i == &info.dnet_id) {
+                                        self.ordered_list.push(info.dnet_id.clone());
                                     }
                                 }
                             }
@@ -201,38 +214,71 @@ impl<'a> View {
                         let lines = vec![Spans::from(name_span)];
                         let names = ListItem::new(lines);
                         nodes.push(names);
-                        for session in &node.info {
-                            if !session.is_empty {
-                                let name = Span::styled(format!("    {}", session.name), style);
+
+                        for inbound in &node.inbound {
+                            if !inbound.is_empty {
+                                let name = Span::styled(format!("    {}", inbound.name), style);
                                 let lines = vec![Spans::from(name)];
                                 let names = ListItem::new(lines);
                                 nodes.push(names);
-                                for connection in &session.info {
-                                    let mut info = Vec::new();
-                                    match connection.addr.as_str() {
+                                for info in &inbound.info {
+                                    let mut infos = Vec::new();
+                                    match info.addr.as_str() {
                                         "Null" => {
                                             let style = Style::default()
                                                 .fg(Color::Blue)
                                                 .add_modifier(Modifier::ITALIC);
                                             let name = Span::styled(
-                                                format!("        {} ", connection.addr),
+                                                format!("        {} ", info.addr),
                                                 style,
                                             );
-                                            info.push(name);
+                                            infos.push(name);
                                         }
                                         addr => {
                                             let name = Span::styled(
-                                                format!(
-                                                    "        {} ({})",
-                                                    addr, connection.remote_id
-                                                ),
+                                                format!("        {} ({})", addr, info.remote_id),
                                                 style,
                                             );
-                                            info.push(name);
+                                            infos.push(name);
                                         }
                                     }
 
-                                    let lines = vec![Spans::from(info)];
+                                    let lines = vec![Spans::from(infos)];
+                                    let names = ListItem::new(lines);
+                                    nodes.push(names);
+                                }
+                            }
+                        }
+
+                        for outbound in &node.outbound {
+                            if !outbound.is_empty {
+                                let name = Span::styled(format!("    {}", outbound.name), style);
+                                let lines = vec![Spans::from(name)];
+                                let names = ListItem::new(lines);
+                                nodes.push(names);
+                                for info in &outbound.info {
+                                    let mut infos = Vec::new();
+                                    match info.addr.as_str() {
+                                        "Null" => {
+                                            let style = Style::default()
+                                                .fg(Color::Blue)
+                                                .add_modifier(Modifier::ITALIC);
+                                            let name = Span::styled(
+                                                format!("        {} ", info.addr),
+                                                style,
+                                            );
+                                            infos.push(name);
+                                        }
+                                        addr => {
+                                            let name = Span::styled(
+                                                format!("        {} ({})", addr, info.remote_id),
+                                                style,
+                                            );
+                                            infos.push(name);
+                                        }
+                                    }
+
+                                    let lines = vec![Spans::from(infos)];
                                     let names = ListItem::new(lines);
                                     nodes.push(names);
                                 }
@@ -263,12 +309,12 @@ impl<'a> View {
         Ok(())
     }
 
-    fn parse_msg_list(&self, connect_id: String) -> DnetViewResult<List<'a>> {
+    fn parse_msg_list(&self, info_id: String) -> DnetViewResult<List<'a>> {
         let send_style = Style::default().fg(Color::LightCyan);
         let recv_style = Style::default().fg(Color::DarkGray);
         let mut texts = Vec::new();
         let mut lines = Vec::new();
-        let log = self.msg_list.msg_map.get(&connect_id);
+        let log = self.msg_list.msg_map.get(&info_id);
         match log {
             Some(values) => {
                 for (i, (t, k, v)) in values.iter().enumerate() {
@@ -315,38 +361,19 @@ impl<'a> View {
                 Some(SelectableObject::Node(node)) => {
                     //debug!(target: "dnetview", "render_info()::SelectableObject::Node");
                     lines.push(Spans::from(Span::styled("Type: Normal", style)));
-                    //match &node.external_addr {
-                    //    Some(addr) => {
-                    //        let node_info = Span::styled(format!("External addr: {}", addr), style);
-                    //        lines.push(Spans::from(node_info));
-                    //    }
-                    //    None => {
-                    //        let node_info = Span::styled("External addr: Null".to_string(), style);
-                    //        lines.push(Spans::from(node_info));
-                    //    }
-                    //}
-                    //lines.push(Spans::from(Span::styled(
-                    //    format!("P2P state: {}", node.state),
-                    //    style,
-                    //)));
+                    lines.push(Spans::from(Span::styled("Hosts:", style)));
+                    for host in &node.hosts {
+                        lines.push(Spans::from(Span::styled(format!("   {}", host), style)));
+                    }
                 }
                 Some(SelectableObject::Session(session)) => {
                     //debug!(target: "dnetview", "render_info()::SelectableObject::Session");
-                    //if session.addr.is_some() {
-                    //    let accept_addr = Span::styled(
-                    //        format!("Accept addr: {}", session.addr.as_ref().unwrap()),
-                    //        style,
-                    //    );
-                    //    lines.push(Spans::from(accept_addr));
-                    //}
-                    //if session.hosts.is_some() {
-                    //    let hosts = Span::styled("Hosts:".to_string(), style);
-                    //    lines.push(Spans::from(hosts));
-                    //    for host in session.hosts.as_ref().unwrap() {
-                    //        let host = Span::styled(format!("      {}", host), style);
-                    //        lines.push(Spans::from(host));
-                    //    }
-                    //}
+                    let addr = Span::styled(format!("Addr: {}", session.addr), style);
+                    lines.push(Spans::from(addr));
+
+                    // TODO: this will be an option
+                    let addr = Span::styled(format!("State: {}", session.state), style);
+                    lines.push(Spans::from(addr));
                 }
                 Some(SelectableObject::Connect(connect)) => {
                     //debug!(target: "dnetview", "render_info()::SelectableObject::Connect");