starduck/components/
data_requirement.rs1use std::{fmt::Display, ops::Add};
2
3use anyhow::{Ok, Result};
4use chrono::{Duration, NaiveDateTime};
5use serde::{Deserialize, Serialize};
6
7use uuid::Uuid;
8
9use serde_with::serde_as;
10
11use crate::{
12 traits::{UpdateState, UpdateStateFrom},
13 SCMessage, Status,
14};
15
16use super::{Component, IoTOutput};
17
18#[serde_as]
19#[derive(Debug, Clone, Deserialize, Serialize)]
20pub struct DataRequirement {
21 pub components: Vec<Component>,
22 pub required: bool,
23 pub count: usize,
24 #[serde_as(as = "Option<serde_with::DurationSeconds<i64>>")]
25 pub timeout: Option<Duration>,
26 pub status: Status,
27 pub output: IoTOutput,
28}
29
30impl DataRequirement {
31 pub fn new(count: usize, required: bool, timeout: Option<Duration>, output: IoTOutput) -> Self {
32 if let Some(dur) = timeout {
33 if dur.is_zero() {}
34 }
35
36 Self {
37 components: Vec::new(),
38 count,
39 required,
40 timeout,
41 status: Status::Uninitialized,
42 output,
43 }
44 }
45
46 pub fn with_defaults(component: Component, required: bool, output: IoTOutput) -> Self {
47 let default_count = 0;
48 let default_duration = None;
49
50 let mut new_data_req = Self::new(default_count, required, default_duration, output);
51 new_data_req.status = Status::Coherent;
52 new_data_req.components.push(component);
53
54 new_data_req
55 }
56
57 pub fn get_component_by_uuid(&self, uuid_to_find: Uuid) -> Option<&Component> {
58 self.components
59 .iter()
60 .find(|&component| component.uuid.map_or(false, |uuid| uuid == uuid_to_find))
61 }
62
63 pub fn find_mut_component_by_uuid(&mut self, uuid_to_find: Uuid) -> Option<&mut Component> {
64 self.components
65 .iter_mut()
66 .find(|component| component.uuid.map_or(false, |uuid| uuid == uuid_to_find))
67 }
68
69 fn valid_component_count(&self) -> usize {
70 self.components
71 .iter()
72 .filter(|&comp| comp.status == Status::Coherent)
73 .count()
74 }
75
76 fn set_all_component_status(&mut self, status: Status) {
77 for comp in self.components.iter_mut() {
78 comp.status = status;
79 }
80 }
81
82 fn validate_timeout(&mut self) -> bool {
83 if let Some(timeout) = self.timeout {
85 if timeout.is_zero() {
86 self.timeout = None;
88 return false;
89 }
90 } else {
91 return false;
92 }
93 true
94 }
95}
96
97impl UpdateState for DataRequirement {
98 fn update_state(&mut self) -> Result<()> {
99 let valid_count = self.valid_component_count();
100
101 if valid_count >= self.count {
102 self.status = Status::Coherent;
103 } else {
104 self.status = Status::Fault;
105 };
106
107 return Ok(());
108 }
109}
110
111impl UpdateStateFrom<&SCMessage> for DataRequirement {
112 fn update_state_from(&mut self, message: &SCMessage) -> Result<()> {
113 if let Some(comp) = self.find_mut_component_by_uuid(message.device_uuid) {
114 return comp.update_state_from(message);
115 }
116
117 let mut new_comp =
118 Component::with_defaults(&message.generate_name(), Some(message.device_uuid));
119 new_comp.update_state_from(message)?;
120
121 self.components.push(new_comp);
122
123 Ok(())
124 }
125}
126
127impl UpdateStateFrom<NaiveDateTime> for DataRequirement {
128 fn update_state_from(&mut self, timestamp: NaiveDateTime) -> Result<()> {
129 if !self.validate_timeout() {
131 self.set_all_component_status(Status::Coherent);
132 return self.update_state();
133 };
134
135 for comp in self.components.iter_mut() {
136 if let Some(last_time) = comp.last_reading {
137 let timeout_time = last_time.add(self.timeout.unwrap());
138
139 let time_diff = timestamp.signed_duration_since(timeout_time);
140
141 if time_diff.num_seconds() >= 0 {
143 comp.status = Status::Fault;
144 } else {
145 comp.status = Status::Coherent;
146 }
147
148 continue;
149 }
150
151 comp.status = Status::Fault;
153 }
154
155 self.update_state()
156 }
157}
158
159impl Display for DataRequirement {
160 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161 write!(f, "{}", serde_json::to_string_pretty(&self).unwrap())
162 }
163}