From 8b5f56f54ed9afb8ac06d5dc87af5dbc2157bfb7 Mon Sep 17 00:00:00 2001 From: lunar-mining Date: Tue, 26 Apr 2022 14:00:56 +0200 Subject: [PATCH] dnetview/ View: refactor * create view objects to handle model data * update() function to write model to view * render() to draw view this commit deprecates ui::ui() --- bin/dnetview/src/lib.rs | 2 +- bin/dnetview/src/main.rs | 64 +++++++--- bin/dnetview/src/model.rs | 18 +-- bin/dnetview/src/ui.rs | 240 ++++++++++++++++++++++--------------- bin/dnetview/src/view.rs | 245 ++++++++++++++++++++++++++++++++++++-- 5 files changed, 434 insertions(+), 135 deletions(-) diff --git a/bin/dnetview/src/lib.rs b/bin/dnetview/src/lib.rs index 89bb61502..cec129874 100644 --- a/bin/dnetview/src/lib.rs +++ b/bin/dnetview/src/lib.rs @@ -8,5 +8,5 @@ pub mod view; pub use config::{DnvConfig, CONFIG_FILE_CONTENTS}; //pub use model::Model; pub use options::ProgramOptions; -pub use ui::ui; +//pub use ui::ui; //pub use view::{IdListView, InfoListView, View}; diff --git a/bin/dnetview/src/main.rs b/bin/dnetview/src/main.rs index ec877c31a..e6f706787 100644 --- a/bin/dnetview/src/main.rs +++ b/bin/dnetview/src/main.rs @@ -31,7 +31,7 @@ use dnetview::{ options::ProgramOptions, ui, util::{generate_id, make_connect_id, make_node_id, make_session_id}, - view::{IdListView, InfoListView, View}, + view::{ConnectInfoView, IdListView, InfoListView, NodeInfoView, SessionInfoView, View}, }; struct DNetView { @@ -108,7 +108,7 @@ async fn main() -> Result<()> { terminal.clear()?; let ids = Mutex::new(FxHashSet::default()); - let infos = Mutex::new(FxHashMap::default()); + let infos = Mutex::new(Vec::new()); let model = Arc::new(Model::new(ids, infos)); @@ -180,10 +180,11 @@ async fn parse_data( let node_info = NodeInfo::new(node_id.clone(), node_name.to_string(), sessions.clone()); let node = SelectableObject::Node(node_info.clone()); + // we might simplify things by making this a Vec update_model(model.clone(), sessions.clone(), node_info, node).await?; - debug!("IDS: {:?}", model.ids.lock().await); - debug!("INFOS: {:?}", model.infos.lock().await); + //debug!("IDS: {:?}", model.ids.lock().await); + //debug!("INFOS: {:?}", model.infos.lock().await); Ok(()) } @@ -194,19 +195,27 @@ async fn update_model( node_info: NodeInfo, node: SelectableObject, ) -> Result<()> { + model.ids.lock().await.insert(node_info.node_id.clone()); + model.infos.lock().await.push(node); + for session in sessions.clone() { - model.ids.lock().await.insert(session.session_id); + model.ids.lock().await.insert(session.clone().session_id); + + let session_obj = SelectableObject::Session(session.clone()); + model.infos.lock().await.push(session_obj); + for connect in session.children { - model.ids.lock().await.insert(connect.connect_id); + model.ids.lock().await.insert(connect.clone().connect_id); + let connect_obj = SelectableObject::Connect(connect.clone()); + model.infos.lock().await.push(connect_obj); } } - model.ids.lock().await.insert(node_info.node_id.clone()); - model.infos.lock().await.insert(node_info.node_id.clone(), node); Ok(()) } async fn parse_inbound(inbound: &Value, node_id: String) -> Result { + let session_name = "Inbound".to_string(); let session_type = Session::Inbound; let session_id = make_session_id(node_id.clone(), &session_type)?; let mut connects: Vec = Vec::new(); @@ -254,8 +263,12 @@ async fn parse_inbound(inbound: &Value, node_id: String) -> Result } } } - let session_info = - SessionInfo::new(session_id.clone(), node_id.clone(), connects.clone()); + let session_info = SessionInfo::new( + session_name, + session_id.clone(), + node_id.clone(), + connects.clone(), + ); Ok(session_info) } None => Err(Error::ValueIsNotObject), @@ -264,6 +277,7 @@ async fn parse_inbound(inbound: &Value, node_id: String) -> Result // TODO: placeholder for now async fn parse_manual(_manual: &Value, node_id: String) -> Result { + let session_name = "Manual".to_string(); let session_type = Session::Manual; let mut connects: Vec = Vec::new(); @@ -280,12 +294,13 @@ async fn parse_manual(_manual: &Value, node_id: String) -> Result { let connect_info = ConnectInfo::new(connect_id, addr, is_empty, msg, status, state, msg_log, parent); connects.push(connect_info.clone()); - let session_info = SessionInfo::new(session_id, node_id, connects.clone()); + let session_info = SessionInfo::new(session_name, session_id, node_id, connects.clone()); Ok(session_info) } async fn parse_outbound(outbound: &Value, node_id: String) -> Result { + let session_name = "Outbound".to_string(); let session_type = Session::Outbound; let mut connects: Vec = Vec::new(); let slots = &outbound["slots"]; @@ -347,7 +362,8 @@ async fn parse_outbound(outbound: &Value, node_id: String) -> Result Err(Error::ValueIsNotObject), @@ -361,15 +377,29 @@ async fn render(terminal: &mut Terminal, model: Arc) -> Re let id_list = IdListView::new(FxHashSet::default()); let info_list = InfoListView::new(FxHashMap::default()); - let mut view = View::new(id_list.clone(), info_list.clone()); + let node_view = NodeInfoView::default(); + let session_view = SessionInfoView::default(); + let connect_view = ConnectInfoView::default(); + + let mut view = View::new( + id_list.clone(), + info_list, + node_view.clone(), + session_view.clone(), + connect_view.clone(), + ); view.id_list.state.select(Some(0)); view.info_list.index = 0; loop { - view.update(model.infos.lock().await.clone()); + //debug!("MODEL: {:?}", model.infos.lock().await.clone()); + //debug!("VIEW BEFORE UPDATE: {:?}", &view.id_list.ids); + let mut view = view.clone().update(model.infos.lock().await.clone())?; + //debug!("VIEW AFTER UPDATE: {:?}", view.clone().id_list.ids); + terminal.draw(|f| { - ui::ui(f, view.clone()); + view.clone().render(f); })?; for k in asi.by_ref().keys() { match k.unwrap() { @@ -378,10 +408,10 @@ async fn render(terminal: &mut Terminal, model: Arc) -> Re return Ok(()) } Key::Char('j') => { - view.id_list.next(); + view.clone().id_list.next(); } Key::Char('k') => { - view.id_list.previous(); + view.clone().id_list.previous(); } _ => (), } diff --git a/bin/dnetview/src/model.rs b/bin/dnetview/src/model.rs index bb4388d99..bac7f818f 100644 --- a/bin/dnetview/src/model.rs +++ b/bin/dnetview/src/model.rs @@ -19,14 +19,12 @@ pub enum SelectableObject { pub struct Model { pub ids: Mutex>, - pub infos: Mutex>, + pub infos: Mutex>, + //pub infos: Mutex>, } impl Model { - pub fn new( - ids: Mutex>, - infos: Mutex>, - ) -> Model { + pub fn new(ids: Mutex>, infos: Mutex>) -> Model { Model { ids, infos } } } @@ -46,14 +44,20 @@ impl NodeInfo { #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, Hash)] pub struct SessionInfo { + pub session_name: String, pub session_id: String, pub parent: String, pub children: Vec, } impl SessionInfo { - pub fn new(session_id: String, parent: String, children: Vec) -> SessionInfo { - SessionInfo { session_id, parent, children } + pub fn new( + session_name: String, + session_id: String, + parent: String, + children: Vec, + ) -> SessionInfo { + SessionInfo { session_name, session_id, parent, children } } } diff --git a/bin/dnetview/src/ui.rs b/bin/dnetview/src/ui.rs index 547674266..1e0012eb5 100644 --- a/bin/dnetview/src/ui.rs +++ b/bin/dnetview/src/ui.rs @@ -1,99 +1,141 @@ -use crate::view::View; -use log::debug; - -use tui::{ - backend::Backend, - layout::{Constraint, Direction, Layout, Rect}, - style::Style, - text::{Span, Spans}, - widgets::{Block, Borders, List, ListItem, Paragraph}, - Frame, -}; - -pub fn ui(f: &mut Frame<'_, B>, mut view: View) { - let list_margin = 2; - let list_direction = Direction::Horizontal; - let list_cnstrnts = vec![Constraint::Percentage(50), Constraint::Percentage(50)]; - - let mut nodes = Vec::new(); - let style = Style::default(); - - for id in &view.id_list.ids { - let id_span = Span::raw(id.to_string()); - let mut lines = vec![Spans::from(id_span)]; - - match &view.info_list.infos.get(id) { - Some(node) => { - //debug!("NODE: {:?}", node); - //if !node.outbound.iter().all(|node| node.is_empty) { - // lines.push(Spans::from(Span::styled(" Outgoing", Style::default()))); - //} - //for outbound in &node.outbound.clone() { - // for slot in outbound.slots.clone() { - // let addr = Span::styled(format!(" {}", slot.addr), style); - // let msg: Span = match slot.channel.last_status.as_str() { - // "recv" => Span::styled( - // format!(" [R: {}]", slot.channel.last_msg), - // style, - // ), - // "sent" => Span::styled( - // format!(" [S: {}]", slot.channel.last_msg), - // style, - // ), - // a => Span::styled(a.to_string(), style), - // }; - // lines.push(Spans::from(vec![addr, msg])); - // } - //} - //if !node.inbound.iter().all(|node| node.is_empty) { - // lines.push(Spans::from(Span::styled(" Incoming", Style::default()))); - //} - //for inbound in &node.inbound { - // let addr = Span::styled(format!(" {}", inbound.connected), style); - // let msg: Span = match inbound.channel.last_status.as_str() { - // "recv" => Span::styled( - // format!(" [R: {}]", inbound.channel.last_msg), - // style, - // ), - // "sent" => Span::styled( - // format!(" [R: {}]", inbound.channel.last_msg), - // style, - // ), - // a => Span::styled(a.to_string(), style), - // }; - // lines.push(Spans::from(vec![addr, msg])); - //} - //lines.push(Spans::from(Span::styled(" Manual", Style::default()))); - //for connect in &node.manual { - // lines.push(Spans::from(Span::styled(format!(" {}", connect.key), style))); - //} - } - None => { - // TODO - debug!("This is also a bug"); - } - } - - let ids = ListItem::new(lines); - nodes.push(ids); - } - - let nodes = - List::new(nodes).block(Block::default().borders(Borders::ALL)).highlight_symbol(">> "); - let slice = Layout::default() - .direction(list_direction) - .margin(list_margin) - .constraints(list_cnstrnts) - .split(f.size()); - - f.render_stateful_widget(nodes, slice[0], &mut view.id_list.state); - - render_info_right(view.clone(), f, slice); -} - -fn render_info_right(_view: View, f: &mut Frame<'_, B>, slice: Vec) { - let span = vec![]; - let graph = - Paragraph::new(span).block(Block::default().borders(Borders::ALL)).style(Style::default()); - f.render_widget(graph, slice[1]); -} +//use crate::model::SelectableObject; +//use crate::view::View; +//use log::debug; +// +//use tui::{ +// backend::Backend, +// layout::{Constraint, Direction, Layout, Rect}, +// style::Style, +// text::{Span, Spans}, +// widgets::{Block, Borders, List, ListItem, Paragraph}, +// Frame, +//}; +// +//pub fn ui(f: &mut Frame<'_, B>, mut view: View) { +// let list_margin = 2; +// let list_direction = Direction::Horizontal; +// let list_cnstrnts = vec![Constraint::Percentage(50), Constraint::Percentage(50)]; +// +// let mut nodes = Vec::new(); +// let style = Style::default(); +// +// // TODO: this is insanely nested. pass SelectableObjects to different views +// for id in &view.id_list.ids { +// let mut lines: Vec = Vec::new(); +// //debug!("{}", id); +// // this only needs to be node ids +// match &view.info_list.infos.get(id) { +// Some(node) => { +// match node { +// SelectableObject::Node(node_info) => { +// let name_span = Span::raw(node_info.node_name.to_string()); +// lines.push(Spans::from(name_span)); +// //let mut lines = vec![Spans::from(name_span)]; +// //let id = &node_info.node_id; +// //let name = &node_info.node_name; +// for child in &node_info.children { +// match child.session_name.as_str() { +// "Outgoing" => { +// lines.push(Spans::from(Span::styled( +// " Outgoing", +// Style::default(), +// ))); +// } +// "Incoming" => { +// lines.push(Spans::from(Span::styled( +// " Outgoing", +// Style::default(), +// ))); +// } +// "Manual" => { +// lines.push(Spans::from(Span::styled( +// " Outgoing", +// Style::default(), +// ))); +// } +// _ => {} +// } +// for child in &child.children { +// // do something +// } +// } +// //if !node.outbound.iter().all(|node| node.is_empty) { +// // lines.push(Spans::from(Span::styled(" Outgoing", Style::default()))); +// //} +// +// // ok +// } +// _ => { +// // ok +// } +// } +// //for outbound in &node.outbound.clone() { LOG_TARGETS=net cargo run -- -vv --slots 5 --seed 0.0.0.0:9999 --irc 127.0.0.1:6668 --rpc 127.0.0.1:8000 +// // for slot in outbound.slots.clone() { +// // let addr = Span::styled(format!(" {}", slot.addr), style); +// // let msg: Span = match slot.channel.last_status.as_str() { +// // "recv" => Span::styled( +// // format!(" [R: {}]", slot.channel.last_msg), +// // style, +// // ), +// // "sent" => Span::styled( +// // format!(" [S: {}]", slot.channel.last_msg), +// // style, +// // ), +// // a => Span::styled(a.to_string(), style), +// // }; +// // lines.push(Spans::from(vec![addr, msg])); +// // } +// //} +// //if !node.inbound.iter().all(|node| node.is_empty) { +// // lines.push(Spans::from(Span::styled(" Incoming", Style::default()))); +// //} +// //for inbound in &node.inbound { +// // let addr = Span::styled(format!(" {}", inbound.connected), style); +// // let msg: Span = match inbound.channel.last_status.as_str() { +// // "recv" => Span::styled( +// // format!(" [R: {}]", inbound.channel.last_msg), +// // style, +// // ), +// // "sent" => Span::styled( +// // format!(" [R: {}]", inbound.channel.last_msg), +// // style, +// // ), +// // a => Span::styled(a.to_string(), style), +// // }; +// // lines.push(Spans::from(vec![addr, msg])); +// //} +// //lines.push(Spans::from(Span::styled(" Manual", Style::default()))); +// //for connect in &node.manual { +// // lines.push(Spans::from(Span::styled(format!(" {}", connect.key), style))); +// //} +// } +// None => { +// // TODO +// debug!("This is also a bug"); +// } +// } +// +// // need list of all ids here +// let ids = ListItem::new(lines); +// nodes.push(ids); +// } +// +// let nodes = +// List::new(nodes).block(Block::default().borders(Borders::ALL)).highlight_symbol(">> "); +// let slice = Layout::default() +// .direction(list_direction) +// .margin(list_margin) +// .constraints(list_cnstrnts) +// .split(f.size()); +// +// f.render_stateful_widget(nodes, slice[0], &mut view.id_list.state); +// +// render_info_right(view.clone(), f, slice); +//} +// +//fn render_info_right(_view: View, f: &mut Frame<'_, B>, slice: Vec) { +// let span = vec![]; +// let graph = +// Paragraph::new(span).block(Block::default().borders(Borders::ALL)).style(Style::default()); +// f.render_widget(graph, slice[1]); +//} diff --git a/bin/dnetview/src/view.rs b/bin/dnetview/src/view.rs index 999df4c37..82cb2ab63 100644 --- a/bin/dnetview/src/view.rs +++ b/bin/dnetview/src/view.rs @@ -1,29 +1,252 @@ +use async_std::sync::Arc; +use darkfi::error::Result; use fxhash::{FxHashMap, FxHashSet}; -//use log::debug; +use log::debug; +use serde::{Deserialize, Serialize}; use tui::widgets::ListState; -use crate::model::SelectableObject; +use tui::{ + backend::Backend, + layout::{Constraint, Direction, Layout, Rect}, + style::Style, + text::{Span, Spans}, + widgets::{Block, Borders, List, ListItem, Paragraph}, + Frame, +}; -#[derive(Clone)] +use crate::model::{ConnectInfo, Model, NodeInfo, SelectableObject, SessionInfo}; + +#[derive(Debug, Clone)] pub struct View { pub id_list: IdListView, pub info_list: InfoListView, + pub node_info: NodeInfoView, + pub session_info: SessionInfoView, + pub connect_info: ConnectInfoView, } impl View { - pub fn new(id_list: IdListView, info_list: InfoListView) -> View { - View { id_list, info_list } + pub fn new( + id_list: IdListView, + info_list: InfoListView, + node_info: NodeInfoView, + session_info: SessionInfoView, + connect_info: ConnectInfoView, + ) -> View { + View { id_list, info_list, node_info, session_info, connect_info } } - pub fn update(&mut self, infos: FxHashMap) { - for (id, info) in infos { - self.id_list.ids.insert(id.clone()); - self.info_list.infos.insert(id, info); + pub fn update(mut self, model: Vec) -> Result { + for obj in model { + let obj_clone = obj.clone(); + match obj { + SelectableObject::Node(node) => { + let node1 = node.clone(); + //self.node_info.clone().update(node1.clone())?; + self.id_list.ids.insert(node1.clone().node_id); + self.info_list.infos.insert(node.node_id, obj_clone); + } + SelectableObject::Session(session) => { + let session1 = session.clone(); + //self.session_info.clone().update(session1.clone())?; + self.id_list.ids.insert(session1.clone().session_id); + self.info_list.infos.insert(session1.clone().session_id, obj_clone); + } + SelectableObject::Connect(connect) => { + let connect1 = connect.clone(); + //self.connect_info.clone().update(connect)?; + self.id_list.ids.insert(connect1.clone().connect_id); + self.info_list.infos.insert(connect1.clone().connect_id, obj_clone); + } + } } + + let id_list = self.id_list; + let info_list = self.info_list; + let node_info = self.node_info; + let session_info = self.session_info; + let connect_info = self.connect_info; + + Ok(View { id_list, info_list, node_info, session_info, connect_info }) + } + + pub fn render(mut self, f: &mut Frame<'_, B>) { + //debug!("VIEW AT RENDER {:?}", self.id_list.ids); + //let mut nodes = Vec::new(); + let list_margin = 2; + let list_direction = Direction::Horizontal; + let list_cnstrnts = vec![Constraint::Percentage(50), Constraint::Percentage(50)]; + + let mut nodes = Vec::new(); + + for id in self.id_list.ids { + match self.info_list.infos.get(&id) { + Some(obj) => { + match obj { + SelectableObject::Node(info) => { + //debug!("FOUND NODE: {:?}", info); + let name_span = Span::raw(&info.node_name); + let lines = vec![Spans::from(name_span)]; + //lines.push(Spans::from(name_span)); + let names = ListItem::new(lines); + nodes.push(names); + //nodes.push(node); + } + SelectableObject::Session(info) => self.session_info.clone().render(info), + SelectableObject::Connect(info) => self.connect_info.clone().render(info), + } + // + } + None => { + // TODO + } // + } + // + } + let slice = Layout::default() + .direction(list_direction) + .margin(list_margin) + .constraints(list_cnstrnts) + .split(f.size()); + + let nodes = + List::new(nodes).block(Block::default().borders(Borders::ALL)).highlight_symbol(">> "); + + f.render_stateful_widget(nodes, slice[0], &mut self.id_list.state); + //for node in nodes { + // f.render_stateful_widget(node, slice[0], &mut self.id_list.state); + //} } } -#[derive(Clone)] +#[derive(Debug, Clone)] +pub struct NodeInfoView { + pub node_id: String, + pub node_name: String, + pub children: Vec, +} + +impl NodeInfoView { + pub fn default() -> NodeInfoView { + let node_id = String::new(); + let node_name = String::new(); + let children: Vec = Vec::new(); + NodeInfoView { node_id, node_name, children } + } + + pub fn update(mut self, data: NodeInfo) -> Result<()> { + //self.state.slect(Some(0)); + self.node_id = data.node_id; + self.node_name = data.node_name; + self.children = data.children; + Ok(()) + } + + pub fn render(self, node: &NodeInfo) -> List { + let mut nodes = Vec::new(); + let mut lines: Vec = Vec::new(); + let name_span = Span::raw(&node.node_name); + lines.push(Spans::from(name_span)); + let ids = ListItem::new(lines); + nodes.push(ids); + let nodes = + List::new(nodes).block(Block::default().borders(Borders::ALL)).highlight_symbol(">> "); + nodes + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, Hash)] +pub struct SessionInfoView { + pub session_name: String, + pub session_id: String, + pub parent: String, + pub children: Vec, +} + +impl SessionInfoView { + pub fn default() -> SessionInfoView { + let session_name = String::new(); + let session_id = String::new(); + let parent = String::new(); + let children: Vec = Vec::new(); + SessionInfoView { session_name, session_id, parent, children } + } + + pub fn update(mut self, data: SessionInfo) -> Result<()> { + self.session_name = data.session_name; + self.session_id = data.session_id; + self.parent = data.parent; + self.children = data.children; + Ok(()) + } + + pub fn render(self, session: &SessionInfo) { + //let mut lines: Vec = Vec::new(); + //let name_span = Span::raw(self.session_name); + //let ids = ListItem::new(lines); + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, Hash)] +pub struct ConnectInfoView { + pub connect_id: String, + pub addr: String, + pub is_empty: bool, + pub last_msg: String, + pub last_status: String, + pub state: String, + pub msg_log: Vec, + pub parent: String, +} + +impl ConnectInfoView { + pub fn default() -> ConnectInfoView { + let connect_id = String::new(); + let addr = String::new(); + let is_empty = true; + let last_msg = String::new(); + let last_status = String::new(); + let state = String::new(); + let msg_log: Vec = Vec::new(); + let parent = String::new(); + ConnectInfoView { + connect_id, + addr, + is_empty, + last_msg, + last_status, + state, + msg_log, + parent, + } + } + + pub fn update(mut self, data: ConnectInfo) -> Result<()> { + self.connect_id = data.connect_id; + self.addr = data.addr; + self.is_empty = data.is_empty; + self.last_msg = data.last_msg; + self.last_status = data.last_status; + self.state = data.state; + self.msg_log = data.msg_log; + self.parent = data.parent; + Ok(()) + } + + pub fn render(self, connect: &ConnectInfo) { + let mut lines: Vec = Vec::new(); + //let name_span = Span::raw(self.connect_id); + } +} + +//#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, Hash)] +//pub enum SelectableObject { +// Node(NodeInfoView), +// Session(SessionInfoView), +// Connect(ConnectInfoViewView), +//} + +#[derive(Debug, Clone)] pub struct IdListView { pub state: ListState, pub ids: FxHashSet, @@ -66,7 +289,7 @@ impl IdListView { } } -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct InfoListView { pub index: usize, pub infos: FxHashMap,