use crate::http::{Body, Client, Method, Request, StatusCode};
#[derive(Debug)]
pub enum Error {
UnusablePath(String),
RateLimited,
Transport(String),
UnexpectedStatus {
status: u16,
message: String,
},
}
impl std::fmt::Display for Error {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::UnusablePath(message) => write!(formatter, "unusable page path: {message}"),
Self::RateLimited => {
write!(formatter, "page cache purge refused: hourly limit reached")
}
Self::Transport(message) => write!(formatter, "page cache purge failed: {message}"),
Self::UnexpectedStatus { status, message } => {
write!(
formatter,
"page cache purge returned status {status}: {message}"
)
}
}
}
}
impl std::error::Error for Error {}
pub type Result<T> = std::result::Result<T, Error>;
pub async fn purge(paths: &[&str]) -> Result<()> {
if paths.is_empty() {
return Ok(());
}
let endpoint =
std::env::var("FN0_STATIC_PAGE_CACHE_URL").expect("FN0_STATIC_PAGE_CACHE_URL must be set");
let body = serde_json::json!({ "paths": paths }).to_string();
let request = Request::builder()
.method(Method::POST)
.uri(format!("{}/purge", endpoint.trim_end_matches('/')))
.header("content-type", "application/json")
.body(Body::from(body))
.map_err(|error| Error::Transport(error.to_string()))?;
let response = Client::new()
.send(request)
.await
.map_err(|error| Error::Transport(error.to_string()))?;
let status = response.status();
if status == StatusCode::ACCEPTED {
return Ok(());
}
let message = String::from_utf8_lossy(&response.into_body().bytes().await)
.chars()
.take(512)
.collect();
match status {
StatusCode::BAD_REQUEST => Err(Error::UnusablePath(message)),
StatusCode::TOO_MANY_REQUESTS => Err(Error::RateLimited),
_ => Err(Error::UnexpectedStatus {
status: status.as_u16(),
message,
}),
}
}