chore: removed leftovers, version bump

This commit is contained in:
əlemi 2022-06-12 12:35:36 +02:00
parent ba59b62b2b
commit 0a0ee7077d
No known key found for this signature in database
GPG key ID: BBCBFE5D7244634E
5 changed files with 51 additions and 252 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "dashboard" name = "dashboard"
version = "0.1.2" version = "0.1.3"
edition = "2021" edition = "2021"
[[bin]] [[bin]]

View file

@ -1,14 +1,12 @@
// pub mod source; pub mod source;
pub mod store; pub mod store;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::{RwLock, Mutex}; use std::sync::{RwLock, Mutex};
use std::num::ParseFloatError; use std::num::ParseFloatError;
use chrono::{DateTime, Utc};
use eframe::egui::plot::{Values, Value};
use eframe::epaint::Color32; use eframe::epaint::Color32;
use self::store::SQLiteDataStore; use self::store::SQLiteDataStore;
use self::source::{Panel, Source};
#[derive(Debug)] #[derive(Debug)]
pub enum FetchError { pub enum FetchError {
@ -75,62 +73,3 @@ impl ApplicationState {
return Ok(()); return Ok(());
} }
} }
pub struct Panel {
pub(crate) id: i32,
pub name: String,
pub view_scroll: bool,
pub view_size: i32,
pub timeserie: bool,
pub(crate) width: i32,
pub(crate) height: i32,
pub limit: bool,
}
impl Panel {
}
pub struct Source {
pub(crate) id: i32,
pub name: String,
pub url: String,
pub interval: i32,
pub color: Color32,
pub visible: bool,
pub(crate) last_fetch: RwLock<DateTime<Utc>>,
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>>,
pub(crate) panel_id: i32,
pub(crate) data: RwLock<Vec<Value>>,
}
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;
}
pub fn values(&self) -> Values {
Values::from_values(self.data.read().expect("Values RwLock poisoned").clone())
}
pub fn values_filter(&self, min_x:f64) -> Values {
let mut values = self.data.read().expect("Values RwLock poisoned").clone();
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()?.into_json()?;
let x : f64;
if query_x.len() > 0 {
x = jql::walker(&res, query_x)?.as_f64().unwrap(); // TODO what if it's given to us as a string?
} else {
x = Utc::now().timestamp() as f64;
}
let y = jql::walker(&res, query_y)?.as_f64().unwrap();
return Ok( Value { x, y } );
}

View file

