dashboard/src/app/data/mod.rs

137 lines
3.9 KiB
Rust
Raw Normal View History

// pub mod source;
2022-06-06 04:41:34 +02:00
pub mod store;
use std::path::PathBuf;
2022-06-07 01:28:17 +02:00
use std::sync::{RwLock, Mutex};
2022-06-06 04:41:34 +02:00
use std::num::ParseFloatError;
use chrono::{DateTime, Utc};
use eframe::egui::plot::{Values, Value};
use self::store::SQLiteDataStore;
2022-06-06 04:41:34 +02:00
#[derive(Debug)]
pub enum FetchError {
UreqError(ureq::Error),
IoError(std::io::Error),
2022-06-06 04:41:34 +02:00
JqError(jq_rs::Error),
RusqliteError(rusqlite::Error),
ParseFloatError(ParseFloatError),
NoPanelWithThatIdError,
2022-06-06 04:41:34 +02:00
}
impl From::<ureq::Error> for FetchError {
fn from(e: ureq::Error) -> Self { FetchError::UreqError(e) }
}
impl From::<std::io::Error> for FetchError {
fn from(e: std::io::Error) -> Self { FetchError::IoError(e) }
2022-06-06 04:41:34 +02:00
}
impl From::<jq_rs::Error> for FetchError {
fn from(e: jq_rs::Error) -> Self { FetchError::JqError(e) }
}
impl From::<ParseFloatError> for FetchError {
fn from(e: ParseFloatError) -> Self { FetchError::ParseFloatError(e) }
}
impl From::<rusqlite::Error> for FetchError {
fn from(e: rusqlite::Error) -> Self { FetchError::RusqliteError(e) }
}
pub struct ApplicationState {
pub run: bool,
pub file_path: PathBuf,
pub file_size: RwLock<u64>,
pub panels: RwLock<Vec<Panel>>,
pub storage: Mutex<SQLiteDataStore>,
}
impl ApplicationState {
pub fn new(path:PathBuf) -> Self {
let storage = SQLiteDataStore::new(path.clone()).unwrap();
let panels = storage.load_panels().unwrap();
return ApplicationState{
run: true,
file_size: RwLock::new(std::fs::metadata(path.clone()).unwrap().len()),
file_path: path,
panels: RwLock::new(panels),
storage: Mutex::new(storage),
};
}
pub fn add_panel(&self, name:&str) -> Result<(), FetchError> {
let panel = self.storage.lock().expect("Storage Mutex poisoned").new_panel(name, 100, 200, 280)?; // TODO make values customizable and useful
self.panels.write().expect("Panels RwLock poisoned").push(panel);
Ok(())
}
2022-06-06 04:41:34 +02:00
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().expect("Storage Mutex poisoned").new_source(panel_id, name, url, query_x, query_y)?;
let panels = self.panels.read().expect("Panels RwLock poisoned");
for panel in &*panels {
if panel.id == panel_id {
panel.sources.write().expect("Sources RwLock poisoned").push(source);
return Ok(());
}
}
Err(FetchError::NoPanelWithThatIdError)
}
}
2022-06-06 04:41:34 +02:00
pub struct Panel {
pub(crate) id: i32,
pub name: String,
pub view_scroll: bool,
pub view_size: i32,
pub timeserie: bool,
2022-06-06 04:41:34 +02:00
pub(crate) width: i32,
pub(crate) height: i32,
pub(crate) sources: RwLock<Vec<Source>>,
2022-06-06 04:41:34 +02:00
}
impl Panel {
}
pub struct Source {
pub(crate) id: i32,
pub name: String,
pub url: String,
pub interval: i32,
pub(crate) last_fetch: RwLock<DateTime<Utc>>,
2022-06-06 04:41:34 +02:00
pub query_x: String,
// pub(crate) compiled_query_x: Arc<Mutex<jq_rs::JqProgram>>,
pub query_y: String,
// pub(crate) compiled_query_y: Arc<Mutex<jq_rs::JqProgram>>,
2022-06-07 01:28:17 +02:00
// pub(crate) panel_id: i32,
pub(crate) data: RwLock<Vec<Value>>,
2022-06-06 04:41:34 +02:00
}
impl Source {
pub fn valid(&self) -> bool {
let last_fetch = self.last_fetch.read().expect("LastFetch RwLock poisoned");
return (Utc::now() - *last_fetch).num_seconds() < self.interval as i64;
2022-06-06 04:41:34 +02:00
}
pub fn values(&self) -> Values {
Values::from_values(self.data.read().expect("Values RwLock poisoned").clone())
2022-06-06 04:41:34 +02:00
}
2022-06-07 01:28:17 +02:00
pub fn values_filter(&self, min_x:f64) -> Values {
let mut values = self.data.read().expect("Values RwLock poisoned").clone();
2022-06-07 01:28:17 +02:00
values.retain(|x| x.x > min_x);
Values::from_values(values)
}
}
pub fn fetch(url:&str, query_x:&str, query_y:&str) -> Result<Value, FetchError> {
let res = ureq::get(url).call()?;
let body = res.into_string()?;
let x : f64;
if query_x.len() > 0 {
x = jq_rs::compile(query_x)?.run(&body)?.trim().parse::<f64>()?; // TODO precompile and guard with a mutex
} else {
x = Utc::now().timestamp() as f64;
2022-06-06 04:41:34 +02:00
}
let y = jq_rs::compile(query_y)?.run(&body)?.trim().parse::<f64>()?;
return Ok( Value { x, y } );
2022-06-06 04:41:34 +02:00
}