use std::convert::TryInto;
use serde::Serialize;
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture;
use worker_sys::ext::CacheStorageExt;
use crate::request::Request;
use crate::response::Response;
use crate::Result;
#[derive(Debug)]
pub struct Cache {
inner: web_sys::Cache,
}
impl Default for Cache {
fn default() -> Self {
let global: web_sys::WorkerGlobalScope = js_sys::global().unchecked_into();
Self {
inner: global.caches().unwrap().default(),
}
}
}
impl Cache {
pub async fn open(name: String) -> Self {
let global: web_sys::WorkerGlobalScope = js_sys::global().unchecked_into();
let cache = global.caches().unwrap().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_with_str(url.as_str(), &response.into()),
CacheKey::Request(request) => self
.inner
.put_with_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 = web_sys::CacheQueryOptions::new();
options.set_ignore_method(ignore_method);
let promise = match key.into() {
CacheKey::Url(url) => self
.inner
.match_with_str_and_options(url.as_str(), &options),
CacheKey::Request(request) => self
.inner
.match_with_request_and_options(&request.try_into()?, &options),
};
let result = JsFuture::from(promise).await?;
if result.is_undefined() {
Ok(None)
} else {
let edge_response: web_sys::Response = 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 = web_sys::CacheQueryOptions::new();
options.set_ignore_method(ignore_method);
let promise = match key.into() {
CacheKey::Url(url) => self
.inner
.delete_with_str_and_options(url.as_str(), &options),
CacheKey::Request(request) => self
.inner
.delete_with_request_and_options(&request.try_into()?, &options),
};
let result = JsFuture::from(promise).await?;
if result.as_bool().unwrap() {
Ok(CacheDeletionOutcome::Success)
} else {
Ok(CacheDeletionOutcome::ResponseNotFound)
}
}
}
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,
}