Skip to content

Commit

Permalink
Refactor: Did a couple of bigger changes
Browse files Browse the repository at this point in the history
New idenfitier for the Tree. This is now an enum describing the level
and the contents of the tree better. This will allow for a calling and methods
and getting properties.

The tree binary has been moved to examples. It was not a useful program, and it shadows
the ubiquitous tree that show a file tree.

Added logging with the tracing crate. This is helpful when debugging issues in the tui

Updated Cargo.lock
  • Loading branch information
Troels51 committed Jul 18, 2024
1 parent 821986c commit c1a100a
Show file tree
Hide file tree
Showing 8 changed files with 612 additions and 466 deletions.
724 changes: 416 additions & 308 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@ itertools = "0.11.0"
clap = { version = "4.4.1", features = ["derive"] }
ratatui = { version = "0.26.2", features = ["macros"] }
zbus_xml = "4.0.0"
tracing-error = "0.2.0"
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json", "fmt"] }
tracing-journald = "0.3.0"
File renamed without changes.
159 changes: 13 additions & 146 deletions src/bin/dtui/app.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use std::time::{Duration, Instant};

use crossterm::event::{self, Event, KeyCode};
use itertools::Itertools;
use ratatui::{backend::Backend, Terminal};
use tokio::sync::mpsc::Receiver;
use tui_tree_widget::TreeItem;
use tracing::Level;
use zbus::names::OwnedBusName;
use zbus_xml::ArgDirection;

