add filtering of methods and objects
This commit is contained in:
parent
780be584e6
commit
3052a1861f
78
src/app.rs
78
src/app.rs
@ -7,7 +7,8 @@ use std::{
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use async_ssh2_lite::{AsyncIoTcpStream, AsyncSession};
|
use async_ssh2_lite::{AsyncIoTcpStream, AsyncSession};
|
||||||
use eframe::CreationContext;
|
use eframe::CreationContext;
|
||||||
use egui::TextEdit;
|
use egui::text::LayoutJob;
|
||||||
|
use lazy_regex::regex_replace_all;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::ubus;
|
use crate::ubus;
|
||||||
@ -31,7 +32,7 @@ pub struct App {
|
|||||||
object_filter: String,
|
object_filter: String,
|
||||||
objects: Vec<Rc<ubus::Object>>,
|
objects: Vec<Rc<ubus::Object>>,
|
||||||
payload: String,
|
payload: String,
|
||||||
response: Option<Value>,
|
response: Option<Result<Value>>,
|
||||||
|
|
||||||
is_connecting: bool,
|
is_connecting: bool,
|
||||||
is_disconnecting: bool,
|
is_disconnecting: bool,
|
||||||
@ -92,6 +93,14 @@ async fn disconnect(session: AsyncSession<AsyncIoTcpStream>) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remove_json_comments(text: &str) -> String {
|
||||||
|
let text = regex_replace_all!(r#"/\*(.|\n)*?\*/"#, &text, |_, _| ""); // Multi line comments
|
||||||
|
let text = regex_replace_all!(r#"//.*\n?"#, &text, |_| ""); // Single line comments
|
||||||
|
let text = regex_replace_all!(r#"(,)(\s*[\]}])"#, &text, |_, _, rest: &str| rest.to_string()); // Trailing commas
|
||||||
|
|
||||||
|
text.into()
|
||||||
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn init(&mut self, _cc: &CreationContext) {}
|
pub fn init(&mut self, _cc: &CreationContext) {}
|
||||||
|
|
||||||
@ -124,9 +133,9 @@ impl App {
|
|||||||
Err(err) => todo!("{}", err),
|
Err(err) => todo!("{}", err),
|
||||||
},
|
},
|
||||||
|
|
||||||
Call(result) => match result {
|
Call(result) => {
|
||||||
Ok(response) => self.response = Some(response),
|
dbg!(&result);
|
||||||
Err(err) => todo!("{}", err),
|
self.response = Some(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,14 +176,17 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn start_call(&mut self, object: String, method: String, message: Option<Value>) {
|
fn start_call(&mut self, object: String, method: String, message: Option<Value>) {
|
||||||
|
dbg!(self.session.is_some());
|
||||||
if self.session.is_none() {
|
if self.session.is_none() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbg!("call");
|
||||||
|
|
||||||
let tx = self.tx.clone();
|
let tx = self.tx.clone();
|
||||||
let session = self.session.clone().unwrap();
|
let session = self.session.clone().unwrap();
|
||||||
self.session = None;
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
|
dbg!("exec");
|
||||||
let result = ubus::call(&session, &object, &method, message.as_ref()).await;
|
let result = ubus::call(&session, &object, &method, message.as_ref()).await;
|
||||||
tx.send(AsyncEvent::Call(result)).expect("Failed to send event");
|
tx.send(AsyncEvent::Call(result)).expect("Failed to send event");
|
||||||
});
|
});
|
||||||
@ -199,12 +211,40 @@ impl App {
|
|||||||
|
|
||||||
ui.text_edit_singleline(&mut self.object_filter);
|
ui.text_edit_singleline(&mut self.object_filter);
|
||||||
egui::ScrollArea::vertical().show(ui, |ui| {
|
egui::ScrollArea::vertical().show(ui, |ui| {
|
||||||
for obj in &self.objects {
|
for obj in self.objects.iter() {
|
||||||
CollapsingHeader::new(&obj.name).show(ui, |ui| {
|
let shown_methods;
|
||||||
for (name, _) in &obj.methods {
|
if obj.name.contains(&self.object_filter) {
|
||||||
if ui.button(name).clicked() {}
|
shown_methods = obj.methods.iter()
|
||||||
}
|
.by_ref()
|
||||||
});
|
.collect::<Vec<_>>();
|
||||||
|
} else {
|
||||||
|
shown_methods = obj.methods.iter()
|
||||||
|
.filter(|(name, _)| name.contains(&self.object_filter))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if shown_methods.len() > 0 {
|
||||||
|
let style = ui.style();
|
||||||
|
let mut text = LayoutJob::default();
|
||||||
|
text.append(&obj.name, 0.0, TextFormat {
|
||||||
|
..TextFormat::default()
|
||||||
|
});
|
||||||
|
text.append(&format!("@{:x}", obj.id), 10.0, TextFormat {
|
||||||
|
color: style.noninteractive().fg_stroke.color,
|
||||||
|
italics: true,
|
||||||
|
..TextFormat::default()
|
||||||
|
});
|
||||||
|
CollapsingHeader::new(text).show(ui, |ui| {
|
||||||
|
for (name, method_params) in &shown_methods {
|
||||||
|
if ui.selectable_label(false, name).clicked() {
|
||||||
|
self.selected_object = Some(obj.clone());
|
||||||
|
self.selected_method = Some(name.clone());
|
||||||
|
let method_params = method_params.iter().map(|(s, p)| (s.as_str(), *p)).collect::<Vec<_>>();
|
||||||
|
self.payload = App::create_default_payload(&method_params);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -246,10 +286,10 @@ impl App {
|
|||||||
Array => "[]",
|
Array => "[]",
|
||||||
Double => "0.00",
|
Double => "0.00",
|
||||||
};
|
};
|
||||||
lines.push(format!("\t\"{}\": {}", ¶m_name, ¶m_value));
|
lines.push(format!("\t\"{}\": {}, // {}", ¶m_name, ¶m_value, param_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
return format!("{{\n{}\n}}", lines.join(",\n"));
|
return format!("{{\n{}\n}}", lines.join("\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_central_panel(&mut self, ui: &mut egui::Ui) {
|
fn show_central_panel(&mut self, ui: &mut egui::Ui) {
|
||||||
@ -320,7 +360,8 @@ impl App {
|
|||||||
if ui.button("call").clicked() {
|
if ui.button("call").clicked() {
|
||||||
let object_name = self.selected_object.as_ref().unwrap().name.clone();
|
let object_name = self.selected_object.as_ref().unwrap().name.clone();
|
||||||
let method_name = self.selected_method.as_ref().unwrap().clone();
|
let method_name = self.selected_method.as_ref().unwrap().clone();
|
||||||
let message = serde_json::from_str(&self.payload).unwrap(); // TODO: handle parsing error
|
let payload = remove_json_comments(&self.payload);
|
||||||
|
let message = serde_json::from_str(&payload).unwrap(); // TODO: handle parsing error
|
||||||
self.start_call(object_name, method_name, Some(message));
|
self.start_call(object_name, method_name, Some(message));
|
||||||
// TODO: Block sending other requests
|
// TODO: Block sending other requests
|
||||||
}
|
}
|
||||||
@ -339,8 +380,13 @@ impl App {
|
|||||||
.resizable(true)
|
.resizable(true)
|
||||||
.show_inside(ui, |ui| {
|
.show_inside(ui, |ui| {
|
||||||
egui::ScrollArea::vertical().show(ui, |ui| {
|
egui::ScrollArea::vertical().show(ui, |ui| {
|
||||||
|
let mut text = match response {
|
||||||
|
Ok(response) => serde_json::to_string_pretty(response).unwrap(),
|
||||||
|
Err(err) => err.to_string()
|
||||||
|
};
|
||||||
|
ui.add_space(10.0);
|
||||||
ui.add(
|
ui.add(
|
||||||
egui::TextEdit::multiline(&mut serde_json::to_string_pretty(response).unwrap())
|
egui::TextEdit::multiline(&mut text)
|
||||||
.font(egui::TextStyle::Monospace) // for cursor height
|
.font(egui::TextStyle::Monospace) // for cursor height
|
||||||
.code_editor()
|
.code_editor()
|
||||||
.desired_rows(10)
|
.desired_rows(10)
|
||||||
|
20
src/ubus.rs
20
src/ubus.rs
@ -1,4 +1,4 @@
|
|||||||
use std::{borrow::Cow, net::TcpStream, str::FromStr};
|
use std::{borrow::Cow, str::FromStr, fmt::Display};
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Result};
|
use anyhow::{anyhow, bail, Result};
|
||||||
use async_ssh2_lite::{AsyncIoTcpStream, AsyncSession};
|
use async_ssh2_lite::{AsyncIoTcpStream, AsyncSession};
|
||||||
@ -6,7 +6,7 @@ use hex::FromHex;
|
|||||||
use lazy_regex::regex_captures;
|
use lazy_regex::regex_captures;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use shell_escape::unix::escape;
|
use shell_escape::unix::escape;
|
||||||
use smol::{channel::Sender, io::AsyncReadExt, Async};
|
use smol::{channel::Sender, io::AsyncReadExt};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::async_line_reader::AsyncLineReader;
|
use crate::async_line_reader::AsyncLineReader;
|
||||||
@ -134,6 +134,22 @@ impl FromStr for MonitorEventType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for UbusParamType {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
use UbusParamType::*;
|
||||||
|
let text = match self {
|
||||||
|
String => "String",
|
||||||
|
Boolean => "Boolean",
|
||||||
|
Integer => "Integer",
|
||||||
|
Double => "Double",
|
||||||
|
Table => "Table",
|
||||||
|
Array => "Array",
|
||||||
|
Unknown => "(unknown)"
|
||||||
|
};
|
||||||
|
f.write_str(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MonitorEvent {
|
pub struct MonitorEvent {
|
||||||
direction: MonitorDir,
|
direction: MonitorDir,
|
||||||
|
Loading…
Reference in New Issue
Block a user