1use std::{hash::Hash, sync::Arc};
8
9use dashmap::DashMap;
10use rustack_cloudfront_model::{
11 CachePolicy, CloudFrontFunction, CloudFrontOriginAccessIdentity, Distribution,
12 FieldLevelEncryption, FieldLevelEncryptionProfile, Invalidation, KeyGroup, KeyValueStore,
13 MonitoringSubscription, OriginAccessControl, OriginRequestPolicy, PublicKey, RealtimeLogConfig,
14 ResponseHeadersPolicy, TagSet,
15};
16use serde::{Deserialize, Serialize};
17
18#[derive(Debug, Default)]
20pub struct CloudFrontStore {
21 pub distributions: DashMap<String, Distribution>,
23 pub invalidations: DashMap<(String, String), Invalidation>,
25 pub origin_access_controls: DashMap<String, OriginAccessControl>,
27 pub origin_access_identities: DashMap<String, CloudFrontOriginAccessIdentity>,
29 pub cache_policies: DashMap<String, CachePolicy>,
31 pub origin_request_policies: DashMap<String, OriginRequestPolicy>,
33 pub response_headers_policies: DashMap<String, ResponseHeadersPolicy>,
35 pub key_groups: DashMap<String, KeyGroup>,
37 pub public_keys: DashMap<String, PublicKey>,
39 pub functions: DashMap<String, CloudFrontFunction>,
41 pub fle_configs: DashMap<String, FieldLevelEncryption>,
43 pub fle_profiles: DashMap<String, FieldLevelEncryptionProfile>,
45 pub monitoring_subscriptions: DashMap<String, MonitoringSubscription>,
47 pub key_value_stores: DashMap<String, KeyValueStore>,
49 pub realtime_log_configs: DashMap<String, RealtimeLogConfig>,
51 pub tags: DashMap<String, TagSet>,
53}
54
55impl CloudFrontStore {
56 #[must_use]
58 pub fn new() -> Arc<Self> {
59 Arc::new(Self::default())
60 }
61
62 #[must_use]
64 pub fn export_snapshot(&self) -> CloudFrontStoreSnapshot {
65 CloudFrontStoreSnapshot {
66 distributions: sorted_values(&self.distributions, |value| value.id.clone()),
67 invalidations: sorted_values(&self.invalidations, |value| {
68 (value.distribution_id.clone(), value.id.clone())
69 }),
70 origin_access_controls: sorted_values(&self.origin_access_controls, |value| {
71 value.id.clone()
72 }),
73 origin_access_identities: sorted_values(&self.origin_access_identities, |value| {
74 value.id.clone()
75 }),
76 cache_policies: sorted_values(&self.cache_policies, |value| value.id.clone()),
77 origin_request_policies: sorted_values(&self.origin_request_policies, |value| {
78 value.id.clone()
79 }),
80 response_headers_policies: sorted_values(&self.response_headers_policies, |value| {
81 value.id.clone()
82 }),
83 key_groups: sorted_values(&self.key_groups, |value| value.id.clone()),
84 public_keys: sorted_values(&self.public_keys, |value| value.id.clone()),
85 functions: sorted_values(&self.functions, |value| value.name.clone()),
86 fle_configs: sorted_values(&self.fle_configs, |value| value.id.clone()),
87 fle_profiles: sorted_values(&self.fle_profiles, |value| value.id.clone()),
88 monitoring_subscriptions: sorted_values(&self.monitoring_subscriptions, |value| {
89 value.distribution_id.clone()
90 }),
91 key_value_stores: sorted_values(&self.key_value_stores, |value| value.name.clone()),
92 realtime_log_configs: sorted_values(&self.realtime_log_configs, |value| {
93 value.name.clone()
94 }),
95 tags: sorted_key_values(&self.tags),
96 }
97 }
98
99 pub fn import_snapshot(&self, snapshot: CloudFrontStoreSnapshot) {
101 self.distributions.clear();
102 self.invalidations.clear();
103 self.origin_access_controls.clear();
104 self.origin_access_identities.clear();
105 self.cache_policies.clear();
106 self.origin_request_policies.clear();
107 self.response_headers_policies.clear();
108 self.key_groups.clear();
109 self.public_keys.clear();
110 self.functions.clear();
111 self.fle_configs.clear();
112 self.fle_profiles.clear();
113 self.monitoring_subscriptions.clear();
114 self.key_value_stores.clear();
115 self.realtime_log_configs.clear();
116 self.tags.clear();
117
118 for value in snapshot.distributions {
119 self.distributions.insert(value.id.clone(), value);
120 }
121 for value in snapshot.invalidations {
122 self.invalidations
123 .insert((value.distribution_id.clone(), value.id.clone()), value);
124 }
125 for value in snapshot.origin_access_controls {
126 self.origin_access_controls.insert(value.id.clone(), value);
127 }
128 for value in snapshot.origin_access_identities {
129 self.origin_access_identities
130 .insert(value.id.clone(), value);
131 }
132 for value in snapshot.cache_policies {
133 self.cache_policies.insert(value.id.clone(), value);
134 }
135 for value in snapshot.origin_request_policies {
136 self.origin_request_policies.insert(value.id.clone(), value);
137 }
138 for value in snapshot.response_headers_policies {
139 self.response_headers_policies
140 .insert(value.id.clone(), value);
141 }
142 for value in snapshot.key_groups {
143 self.key_groups.insert(value.id.clone(), value);
144 }
145 for value in snapshot.public_keys {
146 self.public_keys.insert(value.id.clone(), value);
147 }
148 for value in snapshot.functions {
149 self.functions.insert(value.name.clone(), value);
150 }
151 for value in snapshot.fle_configs {
152 self.fle_configs.insert(value.id.clone(), value);
153 }
154 for value in snapshot.fle_profiles {
155 self.fle_profiles.insert(value.id.clone(), value);
156 }
157 for value in snapshot.monitoring_subscriptions {
158 self.monitoring_subscriptions
159 .insert(value.distribution_id.clone(), value);
160 }
161 for value in snapshot.key_value_stores {
162 self.key_value_stores.insert(value.name.clone(), value);
163 }
164 for value in snapshot.realtime_log_configs {
165 self.realtime_log_configs.insert(value.name.clone(), value);
166 }
167 for (arn, tags) in snapshot.tags {
168 self.tags.insert(arn, tags);
169 }
170 }
171}
172
173#[derive(Debug, Clone, Default, Serialize, Deserialize)]
175#[serde(rename_all = "camelCase")]
176pub struct CloudFrontStoreSnapshot {
177 pub distributions: Vec<Distribution>,
179 pub invalidations: Vec<Invalidation>,
181 pub origin_access_controls: Vec<OriginAccessControl>,
183 pub origin_access_identities: Vec<CloudFrontOriginAccessIdentity>,
185 pub cache_policies: Vec<CachePolicy>,
187 pub origin_request_policies: Vec<OriginRequestPolicy>,
189 pub response_headers_policies: Vec<ResponseHeadersPolicy>,
191 pub key_groups: Vec<KeyGroup>,
193 pub public_keys: Vec<PublicKey>,
195 pub functions: Vec<CloudFrontFunction>,
197 pub fle_configs: Vec<FieldLevelEncryption>,
199 pub fle_profiles: Vec<FieldLevelEncryptionProfile>,
201 pub monitoring_subscriptions: Vec<MonitoringSubscription>,
203 pub key_value_stores: Vec<KeyValueStore>,
205 pub realtime_log_configs: Vec<RealtimeLogConfig>,
207 pub tags: Vec<(String, TagSet)>,
209}
210
211fn sorted_values<K, T, F, O>(map: &DashMap<K, T>, key_fn: F) -> Vec<T>
212where
213 K: Eq + Hash,
214 T: Clone,
215 F: Fn(&T) -> O,
216 O: Ord,
217{
218 let mut values: Vec<T> = map.iter().map(|entry| entry.value().clone()).collect();
219 values.sort_by_key(key_fn);
220 values
221}
222
223fn sorted_key_values<T>(map: &DashMap<String, T>) -> Vec<(String, T)>
224where
225 T: Clone,
226{
227 let mut values: Vec<(String, T)> = map
228 .iter()
229 .map(|entry| (entry.key().clone(), entry.value().clone()))
230 .collect();
231 values.sort_by(|left, right| left.0.cmp(&right.0));
232 values
233}