Skip to main content

winterbaume_accessanalyzer/
views.rs

1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4use winterbaume_core::{StateChangeNotifier, StateViewError, StatefulService};
5
6use crate::handlers::AccessAnalyzerService;
7use crate::state::{AccessAnalyzerState, AnalyzerState};
8use crate::types::{Analyzer, ArchiveRule, CriterionValue};
9
10#[derive(Debug, Clone, Serialize, Deserialize, Default)]
11pub struct AccessAnalyzerStateView {
12    #[serde(default)]
13    pub analyzers: HashMap<String, AnalyzerView>,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct AnalyzerView {
18    pub arn: String,
19    pub name: String,
20    pub analyzer_type: String,
21    pub status: String,
22    pub created_at: String,
23    #[serde(default)]
24    pub tags: HashMap<String, String>,
25    #[serde(default)]
26    pub archive_rules: HashMap<String, ArchiveRuleView>,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct ArchiveRuleView {
31    pub rule_name: String,
32    pub filter: HashMap<String, CriterionValueView>,
33    pub created_at: String,
34    pub updated_at: String,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct CriterionValueView {
39    #[serde(default)]
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub eq: Option<Vec<String>>,
42    #[serde(default)]
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub neq: Option<Vec<String>>,
45    #[serde(default)]
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub contains: Option<Vec<String>>,
48    #[serde(default)]
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub exists: Option<bool>,
51}
52
53// --- From internal types to view types ---
54
55impl From<&AccessAnalyzerState> for AccessAnalyzerStateView {
56    fn from(state: &AccessAnalyzerState) -> Self {
57        AccessAnalyzerStateView {
58            analyzers: state
59                .analyzers
60                .iter()
61                .map(|(k, v)| (k.clone(), AnalyzerView::from(v)))
62                .collect(),
63        }
64    }
65}
66
67impl From<&AnalyzerState> for AnalyzerView {
68    fn from(s: &AnalyzerState) -> Self {
69        AnalyzerView {
70            arn: s.analyzer.arn.clone(),
71            name: s.analyzer.name.clone(),
72            analyzer_type: s.analyzer.analyzer_type.clone(),
73            status: s.analyzer.status.clone(),
74            created_at: s.analyzer.created_at.clone(),
75            tags: s.analyzer.tags.clone(),
76            archive_rules: s
77                .archive_rules
78                .iter()
79                .map(|(k, v)| (k.clone(), ArchiveRuleView::from(v)))
80                .collect(),
81        }
82    }
83}
84
85impl From<&ArchiveRule> for ArchiveRuleView {
86    fn from(r: &ArchiveRule) -> Self {
87        ArchiveRuleView {
88            rule_name: r.rule_name.clone(),
89            filter: r
90                .filter
91                .iter()
92                .map(|(k, v)| (k.clone(), CriterionValueView::from(v)))
93                .collect(),
94            created_at: r.created_at.clone(),
95            updated_at: r.updated_at.clone(),
96        }
97    }
98}
99
100impl From<&CriterionValue> for CriterionValueView {
101    fn from(c: &CriterionValue) -> Self {
102        CriterionValueView {
103            eq: c.eq.clone(),
104            neq: c.neq.clone(),
105            contains: c.contains.clone(),
106            exists: c.exists,
107        }
108    }
109}
110
111// --- From view types to internal types ---
112
113impl From<AccessAnalyzerStateView> for AccessAnalyzerState {
114    fn from(view: AccessAnalyzerStateView) -> Self {
115        AccessAnalyzerState {
116            analyzers: view
117                .analyzers
118                .into_iter()
119                .map(|(k, v)| (k, AnalyzerState::from(v)))
120                .collect(),
121        }
122    }
123}
124
125impl From<AnalyzerView> for AnalyzerState {
126    fn from(v: AnalyzerView) -> Self {
127        AnalyzerState {
128            analyzer: Analyzer {
129                arn: v.arn,
130                name: v.name,
131                analyzer_type: v.analyzer_type,
132                status: v.status,
133                created_at: v.created_at,
134                tags: v.tags,
135            },
136            archive_rules: v
137                .archive_rules
138                .into_iter()
139                .map(|(k, v)| (k, ArchiveRule::from(v)))
140                .collect(),
141        }
142    }
143}
144
145impl From<ArchiveRuleView> for ArchiveRule {
146    fn from(v: ArchiveRuleView) -> Self {
147        ArchiveRule {
148            rule_name: v.rule_name,
149            filter: v
150                .filter
151                .into_iter()
152                .map(|(k, v)| (k, CriterionValue::from(v)))
153                .collect(),
154            created_at: v.created_at,
155            updated_at: v.updated_at,
156        }
157    }
158}
159
160impl From<CriterionValueView> for CriterionValue {
161    fn from(v: CriterionValueView) -> Self {
162        CriterionValue {
163            eq: v.eq,
164            neq: v.neq,
165            contains: v.contains,
166            exists: v.exists,
167        }
168    }
169}
170
171// --- StatefulService implementation ---
172
173impl StatefulService for AccessAnalyzerService {
174    type StateView = AccessAnalyzerStateView;
175
176    async fn snapshot(&self, account_id: &str, region: &str) -> Self::StateView {
177        let state = self.state.get(account_id, region);
178        let guard = state.read().await;
179        AccessAnalyzerStateView::from(&*guard)
180    }
181
182    async fn restore(
183        &self,
184        account_id: &str,
185        region: &str,
186        view: Self::StateView,
187    ) -> Result<(), StateViewError> {
188        let state = self.state.get(account_id, region);
189        {
190            let mut guard = state.write().await;
191            *guard = AccessAnalyzerState::from(view);
192        }
193        self.notify_state_changed(account_id, region).await;
194        Ok(())
195    }
196
197    async fn merge(
198        &self,
199        account_id: &str,
200        region: &str,
201        view: Self::StateView,
202    ) -> Result<(), StateViewError> {
203        let state = self.state.get(account_id, region);
204        {
205            let mut guard = state.write().await;
206            for (k, v) in view.analyzers {
207                guard.analyzers.insert(k, AnalyzerState::from(v));
208            }
209        }
210        self.notify_state_changed(account_id, region).await;
211        Ok(())
212    }
213
214    fn notifier(&self) -> &StateChangeNotifier<Self::StateView> {
215        &self.notifier
216    }
217}