1use 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}