use std::{hash::Hash, sync::Arc};
use dashmap::DashMap;
use rustack_cloudfront_model::{
CachePolicy, CloudFrontFunction, CloudFrontOriginAccessIdentity, Distribution,
FieldLevelEncryption, FieldLevelEncryptionProfile, Invalidation, KeyGroup, KeyValueStore,
MonitoringSubscription, OriginAccessControl, OriginRequestPolicy, PublicKey, RealtimeLogConfig,
ResponseHeadersPolicy, TagSet,
};
use serde::{Deserialize, Serialize};
#[derive(Debug, Default)]
pub struct CloudFrontStore {
pub distributions: DashMap<String, Distribution>,
pub invalidations: DashMap<(String, String), Invalidation>,
pub origin_access_controls: DashMap<String, OriginAccessControl>,
pub origin_access_identities: DashMap<String, CloudFrontOriginAccessIdentity>,
pub cache_policies: DashMap<String, CachePolicy>,
pub origin_request_policies: DashMap<String, OriginRequestPolicy>,
pub response_headers_policies: DashMap<String, ResponseHeadersPolicy>,
pub key_groups: DashMap<String, KeyGroup>,
pub public_keys: DashMap<String, PublicKey>,
pub functions: DashMap<String, CloudFrontFunction>,
pub fle_configs: DashMap<String, FieldLevelEncryption>,
pub fle_profiles: DashMap<String, FieldLevelEncryptionProfile>,
pub monitoring_subscriptions: DashMap<String, MonitoringSubscription>,
pub key_value_stores: DashMap<String, KeyValueStore>,
pub realtime_log_configs: DashMap<String, RealtimeLogConfig>,
pub tags: DashMap<String, TagSet>,
}
impl CloudFrontStore {
#[must_use]
pub fn new() -> Arc<Self> {
Arc::new(Self::default())
}
#[must_use]
pub fn export_snapshot(&self) -> CloudFrontStoreSnapshot {
CloudFrontStoreSnapshot {
distributions: sorted_values(&self.distributions, |value| value.id.clone()),
invalidations: sorted_values(&self.invalidations, |value| {
(value.distribution_id.clone(), value.id.clone())
}),
origin_access_controls: sorted_values(&self.origin_access_controls, |value| {
value.id.clone()
}),
origin_access_identities: sorted_values(&self.origin_access_identities, |value| {
value.id.clone()
}),
cache_policies: sorted_values(&self.cache_policies, |value| value.id.clone()),
origin_request_policies: sorted_values(&self.origin_request_policies, |value| {
value.id.clone()
}),
response_headers_policies: sorted_values(&self.response_headers_policies, |value| {
value.id.clone()
}),
key_groups: sorted_values(&self.key_groups, |value| value.id.clone()),
public_keys: sorted_values(&self.public_keys, |value| value.id.clone()),
functions: sorted_values(&self.functions, |value| value.name.clone()),
fle_configs: sorted_values(&self.fle_configs, |value| value.id.clone()),
fle_profiles: sorted_values(&self.fle_profiles, |value| value.id.clone()),
monitoring_subscriptions: sorted_values(&self.monitoring_subscriptions, |value| {
value.distribution_id.clone()
}),
key_value_stores: sorted_values(&self.key_value_stores, |value| value.name.clone()),
realtime_log_configs: sorted_values(&self.realtime_log_configs, |value| {
value.name.clone()
}),
tags: sorted_key_values(&self.tags),
}
}
pub fn import_snapshot(&self, snapshot: CloudFrontStoreSnapshot) {
self.distributions.clear();
self.invalidations.clear();
self.origin_access_controls.clear();
self.origin_access_identities.clear();
self.cache_policies.clear();
self.origin_request_policies.clear();
self.response_headers_policies.clear();
self.key_groups.clear();
self.public_keys.clear();
self.functions.clear();
self.fle_configs.clear();
self.fle_profiles.clear();
self.monitoring_subscriptions.clear();
self.key_value_stores.clear();
self.realtime_log_configs.clear();
self.tags.clear();
for value in snapshot.distributions {
self.distributions.insert(value.id.clone(), value);
}
for value in snapshot.invalidations {
self.invalidations
.insert((value.distribution_id.clone(), value.id.clone()), value);
}
for value in snapshot.origin_access_controls {
self.origin_access_controls.insert(value.id.clone(), value);
}
for value in snapshot.origin_access_identities {
self.origin_access_identities
.insert(value.id.clone(), value);
}
for value in snapshot.cache_policies {
self.cache_policies.insert(value.id.clone(), value);
}
for value in snapshot.origin_request_policies {
self.origin_request_policies.insert(value.id.clone(), value);
}
for value in snapshot.response_headers_policies {
self.response_headers_policies
.insert(value.id.clone(), value);
}
for value in snapshot.key_groups {
self.key_groups.insert(value.id.clone(), value);
}
for value in snapshot.public_keys {
self.public_keys.insert(value.id.clone(), value);
}
for value in snapshot.functions {
self.functions.insert(value.name.clone(), value);
}
for value in snapshot.fle_configs {
self.fle_configs.insert(value.id.clone(), value);
}
for value in snapshot.fle_profiles {
self.fle_profiles.insert(value.id.clone(), value);
}
for value in snapshot.monitoring_subscriptions {
self.monitoring_subscriptions
.insert(value.distribution_id.clone(), value);
}
for value in snapshot.key_value_stores {
self.key_value_stores.insert(value.name.clone(), value);
}
for value in snapshot.realtime_log_configs {
self.realtime_log_configs.insert(value.name.clone(), value);
}
for (arn, tags) in snapshot.tags {
self.tags.insert(arn, tags);
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CloudFrontStoreSnapshot {
pub distributions: Vec<Distribution>,
pub invalidations: Vec<Invalidation>,
pub origin_access_controls: Vec<OriginAccessControl>,
pub origin_access_identities: Vec<CloudFrontOriginAccessIdentity>,
pub cache_policies: Vec<CachePolicy>,
pub origin_request_policies: Vec<OriginRequestPolicy>,
pub response_headers_policies: Vec<ResponseHeadersPolicy>,
pub key_groups: Vec<KeyGroup>,
pub public_keys: Vec<PublicKey>,
pub functions: Vec<CloudFrontFunction>,
pub fle_configs: Vec<FieldLevelEncryption>,
pub fle_profiles: Vec<FieldLevelEncryptionProfile>,
pub monitoring_subscriptions: Vec<MonitoringSubscription>,
pub key_value_stores: Vec<KeyValueStore>,
pub realtime_log_configs: Vec<RealtimeLogConfig>,
pub tags: Vec<(String, TagSet)>,
}
fn sorted_values<K, T, F, O>(map: &DashMap<K, T>, key_fn: F) -> Vec<T>
where
K: Eq + Hash,
T: Clone,
F: Fn(&T) -> O,
O: Ord,
{
let mut values: Vec<T> = map.iter().map(|entry| entry.value().clone()).collect();
values.sort_by_key(key_fn);
values
}
fn sorted_key_values<T>(map: &DashMap<String, T>) -> Vec<(String, T)>
where
T: Clone,
{
let mut values: Vec<(String, T)> = map
.iter()
.map(|entry| (entry.key().clone(), entry.value().clone()))
.collect();
values.sort_by(|left, right| left.0.cmp(&right.0));
values
}