use crate::services::{ analytic_service::types, metric_service::MetricService, segments_service::SegmentsService, }; use super::types::{AnalyticUnit, AnalyticUnitConfig, LearningResult, ThresholdConfig}; use async_trait::async_trait; // TODO: move to config const DETECTION_STEP: u64 = 10; pub struct ThresholdAnalyticUnit { config: ThresholdConfig, } impl ThresholdAnalyticUnit { pub fn new(config: ThresholdConfig) -> ThresholdAnalyticUnit { ThresholdAnalyticUnit { config } } } #[async_trait] impl AnalyticUnit for ThresholdAnalyticUnit { async fn learn(&mut self, _ms: MetricService, _ss: SegmentsService) -> LearningResult { return LearningResult::Finished; } fn set_config(&mut self, config: AnalyticUnitConfig) { if let AnalyticUnitConfig::Threshold(cfg) = config { self.config = cfg; } else { panic!("Bad config!"); } } async fn detect( &self, ms: MetricService, from: u64, to: u64, ) -> anyhow::Result> { let mr = ms.query(from, to, DETECTION_STEP).await.unwrap(); if mr.data.keys().len() == 0 { return Ok(Vec::new()); } let k = mr.data.keys().nth(0).unwrap(); let ts = &mr.data[k]; let mut result = Vec::<(u64, u64)>::new(); let mut from: Option = None; for (t, v) in ts { if *v > self.config.threshold { if from.is_some() { continue; } else { from = Some(*t); } } else { if from.is_some() { result.push((from.unwrap(), *t)); from = None; } } } // TODO: don't repeat myself if from.is_some() { result.push((from.unwrap(), ts.last().unwrap().0)); } // TODO: decide what to do it from is Some() in the end Ok(result) } }