-
Notifications
You must be signed in to change notification settings - Fork 640
/
Copy pathcloudfront.rs
85 lines (71 loc) · 2.81 KB
/
cloudfront.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use aws_credential_types::Credentials;
use aws_sdk_cloudfront::config::retry::RetryConfig;
use aws_sdk_cloudfront::config::{BehaviorVersion, Region};
use aws_sdk_cloudfront::types::{InvalidationBatch, Paths};
use aws_sdk_cloudfront::{Client, Config};
pub struct CloudFront {
client: Client,
distribution_id: String,
}
impl CloudFront {
pub fn from_environment() -> Option<Self> {
let distribution_id = dotenvy::var("CLOUDFRONT_DISTRIBUTION").ok()?;
let access_key = dotenvy::var("AWS_ACCESS_KEY").expect("missing AWS_ACCESS_KEY");
let secret_key = dotenvy::var("AWS_SECRET_KEY").expect("missing AWS_SECRET_KEY");
let credentials = Credentials::from_keys(access_key, secret_key, None);
let config = Config::builder()
.behavior_version(BehaviorVersion::v2025_01_17())
.region(Region::new("us-east-1"))
.credentials_provider(credentials)
.retry_config(RetryConfig::standard().with_max_attempts(10))
.build();
let client = Client::from_conf(config);
Some(Self {
client,
distribution_id,
})
}
/// Invalidate a file on CloudFront
///
/// `path` is the path to the file to invalidate, such as `config.json`, or `re/ge/regex`
pub async fn invalidate(&self, path: &str) -> anyhow::Result<()> {
self.invalidate_many(vec![path.to_string()]).await
}
/// Invalidate multiple paths on Cloudfront.
#[instrument(skip(self))]
pub async fn invalidate_many(&self, mut paths: Vec<String>) -> anyhow::Result<()> {
let now = chrono::offset::Utc::now().timestamp_micros();
// We need to ensure that paths have a starting slash.
for path in paths.iter_mut() {
if !path.starts_with('/') {
*path = format!("/{path}");
}
}
let paths = Paths::builder()
// It looks like you have to set quantity even if you provide a full blown Vec, because
// reasons.
.quantity(paths.len() as i32)
.set_items(Some(paths))
.build()?;
let invalidation_batch = InvalidationBatch::builder()
.caller_reference(format!("{now}"))
.paths(paths)
.build()?;
let invalidation_request = self
.client
.create_invalidation()
.distribution_id(&self.distribution_id)
.invalidation_batch(invalidation_batch);
debug!("Sending invalidation request");
match invalidation_request.send().await {
Ok(_) => {
debug!("Invalidation request successful");
Ok(())
}
Err(error) => {
warn!(?error, "Invalidation request failed");
Err(error.into())
}
}
}
}