dnetview: various bug fixes and cleanup

* fix bug that was multiplying the number of inbound and outbounds due to including null() sessions in a loop
* stop looping through session.info in make_ordered_list (it's not a vew now)
* create a specific networkID for lilith networks (better debugging)
* rename Connect to Slot
This commit is contained in:
lunar-mining
2023-08-06 10:04:41 +02:00
parent 11250d1b6c
commit 526a4c7e77
4 changed files with 152 additions and 155 deletions

View File

@@ -29,7 +29,7 @@ type MsgMap = Mutex<HashMap<String, MsgLog>>;
pub enum Session {
Inbound,
Outbound,
Manual,
//Manual,
Offline,
}
@@ -39,7 +39,7 @@ pub enum SelectableObject {
Lilith(LilithInfo),
Network(NetworkInfo),
Session(SessionInfo),
Connect(SlotInfo),
Slot(SlotInfo),
}
#[derive(Debug)]
@@ -88,6 +88,7 @@ pub struct SessionInfo {
pub addr: String,
pub state: Option<String>,
pub info: SlotInfo,
pub sort: Session,
pub is_empty: bool,
}
@@ -98,9 +99,10 @@ impl SessionInfo {
addr: String,
state: Option<String>,
info: SlotInfo,
sort: Session,
is_empty: bool,
) -> Self {
Self { dnet_id, node_id, addr, state, info, is_empty }
Self { dnet_id, node_id, addr, state, info, sort, is_empty }
}
}

View File

