feat: show file size in footer (update every s)

also made jq_rs use bundled jqlib because rust-analyzer won't work otherwise
This commit is contained in:
əlemi 2022-06-08 12:58:07 +02:00
parent c72e8801f9
commit 203cff23f9
Signed by: alemi
GPG key ID: A4895B84D311642C
5 changed files with 46 additions and 28 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "dashboard" name = "dashboard"
version = "0.1.0" version = "0.1.1"
edition = "2021" edition = "2021"
[[bin]] [[bin]]
@ -16,7 +16,7 @@ eframe = { version = "0.18", features = ["persistence"] }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
rusqlite = { version = "0.27" } rusqlite = { version = "0.27" }
jq-rs = "0.4" jq-rs = { version = "0.4", features = ["bundled"] }
ureq = { version = "2", features = ["json"] } ureq = { version = "2", features = ["json"] }
[env] [env]

View file

@ -37,35 +37,39 @@ impl From::<rusqlite::Error> for FetchError {
pub struct ApplicationState { pub struct ApplicationState {
pub run: bool, pub run: bool,
pub file_path: PathBuf,
pub file_size: RwLock<u64>,
pub panels: RwLock<Vec<Panel>>, pub panels: RwLock<Vec<Panel>>,
pub storage: Mutex<SQLiteDataStore>, pub storage: Mutex<SQLiteDataStore>,
} }
impl ApplicationState { impl ApplicationState {
pub fn new(path:PathBuf) -> Self { pub fn new(path:PathBuf) -> Self {
let storage = SQLiteDataStore::new(path).unwrap(); let storage = SQLiteDataStore::new(path.clone()).unwrap();
let panels = storage.load_panels().unwrap(); let panels = storage.load_panels().unwrap();
return ApplicationState{ return ApplicationState{
run: true, run: true,
file_size: RwLock::new(std::fs::metadata(path.clone()).unwrap().len()),
file_path: path,
panels: RwLock::new(panels), panels: RwLock::new(panels),
storage: Mutex::new(storage), storage: Mutex::new(storage),
}; };
} }
pub fn add_panel(&self, name:&str) -> Result<(), FetchError> { pub fn add_panel(&self, name:&str) -> Result<(), FetchError> {
let panel = self.storage.lock().unwrap().new_panel(name, 100, 200, 280)?; // TODO make values customizable and useful let panel = self.storage.lock().expect("Storage Mutex poisoned").new_panel(name, 100, 200, 280)?; // TODO make values customizable and useful
self.panels.write().unwrap().push(panel); self.panels.write().expect("Panels RwLock poisoned").push(panel);
Ok(()) Ok(())
} }
pub fn add_source(&self, panel_id:i32, name:&str, url:&str, query_x:&str, query_y:&str) -> Result<(), FetchError> { pub fn add_source(&self, panel_id:i32, name:&str, url:&str, query_x:&str, query_y:&str) -> Result<(), FetchError> {
let source = self.storage.lock().unwrap().new_source(panel_id, name, url, query_x, query_y)?; let source = self.storage.lock().expect("Storage Mutex poisoned").new_source(panel_id, name, url, query_x, query_y)?;
let panels = self.panels.read().unwrap(); let panels = self.panels.read().expect("Panels RwLock poisoned");
for panel in &*panels { for panel in &*panels {
if panel.id == panel_id { if panel.id == panel_id {
panel.sources.write().unwrap().push(source); panel.sources.write().expect("Sources RwLock poisoned").push(source);
return Ok(()); return Ok(());
} }
} }
@ -104,26 +108,19 @@ pub struct Source {
impl Source { impl Source {
pub fn valid(&self) -> bool { pub fn valid(&self) -> bool {
let last_fetch = self.last_fetch.read().unwrap(); let last_fetch = self.last_fetch.read().expect("LastFetch RwLock poisoned");
return (Utc::now() - *last_fetch).num_seconds() < self.interval as i64; return (Utc::now() - *last_fetch).num_seconds() < self.interval as i64;
} }
pub fn values(&self) -> Values { pub fn values(&self) -> Values {
Values::from_values(self.data.read().unwrap().clone()) Values::from_values(self.data.read().expect("Values RwLock poisoned").clone())
} }
pub fn values_filter(&self, min_x:f64) -> Values { pub fn values_filter(&self, min_x:f64) -> Values {
let mut values = self.data.read().unwrap().clone(); let mut values = self.data.read().expect("Values RwLock poisoned").clone();
values.retain(|x| x.x > min_x); values.retain(|x| x.x > min_x);
Values::from_values(values) Values::from_values(values)
} }
// Not really useful since different data has different fetch rates
// pub fn values_limit(&self, size:usize) -> Values {
// let values = self.data.read().unwrap().clone();
// let min = if values.len() < size { 0 } else { values.len() - size };
// Values::from_values(values[min..values.len()].to_vec())
// }
} }
pub fn fetch(url:&str, query_x:&str, query_y:&str) -> Result<Value, FetchError> { pub fn fetch(url:&str, query_x:&str, query_y:&str) -> Result<Value, FetchError> {

View file

@ -3,20 +3,13 @@ pub mod worker;
pub mod util; pub mod util;
use std::sync::Arc; use std::sync::Arc;
use chrono::{DateTime, NaiveDateTime, Utc}; use chrono::Utc;
use eframe::egui; use eframe::egui;
use eframe::egui::{plot::{Line, Plot}}; use eframe::egui::{plot::{Line, Plot}};
use self::data::ApplicationState; use self::data::ApplicationState;
use self::worker::native_save; use self::worker::native_save;
use self::util::{human_size, timestamp_to_str};
fn timestamp_to_str(t:i64) -> String {
format!(
"{}",
DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(t, 0), Utc)
.format("%Y/%m/%d %H:%M:%S")
)
}
struct InputBuffer { struct InputBuffer {
panel_name: String, panel_name: String,
@ -112,7 +105,9 @@ impl eframe::App for App {
}); });
egui::TopBottomPanel::bottom("footer").show(ctx, |ui| { egui::TopBottomPanel::bottom("footer").show(ctx, |ui| {
ui.horizontal(|ui|{ ui.horizontal(|ui|{
ui.label(self.data.file.to_str().unwrap()); ui.label(self.data.file_path.to_str().unwrap());
ui.separator();
ui.label(human_size(*self.data.file_size.read().unwrap()));
ui.with_layout(egui::Layout::top_down(egui::Align::RIGHT), |ui| { ui.with_layout(egui::Layout::top_down(egui::Align::RIGHT), |ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.label(format!("v{}-{}", env!("CARGO_PKG_VERSION"), git_version::git_version!())); ui.label(format!("v{}-{}", env!("CARGO_PKG_VERSION"), git_version::git_version!()));

23
src/app/util.rs Normal file
View file

@ -0,0 +1,23 @@
// if you're handling more than terabytes of data, it's the future and you ought to update this code!
use chrono::{DateTime, Utc, NaiveDateTime};
const PREFIXES: &'static [&'static str] = &["", "k", "M", "G", "T"];
pub fn human_size(size:u64) -> String {
let mut buf : f64 = size as f64;
let mut prefix : usize = 0;
while buf > 1024.0 && prefix < PREFIXES.len() -1 {
buf /= 1024.0;
prefix += 1;
}
return format!("{:.3} {}B", buf, PREFIXES[prefix]);
}
pub fn timestamp_to_str(t:i64) -> String {
format!(
"{}",
DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(t, 0), Utc)
.format("%Y/%m/%d %H:%M:%S")
)
}

View file

@ -79,6 +79,9 @@ impl BackgroundWorker for NativeBackgroundWorker {
} }
} }
let mut fsize = state.file_size.write().expect("File Size RwLock poisoned");
*fsize = std::fs::metadata(state.file_path.clone()).unwrap().len();
ctx.request_repaint(); ctx.request_repaint();
} }
}); });