Skip to main content

winterbaume_simpledbv2/
views.rs

1//! Serde-compatible view types for SDB state snapshots.
2
3use std::collections::{HashMap, HashSet};
4
5use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7use winterbaume_core::{StateChangeNotifier, StateViewError, StatefulService};
8
9use crate::handlers::SimpleDbV2Service;
10use crate::state::SdbState;
11use crate::types::Export;
12
13#[derive(Debug, Clone, Serialize, Deserialize, Default)]
14pub struct SdbStateView {
15    #[serde(default)]
16    pub exports: HashMap<String, ExportView>,
17    #[serde(default)]
18    pub domains: HashSet<String>,
19    #[serde(default)]
20    pub next_export_id: u64,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct ExportView {
25    pub export_arn: String,
26    pub client_token: String,
27    pub export_status: String,
28    pub domain_name: String,
29    pub requested_at: DateTime<Utc>,
30    pub s3_bucket: String,
31    pub s3_key_prefix: Option<String>,
32    pub s3_sse_algorithm: Option<String>,
33    pub s3_sse_kms_key_id: Option<String>,
34    pub s3_bucket_owner: Option<String>,
35    pub failure_code: Option<String>,
36    pub failure_message: Option<String>,
37    pub export_manifest: Option<String>,
38    pub items_count: Option<i64>,
39    pub export_data_cutoff_time: Option<DateTime<Utc>>,
40}
41
42impl From<&SdbState> for SdbStateView {
43    fn from(state: &SdbState) -> Self {
44        SdbStateView {
45            exports: state
46                .exports
47                .iter()
48                .map(|(k, v)| (k.clone(), ExportView::from(v)))
49                .collect(),
50            domains: state.domains.clone(),
51            next_export_id: state.next_export_id,
52        }
53    }
54}
55
56impl From<&Export> for ExportView {
57    fn from(e: &Export) -> Self {
58        ExportView {
59            export_arn: e.export_arn.clone(),
60            client_token: e.client_token.clone(),
61            export_status: e.export_status.clone(),
62            domain_name: e.domain_name.clone(),
63            requested_at: e.requested_at,
64            s3_bucket: e.s3_bucket.clone(),
65            s3_key_prefix: e.s3_key_prefix.clone(),
66            s3_sse_algorithm: e.s3_sse_algorithm.clone(),
67            s3_sse_kms_key_id: e.s3_sse_kms_key_id.clone(),
68            s3_bucket_owner: e.s3_bucket_owner.clone(),
69            failure_code: e.failure_code.clone(),
70            failure_message: e.failure_message.clone(),
71            export_manifest: e.export_manifest.clone(),
72            items_count: e.items_count,
73            export_data_cutoff_time: e.export_data_cutoff_time,
74        }
75    }
76}
77
78impl From<SdbStateView> for SdbState {
79    fn from(view: SdbStateView) -> Self {
80        SdbState {
81            exports: view
82                .exports
83                .into_iter()
84                .map(|(k, v)| (k, Export::from(v)))
85                .collect(),
86            domains: view.domains,
87            next_export_id: view.next_export_id,
88        }
89    }
90}
91
92impl From<ExportView> for Export {
93    fn from(v: ExportView) -> Self {
94        Export {
95            export_arn: v.export_arn,
96            client_token: v.client_token,
97            export_status: v.export_status,
98            domain_name: v.domain_name,
99            requested_at: v.requested_at,
100            s3_bucket: v.s3_bucket,
101            s3_key_prefix: v.s3_key_prefix,
102            s3_sse_algorithm: v.s3_sse_algorithm,
103            s3_sse_kms_key_id: v.s3_sse_kms_key_id,
104            s3_bucket_owner: v.s3_bucket_owner,
105            failure_code: v.failure_code,
106            failure_message: v.failure_message,
107            export_manifest: v.export_manifest,
108            items_count: v.items_count,
109            export_data_cutoff_time: v.export_data_cutoff_time,
110        }
111    }
112}
113
114impl StatefulService for SimpleDbV2Service {
115    type StateView = SdbStateView;
116
117    async fn snapshot(&self, account_id: &str, region: &str) -> Self::StateView {
118        let state = self.state.get(account_id, region);
119        let guard = state.read().await;
120        SdbStateView::from(&*guard)
121    }
122
123    async fn restore(
124        &self,
125        account_id: &str,
126        region: &str,
127        view: Self::StateView,
128    ) -> Result<(), StateViewError> {
129        let state = self.state.get(account_id, region);
130        {
131            let mut guard = state.write().await;
132            *guard = SdbState::from(view);
133        }
134        self.notify_state_changed(account_id, region).await;
135        Ok(())
136    }
137
138    async fn merge(
139        &self,
140        account_id: &str,
141        region: &str,
142        view: Self::StateView,
143    ) -> Result<(), StateViewError> {
144        let state = self.state.get(account_id, region);
145        {
146            let mut guard = state.write().await;
147            for (k, v) in view.exports {
148                guard.exports.insert(k, Export::from(v));
149            }
150            for domain in view.domains {
151                guard.domains.insert(domain);
152            }
153        }
154        self.notify_state_changed(account_id, region).await;
155        Ok(())
156    }
157
158    fn notifier(&self) -> &StateChangeNotifier<Self::StateView> {
159        &self.notifier
160    }
161}