@@ -33,7 +33,7 @@ use crate::{
LilithInfo, Model, NetworkInfo, NodeInfo, SelectableObject, Session, SessionInfo, SlotInfo,
},
rpc::RpcConnect,
util::{make_empty_id, make_info_id, make_node_id, make_session_id},
util::{make_empty_id, make_info_id, make_network_id, make_node_id, make_session_id},
};
pub struct DataParser {
@@ -93,7 +93,6 @@ impl DataParser {
// Parse response
match response {
Ok(reply) => {
debug!("dnetview:: poll() reply {:?}", reply);
if reply.as_object().is_none() || reply.as_object().unwrap().is_empty() {
return Err(DnetViewError::EmptyRpcReply)
}
@@ -121,13 +120,13 @@ impl DataParser {
async fn parse_offline(&self, node_name: String) -> DnetViewResult<()> {
debug!(target: "dnetview", "parse_offline() START");
let name = "Offline".to_string();
let session_type = Session::Offline;
let sort = Session::Offline;
let mut sessions: Vec<SessionInfo> = Vec::new();
let hosts = Vec::new();
let node_id = make_node_id(&node_name)?;
let dnet_id = make_empty_id(&node_id, &session_type, 0)?;
let dnet_id = make_empty_id(&node_id, &sort, 0)?;
let addr = "Null".to_string();
let state = None;
let random_id = 0;
@@ -148,10 +147,10 @@ impl DataParser {
let session_info = SessionInfo::new(
dnet_id,
node_id.clone(),
//name.clone(),
addr.clone(),
state,
slot,
sort.clone(),
is_empty,
);
sessions.push(session_info);
@@ -204,7 +203,7 @@ impl DataParser {
let mut networks = vec![];
for spawn in spawns {
let name = spawn.get("name").unwrap().as_str().unwrap().to_string();
let id = make_node_id(&name)?;
let id = make_network_id(&name)?;
let urls: Vec<String> =
serde_json::from_value(spawn.get("urls").unwrap().clone()).unwrap();
let nodes: Vec<String> =
@@ -293,7 +292,7 @@ impl DataParser {
.lock()
.await
.insert(inbound.clone().dnet_id, inbound_obj.clone());
let info_obj = SelectableObject::Connect(inbound.info.clone());
let info_obj = SelectableObject::Slot(inbound.info.clone());
self.model
.selectables
.lock()
@@ -309,7 +308,7 @@ impl DataParser {
.lock()
.await
.insert(outbound.clone().dnet_id, outbound_obj.clone());
let info_obj = SelectableObject::Connect(outbound.info.clone());
let info_obj = SelectableObject::Slot(outbound.info.clone());
self.model
.selectables
.lock()
@@ -325,9 +324,9 @@ impl DataParser {
&self,
reply: &Value,
node_id: &String,
prefix: Session,
sort: Session,
) -> DnetViewResult<Vec<SessionInfo>> {
let session_id = make_session_id(&node_id, &prefix)?;
let session_id = make_session_id(&node_id, &sort)?;
let mut session_info: Vec<SessionInfo> = Vec::new();
// TODO: improve this ugly hack.
@@ -335,15 +334,14 @@ impl DataParser {
// Dnetview is not enabled.
if reply.is_null() {
debug!(target: "dnetview", "parse_outbound() reply.is_null() == True");
slot_count += 1;
let info_id = make_empty_id(&node_id, &prefix, slot_count)?;
let info_id = make_empty_id(&node_id, &sort, slot_count)?;
let node_id = node_id.to_string();
let addr = "Null".to_string();
let random_id = 0;
let remote_id = "Null".to_string();
let log = Vec::new();
let is_empty = false;
let is_empty = true;
let slot = SlotInfo::new(
info_id.clone(),
@@ -358,94 +356,106 @@ impl DataParser {
let addr = "Null".to_string();
let state = None;
let session =
SessionInfo::new(session_id.clone(), node_id.clone(), addr, state, slot, is_empty);
let session = SessionInfo::new(
session_id.clone(),
node_id.clone(),
addr,
state,
slot,
sort.clone(),
is_empty,
);
session_info.push(session);
return Ok(session_info)
}
let sessions = reply.as_array().unwrap();
debug!(target: "dnetview", "parse_outbound() len session{:?}", sessions.len());
for session in sessions {
match session.as_object() {
Some(obj) => {
debug!(target: "dnetview", "parse_outbound() obj {:?}", session);
let addr = obj.get("addr").unwrap().as_str().unwrap().to_string();
// TODO: display empty sessions?
if !session.is_null() {
match session.as_object() {
Some(obj) => {
debug!(target: "dnetview", "parse_outbound() OBJ {:?}", obj);
let addr = obj.get("addr").unwrap().as_str().unwrap().to_string();
let state: Option<String> = match obj.get("state") {
Some(state) => Some(state.as_str().unwrap().to_string()),
None => None,
};
let state: Option<String> = match obj.get("state") {
Some(state) => Some(state.as_str().unwrap().to_string()),
None => None,
};
let info: serde_json::Map<String, Value> =
serde_json::from_value(obj.get("info").unwrap().clone()).unwrap();
let info: serde_json::Map<String, Value> =
serde_json::from_value(obj.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 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(info.get("log").unwrap().clone()).unwrap();
let log: Vec<(NanoTimestamp, String, String)> =
serde_json::from_value(info.get("log").unwrap().clone()).unwrap();
// ...
let node_id = node_id.to_string();
let is_empty = false;
// ...
let node_id = node_id.to_string();
let is_empty = false;
let slot = SlotInfo::new(
info_id.clone(),
node_id.clone(),
slot_addr,
random_id,
remote_id,
log,
is_empty,
);
let slot = SlotInfo::new(
info_id.clone(),
node_id.clone(),
slot_addr,
random_id,
remote_id,
log,
is_empty,
);
let session = SessionInfo::new(
session_id.clone(),
node_id.clone(),
addr.clone(),
state,
slot,
is_empty,
);
session_info.push(session);
}
None => {
// TODO: clean up empty info boilerplate.
slot_count += 1;
let info_id = make_empty_id(node_id, &prefix, slot_count)?;
let node_id = node_id.to_string();
let addr = "Null".to_string();
let random_id = 0;
let remote_id = "Null".to_string();
let log = Vec::new();
let is_empty = true;
let session = SessionInfo::new(
session_id.clone(),
node_id.clone(),
addr.clone(),
state,
slot.clone(),
sort.clone(),
is_empty,
);
session_info.push(session);
}
None => {
// TODO: clean up empty info boilerplate.
slot_count += 1;
let info_id = make_empty_id(node_id, &sort, slot_count)?;
let node_id = node_id.to_string();
let addr = "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(
info_id.clone(),
node_id.clone(),
addr.clone(),
random_id,
remote_id,
log,
is_empty,
);
let is_empty = true;
let slot = SlotInfo::new(
info_id.clone(),
node_id.clone(),
addr.clone(),
random_id,
remote_id,
log,
is_empty,
);
let is_empty = true;
let state = None;
let session = SessionInfo::new(
session_id.clone(),
node_id.clone(),
addr.clone(),
state,
slot,
is_empty,
);
session_info.push(session);
let state = None;
let session = SessionInfo::new(
session_id.clone(),
node_id.clone(),
addr.clone(),
state,
slot.clone(),
sort.clone(),
is_empty,
);
session_info.push(session);
}
}
}
}
@@ -470,7 +480,6 @@ impl DataParser {
let h = Vec::new();
return Ok(h)
}
debug!("dnetview::parse_hosts() hosts returns None and !is_null() {}", hosts);
Err(DnetViewError::ValueIsNotObject)
}
}

View File

@@ -26,13 +26,19 @@ pub fn make_node_id(node_name: &String) -> Result<String> {
Ok(id)
}
pub fn make_network_id(node_name: &String) -> Result<String> {
let mut id = hex::encode(node_name);
id.insert_str(0, "NETWORK");
Ok(id)
}
pub fn make_session_id(node_id: &str, session: &Session) -> Result<String> {
let mut num = 0_u64;
let session_chars = match session {
Session::Inbound => vec!['i', 'n'],
Session::Outbound => vec!['o', 'u', 't'],
Session::Manual => vec!['m', 'a', 'n'],
//Session::Manual => vec!['m', 'a', 'n'],
Session::Offline => vec!['o', 'f', 'f'],
};
@@ -87,19 +93,19 @@ pub fn make_empty_id(node_id: &str, session: &Session, count: u64) -> Result<Str
id.insert_str(0, "EMPTYOUT");
id
}
Session::Manual => {
let session_chars = vec!['m', 'a', 'n'];
for i in session_chars {
num += i as u64
}
for i in node_id.chars() {
num += i as u64
}
num += count;
let mut id = hex::encode(num.to_ne_bytes());
id.insert_str(0, "EMPTYMAN");
id
}
//Session::Manual => {
// let session_chars = vec!['m', 'a', 'n'];
// for i in session_chars {
// num += i as u64
// }
// for i in node_id.chars() {
// num += i as u64
// }
// num += count;
// let mut id = hex::encode(num.to_ne_bytes());
// id.insert_str(0, "EMPTYMAN");
// id
//}
Session::Offline => {
let session_chars = vec!['o', 'f', 'f'];
for i in session_chars {

View File

@@ -16,8 +16,8 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use log::debug;
use std::collections::HashMap;
//use log::debug;
use tui::{
backend::Backend,
@@ -85,6 +85,9 @@ impl<'a> View {
}
}
// The order of the ordered_list created here must match the order
// of the Vec<ListItem> created in render_left().
// This is used to render_right() correctly.
fn make_ordered_list(&mut self) {
for obj in self.selectables.values() {
match obj {
@@ -98,11 +101,9 @@ impl<'a> View {
if !self.ordered_list.iter().any(|i| i == &inbound.dnet_id) {
self.ordered_list.push(inbound.dnet_id.clone());
}
//for info in &inbound.info {
if !self.ordered_list.iter().any(|i| i == &inbound.info.dnet_id) {
self.ordered_list.push(inbound.info.dnet_id.clone());
}
//}
}
}
for outbound in &node.outbound {
@@ -110,11 +111,9 @@ impl<'a> View {
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 == &outbound.info.dnet_id) {
self.ordered_list.push(outbound.info.dnet_id.clone());
}
//}
}
}
}
@@ -132,12 +131,10 @@ impl<'a> View {
_ => (),
}
}
//debug!(target: "dnetview", "render_ids()::ordered_list: {:?}", self.ordered_list);
}
// TODO: this function is dynamically resizing the msgs index
// according to what set of msgs is selected.
// it's ugly. would prefer something more simple
// TODO: this function displays msgs according to what id is
// selected. It's ugly, would prefer something more simple.
fn update_msg_index(&mut self) {
if let Some(sel) = self.id_menu.state.selected() {
if let Some(ord) = self.ordered_list.get(sel) {
@@ -165,31 +162,28 @@ impl<'a> View {
.constraints(cnstrnts)
.split(f.size());
self.render_ids(f, slice.clone())?;
self.render_left(f, slice.clone())?;
if self.ordered_list.is_empty() {
// we have not received any data
Ok(())
} else {
// get the id at the current index
match self.id_menu.state.selected() {
Some(i) => {
//debug!(target: "dnetview", "render()::selected index: {}", i);
match self.ordered_list.get(i) {
Some(i) => {
let id = i.clone();
self.render_info(f, slice, id)?;
Ok(())
}
None => Err(DnetViewError::NoIdAtIndex),
Some(i) => match self.ordered_list.get(i) {
Some(i) => {
let id = i.clone();
self.render_right(f, slice, id)?;
Ok(())
}
}
None => Err(DnetViewError::NoIdAtIndex),
},
// nothing is selected right now
None => Ok(()),
}
}
}
fn render_ids<B: Backend>(
fn render_left<B: Backend>(
&mut self,
f: &mut Frame<'_, B>,
slice: Vec<Rect>,
@@ -215,13 +209,13 @@ impl<'a> View {
let names = ListItem::new(lines);
nodes.push(names);
for inbound in &node.inbound {
if !inbound.is_empty {
let name = Span::styled(format!(" Inbound"), style);
let lines = vec![Spans::from(name)];
let names = ListItem::new(lines);
nodes.push(names);
//for info in &inbound.info {
if !node.inbound.is_empty() {
let name = Span::styled(format!(" Inbound"), style);
let lines = vec![Spans::from(name)];
let names = ListItem::new(lines);
nodes.push(names);
for inbound in &node.inbound {
let mut infos = Vec::new();
match inbound.info.addr.as_str() {
"Null" => {
@@ -246,21 +240,19 @@ impl<'a> View {
}
}
}
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"), style);
let lines = vec![Spans::from(name)];
let names = ListItem::new(lines);
nodes.push(names);
//for info in &outbound.info {
if !&node.outbound.is_empty() {
let name = Span::styled(format!(" Outbound"), style);
let lines = vec![Spans::from(name)];
let names = ListItem::new(lines);
nodes.push(names);
for outbound in &node.outbound {
let mut infos = Vec::new();
match outbound.info.addr.as_str() {
"Null" => {
@@ -285,11 +277,9 @@ impl<'a> View {
}
}
}
let lines = vec![Spans::from(infos)];
let names = ListItem::new(lines);
nodes.push(names);
//}
}
}
}
@@ -349,12 +339,13 @@ impl<'a> View {
Ok(msg_list)
}
fn render_info<B: Backend>(
fn render_right<B: Backend>(
&mut self,
f: &mut Frame<'_, B>,
slice: Vec<Rect>,
selected: String,
) -> DnetViewResult<()> {
debug!(target: "dnetview", "render_right() selected ID: {}", selected.clone());
let style = Style::default();
let mut lines = Vec::new();
@@ -363,11 +354,9 @@ impl<'a> View {
return Ok(())
} else {
let info = self.selectables.get(&selected);
//debug!(target: "dnetview", "render_info()::selected {}", selected);
match info {
Some(SelectableObject::Node(node)) => {
//debug!(target: "dnetview", "render_info()::SelectableObject::Node");
lines.push(Spans::from(Span::styled("Type: Normal", style)));
lines.push(Spans::from(Span::styled("Hosts:", style)));
for host in &node.hosts {
@@ -375,7 +364,6 @@ impl<'a> View {
}
}
Some(SelectableObject::Session(session)) => {
//debug!(target: "dnetview", "render_info()::SelectableObject::Session");
let addr = Span::styled(format!("Addr: {}", session.addr), style);
lines.push(Spans::from(addr));
@@ -387,16 +375,8 @@ impl<'a> View {
lines.push(Spans::from(addr));
}
}
Some(SelectableObject::Connect(connect)) => {
// TODO: this renders in the top right and overwrites the msg log
//let addr = Span::styled(format!("Addr: {}", connect.addr), style);
//let random_id = Span::styled(format!("Random id: {}", connect.random_id), style);
//let remote_id = Span::styled(format!("Remote id: {}", connect.remote_id), style);
//lines.push(Spans::from(addr));
//lines.push(Spans::from(random_id));
//lines.push(Spans::from(remote_id));
//debug!(target: "dnetview", "render_info()::SelectableObject::Connect");
let text = self.parse_msg_list(connect.dnet_id.clone())?;
Some(SelectableObject::Slot(slot)) => {
let text = self.parse_msg_list(slot.dnet_id.clone())?;
f.render_stateful_widget(text, slice[1], &mut self.msg_list.state);
}
Some(SelectableObject::Lilith(_lilith)) => {