use crate::{
dbus_handler::DbusActorHandle, messages::AppMessage, stateful_list::StatefulList,
Expand All @@ -19,17 +17,16 @@ pub enum WorkingArea {
Objects,
}

pub struct App<'a> {
pub struct App {
dbus_rx: Receiver<AppMessage>,
dbus_handle: DbusActorHandle,
pub services: StatefulList<OwnedBusName>,
pub objects: StatefulTree<'a>,

pub objects: StatefulTree,
pub working_area: WorkingArea,
}

impl<'a> App<'a> {
pub fn new(dbus_rx: Receiver<AppMessage>, dbus_handle: DbusActorHandle) -> App<'a> {
impl App {
pub fn new(dbus_rx: Receiver<AppMessage>, dbus_handle: DbusActorHandle) -> App {
App {
dbus_rx,
dbus_handle,
Expand All @@ -44,7 +41,7 @@ impl<'a> App<'a> {

pub async fn run_app<B: Backend>(
terminal: &mut Terminal<B>,
mut app: App<'static>,
mut app: App,
tick_rate: Duration,
) -> Result<(), zbus::Error> {
let mut last_tick = Instant::now();
Expand All @@ -55,143 +52,8 @@ pub async fn run_app<B: Backend>(

match app.dbus_rx.try_recv() {
Ok(message) => match message {
AppMessage::Objects(nodes) => {
app.objects = StatefulTree::with_items(
nodes
.iter()
.sorted_by(|a, b| a.0.cmp(b.0))
.enumerate()
.map(|(id, (object_name, node))| {
let children: Vec<TreeItem<usize>> = node
.interfaces()
.iter()
.enumerate()
.map(|(id, interface)| {
let methods: Vec<TreeItem<usize>> = interface
.methods()
.iter()
.enumerate()
.map(|(id, method)| {
let inputs: Vec<String> = method
.args()
.iter()
.filter(|arg| {
arg.direction()
.is_some_and(|s| s == ArgDirection::In)
})
.map(|arg| {
format!(
"{}: {}",
arg.name().unwrap_or_default(),
arg.ty()
)
})
.collect();
let outputs: Vec<String> = method
.args()
.iter()
.filter(|arg| {
arg.direction()
.is_some_and(|s| s == ArgDirection::Out)
})
.map(|arg| {
format!(
"{}: {}",
arg.name().unwrap_or_default(),
arg.ty()
)
})
.collect();
let return_arrow =
if outputs.is_empty() { "" } else { "=>" }; // If we dont return anything, the arrow shouldnt be there
let leaf_string: String = format!(
"{}({}) {} {}",
method.name(),
inputs.join(", "),
return_arrow,
outputs.join(", ")
);
TreeItem::new_leaf(id, leaf_string)
})
.collect();
let properties: Vec<TreeItem<usize>> = interface
.properties()
.iter()
.enumerate()
.map(|(id, property)| {
TreeItem::new_leaf(
id,
format!(
"{}: {}",
property.name(),
property.ty()
),
)
})
.collect();
let signals: Vec<TreeItem<usize>> = interface
.signals()
.iter()
.enumerate()
.map(|(id, signal)| {
// Signals can only have input parameters
let inputs: Vec<String> = signal
.args()
.iter()
.filter(|arg| {
arg.direction()
.is_some_and(|s| s == ArgDirection::In)
})
.map(|arg| {
format!(
"{}: {}",
arg.name().unwrap_or_default(),
arg.ty()
)
})
.collect();
let leaf_string: String = format!(
"{}({})",
signal.name(),
inputs.join(", ")
);
TreeItem::new_leaf(id, leaf_string)
})
.collect();
// let annotations: Vec<TreeItem> = interface
// .annotations()
// .iter()
// .map(|annotation| {
// TreeItem::new_leaf(annotation.name().to_string())
// })
// .collect();
let methods_tree = TreeItem::new(0, "Methods", methods)
.expect("Methods should have different ids");
let properties_tree =
TreeItem::new(1, "Properties", properties)
.expect("Properties should have different ids");
let signals_tree = TreeItem::new(2, "Signals", signals)
.expect("Signals should have different ids");
// let annotations_tree =
// TreeItem::new("Annotations", annotations);
// TODO: Annotations are used differently, so i dont want to waste space with it
TreeItem::new(
id,
interface.name().to_string(),
vec![
methods_tree,
properties_tree,
signals_tree,
// annotations_tree,
],
)
.unwrap()
})
.collect();
TreeItem::new(id, object_name.clone(), children).unwrap()
})
.collect(),
);
AppMessage::Objects((_service_name, root_node)) => {
app.objects = StatefulTree::from_nodes(root_node);
}
AppMessage::Services(names) => {
app.services = StatefulList::with_items(names);
Expand Down Expand Up @@ -239,6 +101,11 @@ pub async fn run_app<B: Backend>(
},
_ => (),
}
tracing::event!(
Level::DEBUG,
"{}",
format!("state = {:?}", app.objects.state)
);
}
}
if last_tick.elapsed() >= tick_rate {
Expand Down
8 changes: 5 additions & 3 deletions src/bin/dtui/dbus_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ impl DbusActor {
.await?;
let introspect_xml: String = introspectable_proxy.introspect().await?;
let introspect = Node::from_reader(BufReader::new(introspect_xml.as_bytes()))?;

Ok(introspect)
}

Expand All @@ -45,8 +46,8 @@ impl DbusActor {
service_name: &OwnedBusName,
path: &ObjectPath<'async_recursion>,
) -> Result<HashMap<String, Node<'static>>, Box<dyn Error + Send + Sync>> {
let mut result = HashMap::new();
let node = self.get_node(service_name, path).await?;
let mut result = HashMap::new();

for sub_node in node.nodes() {
if let Some(name) = sub_node.name() {
Expand All @@ -56,7 +57,7 @@ impl DbusActor {
path.as_str().to_string() + "/" + name
};
let sub_path = ObjectPath::try_from(path_name)?;
result.extend(self.get_sub_nodes(service_name, &sub_path).await?)
result.extend(self.get_sub_nodes(service_name, &sub_path).await?);
}
}
result.insert(path.to_string(), node);
Expand All @@ -68,9 +69,10 @@ impl DbusActor {
DbusMessage::GetObjects(service_name) => {
let path_name = "/".to_string();
let path = ObjectPath::try_from(path_name).expect("/ is always a valid path");

if let Ok(nodes) = self.get_sub_nodes(&service_name, &path).await {
self.app_sender
.send(AppMessage::Objects(nodes))
.send(AppMessage::Objects((service_name, nodes)))
.await
.expect("channel dead");
}
Expand Down
13 changes: 13 additions & 0 deletions src/bin/dtui/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ use ratatui::{
};
use std::{error::Error, io, time::Duration};
use tokio::sync::mpsc::{self};
use tracing::{level_filters::LevelFilter};
use tracing_subscriber::prelude::*;
use tracing_subscriber::{layer::SubscriberExt};

use zbus::{Connection, ConnectionBuilder};

Expand All @@ -42,6 +45,9 @@ struct Args {
//Address of potentially remote connection
#[clap(long)]
address: Option<String>,

#[clap(default_value_t = LevelFilter::OFF)]
debug_level: LevelFilter,
}

// This function is mainly used to make error handling nicer, so that we can cleanup the terminal nicely
Expand All @@ -66,10 +72,17 @@ where
let app = App::new(app_receiver, dbus_handler);
run_app(terminal, app, tick_rate).await
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let args = Args::parse();

// Initialize tracing to journald
let registry = tracing_subscriber::registry();
match tracing_journald::layer() {
Ok(layer) => registry.with(layer.with_filter(args.debug_level)).init(),
Err(_) => (),
}
enable_raw_mode()?;
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
Expand Down
2 changes: 1 addition & 1 deletion src/bin/dtui/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ pub enum DbusMessage {
ServiceRequest(),
}
pub enum AppMessage {
Objects(HashMap<String, Node<'static>>),
Objects((OwnedBusName, HashMap<String, Node<'static>>)), // Service name + Map of (Object names, node)
Services(Vec<OwnedBusName>),
}
Loading

0 comments on commit c1a100a

Please sign in to comment.