use std::convert::TryInto;
use serde::Serialize;
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture;
use worker_sys::cache::Cache as EdgeCache;
use worker_sys::Response as EdgeResponse;
use worker_sys::WorkerGlobalScope;
use crate::request::Request;
use crate::response::Response;
use crate::Result;
#[derive(Debug)]
pub struct Cache {
inner: EdgeCache,
}
impl Default for Cache {
fn default() -> Self {
let global: WorkerGlobalScope = js_sys::global().unchecked_into();
Self {
inner: global.caches().default(),
}
}
}
impl Cache {
pub async fn open(name: String) -> Self {
let global: WorkerGlobalScope = js_sys::global().unchecked_into();
let cache = global.caches().open(name);
let inner = JsFuture::from(cache).await.unwrap().into();
Self { inner }
}
pub async fn put<'a, K: Into<CacheKey<'a>>>(&self, key: K, response: Response) -> Result<()> {
let promise = match key.into() {
CacheKey::Url(url) => self.inner.put_url(url.as_str(), &response.into()),
CacheKey::Request(request) => self
.inner
.put_request(&request.try_into()?, &response.into()),
};
let _ = JsFuture::from(promise).await?;
Ok(())
}
pub async fn get<'a, K: Into<CacheKey<'a>>>(
&self,
key: K,
ignore_method: bool,
) -> Result<Option<Response>> {
let options = serde_wasm_bindgen::to_value(&MatchOptions { ignore_method })?;
let promise = match key.into() {
CacheKey::Url(url) => self.inner.match_url(url.as_str(), options),
CacheKey::Request(request) => self.inner.match_request(&request.try_into()?, options),
};
let result = JsFuture::from(promise).await?;
if result.is_undefined() {
Ok(None)
} else {
let edge_response: EdgeResponse = result.into();
let response = Response::from(edge_response);
Ok(Some(response))
}
}
pub async fn delete<'a, K: Into<CacheKey<'a>>>(
&self,
key: K,
ignore_method: bool,
) -> Result<CacheDeletionOutcome> {
let options = serde_wasm_bindgen::to_value(&MatchOptions { ignore_method })?;
let promise = match key.into() {
CacheKey::Url(url) => self.inner.delete_url(url.as_str(), options),
CacheKey::Request(request) => self.inner.delete_request(&request.try_into()?, options),
};
let result = JsFuture::from(promise).await?;
if result.as_bool().unwrap() {
Ok(CacheDeletionOutcome::Success)
} else {
Ok(CacheDeletionOutcome::ResponseNotFound)
}
}
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct MatchOptions {
ignore_method: bool,
}
pub enum CacheKey<'a> {
Url(String),
Request(&'a Request),
}
impl From<&str> for CacheKey<'_> {
fn from(url: &str) -> Self {
Self::Url(url.to_string())
}
}
impl From<String> for CacheKey<'_> {
fn from(url: String) -> Self {
Self::Url(url)
}
}
impl From<&String> for CacheKey<'_> {
fn from(url: &String) -> Self {
Self::Url(url.clone())
}
}
impl<'a> From<&'a Request> for CacheKey<'a> {
fn from(request: &'a Request) -> Self {
Self::Request(request)
}
}
#[derive(Serialize)]
pub enum CacheDeletionOutcome {
Success,
ResponseNotFound,
}