mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
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:
@@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)) => {
|
||||
|
||||
Reference in New Issue
Block a user