@ -1,201 +1,61 @@
use std::sync::{Arc, Mutex}; use std::sync::RwLock;
use rand::Rng;
use std::io::{Write, Read};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize, de::{DeserializeOwned}}; use eframe::egui::plot::{Values, Value};
use eframe::egui::{plot::Value, Context}; use eframe::epaint::Color32;
use super::FetchError;
pub fn native_save(name: &str, data:String) -> std::io::Result<()> { pub struct Panel {
let mut file = std::fs::File::create(name)?; pub(crate) id: i32,
file.write_all(data.as_bytes())?; pub name: String,
return Ok(()); pub view_scroll: bool,
} pub view_size: i32,
pub struct DataSource { pub timeserie: bool,
data : Arc<Mutex<Vec<Value>>>, pub(crate) width: i32,
pub(crate) height: i32,
pub limit: bool,
} }
#[derive(Serialize, Deserialize)] pub struct Source {
struct SerializableValue { pub(crate) id: i32,
x : f64, pub name: String,
y : f64, pub url: String,
pub interval: i32,
pub color: Color32,
pub visible: bool,
pub(crate) last_fetch: RwLock<DateTime<Utc>>,
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>>,
pub(crate) panel_id: i32,
pub(crate) data: RwLock<Vec<Value>>,
} }
impl DataSource { impl Source {
pub fn new() -> Self { pub fn valid(&self) -> bool {
Self{ data: Arc::new(Mutex::new(Vec::new())) } let last_fetch = self.last_fetch.read().expect("LastFetch RwLock poisoned");
return (Utc::now() - *last_fetch).num_seconds() < self.interval as i64;
} }
pub fn view(&self) -> Vec<Value> { // TODO handle errors pub fn values(&self) -> Values {
return self.data.lock().unwrap().clone(); Values::from_values(self.data.read().expect("Values RwLock poisoned").clone())
} }
pub fn serialize(&self) -> String { pub fn values_filter(&self, min_x:f64) -> Values {
let mut out : Vec<SerializableValue> = Vec::new(); let mut values = self.data.read().expect("Values RwLock poisoned").clone();
for value in self.view() { values.retain(|x| x.x > min_x);
out.push(SerializableValue { x: value.x, y: value.y }); Values::from_values(values)
}
return serde_json::to_string(&out).unwrap();
} }
} }
pub trait PlotValue { pub fn fetch(url:&str, query_x:&str, query_y:&str) -> Result<Value, FetchError> {
fn as_value(&self) -> Value; let res = ureq::get(url).call()?.into_json()?;
} let x : f64;
if query_x.len() > 0 {
pub trait Data { x = jql::walker(&res, query_x)?.as_f64().unwrap(); // TODO what if it's given to us as a string?
fn load_remote(&mut self, url:&str, ctx:Context); } else {
fn load_local(&mut self, file:&str, ctx:Context); x = Utc::now().timestamp() as f64;
fn read(&mut self, file:&str, storage:Arc<Mutex<Vec<Value>>>, ctx:Context) -> std::io::Result<()> {
let mut file = std::fs::File::open(file)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
let data : Vec<SerializableValue> = serde_json::from_str(contents.as_str())?;
for v in data {
storage.lock().unwrap().push(Value { x: v.x, y: v.y });
}
ctx.request_repaint();
Ok(())
}
fn fetch<T>(&mut self, base:&str, endpoint:&str, storage:Arc<Mutex<Vec<Value>>>, ctx:Context)
where T : DeserializeOwned + PlotValue {
let request = ehttp::Request::get(format!("{}/{}", base, endpoint));
ehttp::fetch(request, move |result: ehttp::Result<ehttp::Response>| {
let data : T = serde_json::from_slice(result.unwrap().bytes.as_slice()).unwrap();
storage.lock().unwrap().push(data.as_value());
ctx.request_repaint();
});
} }
} let y = jql::walker(&res, query_y)?.as_f64().unwrap();
return Ok( Value { x, y } );
pub struct TpsData {
pub ds: DataSource,
load_interval : i64,
last_load : DateTime<Utc>,
}
#[derive(Serialize, Deserialize)]
struct TpsResponseData {
tps: f64
}
impl PlotValue for TpsResponseData {
fn as_value(&self) -> Value {
Value { x: Utc::now().timestamp() as f64, y: self.tps }
}
}
impl TpsData {
pub fn new(load_interval:i64) -> Self {
Self { ds: DataSource::new() , last_load: Utc::now(), load_interval }
}
}
impl Data for TpsData{
fn load_remote(&mut self, url:&str, ctx:Context) {
if (Utc::now() - self.last_load).num_seconds() < self.load_interval { return; }
self.last_load = Utc::now();
self.fetch::<TpsResponseData>(url, "tps", self.ds.data.clone(), ctx);
}
fn load_local(&mut self, file:&str, ctx:Context) {
self.read(file, self.ds.data.clone(), ctx).unwrap_or_else(|_err| println!("Could not load {}", file));
}
}
pub struct ChatData {
pub ds : DataSource,
load_interval : i64,
last_load : DateTime<Utc>,
}
#[derive(Serialize, Deserialize)]
struct ChatResponseData {
volume: f64
}
impl PlotValue for ChatResponseData {
fn as_value(&self) -> Value {
Value { x:Utc::now().timestamp() as f64, y: self.volume }
}
}
impl ChatData {
pub fn new(load_interval:i64) -> Self {
Self { ds: DataSource::new() , last_load: Utc::now(), load_interval }
}
}
impl Data for ChatData{
fn load_remote(&mut self, url:&str, ctx:Context) {
if (Utc::now() - self.last_load).num_seconds() < self.load_interval { return; }
self.last_load = Utc::now();
self.fetch::<ChatResponseData>(url, "chat_activity", self.ds.data.clone(), ctx);
}
fn load_local(&mut self, file:&str, ctx:Context) {
self.read(file, self.ds.data.clone(), ctx).unwrap_or_else(|_err| println!("Could not load {}", file));
}
}
pub struct PlayerCountData {
pub ds : DataSource,
load_interval : i64,
last_load : DateTime<Utc>,
}
#[derive(Serialize, Deserialize)]
struct PlayerCountResponseData {
count: i32
}
impl PlotValue for PlayerCountResponseData {
fn as_value(&self) -> Value {
Value { x:Utc::now().timestamp() as f64, y: self.count as f64 }
}
}
impl PlayerCountData {
pub fn new(load_interval:i64) -> Self {
Self { ds: DataSource::new() , last_load: Utc::now(), load_interval }
}
}
impl Data for PlayerCountData{
fn load_remote(&mut self, url:&str, ctx:Context) {
if (Utc::now() - self.last_load).num_seconds() < self.load_interval { return; }
self.last_load = Utc::now();
self.fetch::<PlayerCountResponseData>(url, "player_count", self.ds.data.clone(), ctx);
}
fn load_local(&mut self, file:&str, ctx:Context) {
self.read(file, self.ds.data.clone(), ctx).unwrap_or_else(|_err| println!("Could not load {}", file));
}
}
pub struct RandomData {
pub ds : DataSource,
load_interval : i64,
last_load : DateTime<Utc>,
rng: rand::rngs::ThreadRng,
}
impl RandomData {
#[allow(dead_code)]
pub fn new(load_interval:i64) -> Self {
Self { ds: DataSource::new() , last_load: Utc::now(), load_interval, rng : rand::thread_rng() }
}
}
impl Data for RandomData{
fn load_remote(&mut self, _url:&str, ctx:Context) {
if (Utc::now() - self.last_load).num_seconds() < self.load_interval { return; }
self.last_load = Utc::now();
self.ds.data.lock().unwrap().push(Value {x:Utc::now().timestamp() as f64, y:self.rng.gen()});
ctx.request_repaint();
}
fn load_local(&mut self, _file:&str, _ctx:Context) {}
} }

View file

@ -1,4 +1,4 @@
use crate::app::{data::{Panel, Source}, util::repack_color}; use crate::app::{data::source::{Panel, Source}, util::repack_color};
use chrono::{TimeZone, Utc}; use chrono::{TimeZone, Utc};
use eframe::egui::{Color32, plot::Value}; use eframe::egui::{Color32, plot::Value};
use rusqlite::{params, Connection}; use rusqlite::{params, Connection};

View file

@ -1,7 +1,7 @@
use std::sync::Arc; use std::sync::Arc;
use chrono::Utc; use chrono::Utc;
use eframe::egui::Context; use eframe::egui::Context;
use crate::app::data::{fetch, ApplicationState}; use crate::app::data::{ApplicationState, source::fetch};
pub fn native_save(state:Arc<ApplicationState>) { pub fn native_save(state:Arc<ApplicationState>) {
std::thread::spawn(move || { std::thread::spawn(move || {