adds frontend history

This commit is contained in:
2024-12-30 21:36:46 -05:00
parent aa1763cbe7
commit ff0a578940
8 changed files with 184 additions and 63 deletions

View File

@@ -1,13 +1,13 @@
use crate::telemetry::data_item::TelemetryDataItem;
use crate::telemetry::data_value::TelemetryDataValue;
use chrono::{DateTime, SecondsFormat, TimeDelta, Utc};
use log::error;
use std::collections::VecDeque;
use std::sync::RwLock;
use log::error;
use crate::telemetry::data_item::TelemetryDataItem;
struct SegmentData {
values: Vec<TelemetryDataValue>,
timestamps: Vec<DateTime<Utc>>
timestamps: Vec<DateTime<Utc>>,
}
struct HistorySegment {
@@ -47,12 +47,18 @@ impl HistorySegment {
data.values.insert(index, value);
}
fn get(&self, from: DateTime<Utc>, to: DateTime<Utc>, maximum_resolution: TimeDelta) -> (DateTime<Utc>, Vec<TelemetryDataItem>) {
fn get(
&self,
from: DateTime<Utc>,
to: DateTime<Utc>,
maximum_resolution: TimeDelta,
) -> (DateTime<Utc>, Vec<TelemetryDataItem>) {
let mut result = vec![];
let mut next_from = from;
if from < self.end && self.start < to { // If there is overlap with the range
if from < self.end && self.start < to {
// If there is overlap with the range
let data = self.data.read().unwrap_or_else(|err| {
error!("HistorySegment::get - data was poisoned: {}", err);
let lock = err.into_inner();
@@ -73,17 +79,25 @@ impl HistorySegment {
let t = data.timestamps[i];
if t >= next_from {
let time_since_next_from = t - next_from;
next_from = match (time_since_next_from.num_nanoseconds(), maximum_resolution.num_nanoseconds()) {
next_from = match (
time_since_next_from.num_nanoseconds(),
maximum_resolution.num_nanoseconds(),
) {
(_, Some(0)) => t,
(Some(nanos_since_next_from), Some(maximum_resolution_nanos)) => {
let nanos_since_next_from = nanos_since_next_from as u64;
let maximum_resolution_nanos = maximum_resolution_nanos as u64;
let num_steps = nanos_since_next_from.div_ceil(maximum_resolution_nanos);
let num_steps =
nanos_since_next_from.div_ceil(maximum_resolution_nanos);
let subsec_nanos = maximum_resolution.subsec_nanos() as u64;
// This will break once this can't be represented in 2^63 nanoseconds (over 200 years)
let seconds = ((maximum_resolution.num_seconds() as u64) * num_steps) as i64;
let seconds =
((maximum_resolution.num_seconds() as u64) * num_steps) as i64;
let nanos = (num_steps * subsec_nanos) as i64;
next_from + TimeDelta::seconds(seconds) + TimeDelta::nanoseconds(nanos)
},
next_from
+ TimeDelta::seconds(seconds)
+ TimeDelta::nanoseconds(nanos)
}
_ => t + maximum_resolution, // If there is a gap so big it can't be represented in 2^63 nanoseconds (over 200 years) just skip forward
};
result.push(TelemetryDataItem {
@@ -104,14 +118,18 @@ pub struct TelemetryHistory {
}
impl TelemetryHistory {
pub fn new() -> Self {
Self {
segments: RwLock::new(VecDeque::new()),
}
}
pub fn insert(&self, service: &TelemetryHistoryService, value: TelemetryDataValue, timestamp: DateTime<Utc>) {
pub fn insert(
&self,
service: &TelemetryHistoryService,
value: TelemetryDataValue,
timestamp: DateTime<Utc>,
) {
let segments = self.segments.read().unwrap_or_else(|err| {
error!("TelemetryHistory::insert - segments was poisoned: {}", err);
let lock = err.into_inner();
@@ -130,14 +148,20 @@ impl TelemetryHistory {
});
if segments.len() == 0 {
segments.push_back(HistorySegment::new(timestamp, timestamp + service.segment_width));
segments.push_back(HistorySegment::new(
timestamp,
timestamp + service.segment_width,
));
} else {
while segments[segments.len() - 1].end < timestamp {
if segments.len() == service.max_segments {
let _ = segments.pop_front();
}
let start_time = segments[segments.len() - 1].end;
segments.push_back(HistorySegment::new(start_time, start_time + service.segment_width));
segments.push_back(HistorySegment::new(
start_time,
start_time + service.segment_width,
));
}
}
@@ -158,7 +182,12 @@ impl TelemetryHistory {
segments[segment_index].insert(value, timestamp);
}
pub fn get(&self, from: DateTime<Utc>, to: DateTime<Utc>, maximum_resolution: TimeDelta) -> Vec<TelemetryDataItem> {
pub fn get(
&self,
from: DateTime<Utc>,
to: DateTime<Utc>,
maximum_resolution: TimeDelta,
) -> Vec<TelemetryDataItem> {
let mut result = vec![];
let segments = self.segments.read().unwrap_or_else(|err| {
@@ -182,14 +211,14 @@ impl TelemetryHistory {
pub struct TelemetryHistoryService {
segment_width: TimeDelta,
max_segments: usize
max_segments: usize,
}
impl TelemetryHistoryService {
pub fn new() -> Self {
Self {
segment_width: TimeDelta::minutes(1),
max_segments: 5
max_segments: 5,
}
}
}

View File

@@ -1,15 +1,15 @@
use crate::core::{TelemetryDefinitionRequest, Uuid};
use crate::telemetry::data::{TelemetryData, TelemetryDataHistory};
use crate::telemetry::definition::TelemetryDefinition;
use crate::telemetry::history::{TelemetryHistory, TelemetryHistoryService};
use papaya::{HashMap, HashMapRef, LocalGuard};
use std::error::Error;
use std::hash::RandomState;
use crate::telemetry::history::{TelemetryHistory, TelemetryHistoryService};
pub struct TelemetryManagementService {
uuid_index: HashMap<String, String>,
tlm_data: HashMap<String, TelemetryDataHistory>,
telemetry_history_service: TelemetryHistoryService
telemetry_history_service: TelemetryHistoryService,
}
impl TelemetryManagementService {
@@ -17,7 +17,7 @@ impl TelemetryManagementService {
Self {
uuid_index: HashMap::new(),
tlm_data: HashMap::new(),
telemetry_history_service
telemetry_history_service,
}
}
@@ -60,12 +60,15 @@ impl TelemetryManagementService {
pub fn get_by_uuid(&self, uuid: &String) -> Option<TelemetryData> {
let tlm_data = self.tlm_data.pin();
tlm_data.get(uuid).map(|data_history| &data_history.data).cloned()
tlm_data
.get(uuid)
.map(|data_history| &data_history.data)
.cloned()
}
pub fn pin(&self) -> TelemetryManagementServicePin {
TelemetryManagementServicePin {
tlm_data: self.tlm_data.pin()
tlm_data: self.tlm_data.pin(),
}
}
@@ -75,7 +78,7 @@ impl TelemetryManagementService {
}
pub struct TelemetryManagementServicePin<'a> {
tlm_data: HashMapRef<'a, String, TelemetryDataHistory, RandomState, LocalGuard<'a>>
tlm_data: HashMapRef<'a, String, TelemetryDataHistory, RandomState, LocalGuard<'a>>,
}
impl<'a> TelemetryManagementServicePin<'a> {
@@ -83,4 +86,3 @@ impl<'a> TelemetryManagementServicePin<'a> {
self.tlm_data.get(uuid)
}
}

View File

@@ -3,5 +3,5 @@ pub mod data_item;
pub mod data_type;
pub mod data_value;
pub mod definition;
pub mod management_service;
pub mod history;
pub mod management_service;