summaryrefslogtreecommitdiff
path: root/ext/cache/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ext/cache/lib.rs')
-rw-r--r--ext/cache/lib.rs214
1 files changed, 214 insertions, 0 deletions
diff --git a/ext/cache/lib.rs b/ext/cache/lib.rs
new file mode 100644
index 000000000..350efbc38
--- /dev/null
+++ b/ext/cache/lib.rs
@@ -0,0 +1,214 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+mod sqlite;
+use deno_core::ByteString;
+pub use sqlite::SqliteBackedCache;
+
+use async_trait::async_trait;
+use deno_core::error::AnyError;
+use deno_core::include_js_files;
+use deno_core::op;
+use deno_core::serde::Deserialize;
+use deno_core::serde::Serialize;
+use deno_core::Extension;
+use deno_core::OpState;
+use deno_core::Resource;
+use deno_core::ResourceId;
+
+use std::cell::RefCell;
+use std::path::PathBuf;
+use std::rc::Rc;
+use std::sync::Arc;
+
+#[derive(Deserialize, Serialize, Debug, Clone)]
+#[serde(rename_all = "camelCase")]
+pub struct CachePutRequest {
+ pub cache_id: i64,
+ pub request_url: String,
+ pub request_headers: Vec<(ByteString, ByteString)>,
+ pub response_headers: Vec<(ByteString, ByteString)>,
+ pub response_has_body: bool,
+ pub response_status: u16,
+ pub response_status_text: String,
+}
+
+#[derive(Deserialize, Serialize, Debug)]
+#[serde(rename_all = "camelCase")]
+pub struct CacheMatchRequest {
+ pub cache_id: i64,
+ pub request_url: String,
+ pub request_headers: Vec<(ByteString, ByteString)>,
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct CacheMatchResponse(CacheMatchResponseMeta, Option<ResourceId>);
+
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct CacheMatchResponseMeta {
+ pub response_status: u16,
+ pub response_status_text: String,
+ pub request_headers: Vec<(ByteString, ByteString)>,
+ pub response_headers: Vec<(ByteString, ByteString)>,
+}
+
+#[derive(Deserialize, Serialize, Debug)]
+#[serde(rename_all = "camelCase")]
+pub struct CacheDeleteRequest {
+ pub cache_id: i64,
+ pub request_url: String,
+}
+
+#[async_trait]
+pub trait Cache: Clone {
+ async fn storage_open(&self, cache_name: String) -> Result<i64, AnyError>;
+ async fn storage_has(&self, cache_name: String) -> Result<bool, AnyError>;
+ async fn storage_delete(&self, cache_name: String) -> Result<bool, AnyError>;
+
+ async fn put(
+ &self,
+ request_response: CachePutRequest,
+ ) -> Result<Option<Rc<dyn Resource>>, AnyError>;
+ async fn r#match(
+ &self,
+ request: CacheMatchRequest,
+ ) -> Result<
+ Option<(CacheMatchResponseMeta, Option<Rc<dyn Resource>>)>,
+ AnyError,
+ >;
+ async fn delete(&self, request: CacheDeleteRequest)
+ -> Result<bool, AnyError>;
+}
+
+#[op]
+pub async fn op_cache_storage_open<CA>(
+ state: Rc<RefCell<OpState>>,
+ cache_name: String,
+) -> Result<i64, AnyError>
+where
+ CA: Cache + 'static,
+{
+ let cache = get_cache::<CA>(&state)?;
+ cache.storage_open(cache_name).await
+}
+
+#[op]
+pub async fn op_cache_storage_has<CA>(
+ state: Rc<RefCell<OpState>>,
+ cache_name: String,
+) -> Result<bool, AnyError>
+where
+ CA: Cache + 'static,
+{
+ let cache = get_cache::<CA>(&state)?;
+ cache.storage_has(cache_name).await
+}
+
+#[op]
+pub async fn op_cache_storage_delete<CA>(
+ state: Rc<RefCell<OpState>>,
+ cache_name: String,
+) -> Result<bool, AnyError>
+where
+ CA: Cache + 'static,
+{
+ let cache = get_cache::<CA>(&state)?;
+ cache.storage_delete(cache_name).await
+}
+
+#[op]
+pub async fn op_cache_put<CA>(
+ state: Rc<RefCell<OpState>>,
+ request_response: CachePutRequest,
+) -> Result<Option<ResourceId>, AnyError>
+where
+ CA: Cache + 'static,
+{
+ let cache = get_cache::<CA>(&state)?;
+ match cache.put(request_response).await? {
+ Some(resource) => {
+ let rid = state.borrow_mut().resource_table.add_rc_dyn(resource);
+ Ok(Some(rid))
+ }
+ None => Ok(None),
+ }
+}
+
+#[op]
+pub async fn op_cache_match<CA>(
+ state: Rc<RefCell<OpState>>,
+ request: CacheMatchRequest,
+) -> Result<Option<CacheMatchResponse>, AnyError>
+where
+ CA: Cache + 'static,
+{
+ let cache = get_cache::<CA>(&state)?;
+ match cache.r#match(request).await? {
+ Some((meta, None)) => Ok(Some(CacheMatchResponse(meta, None))),
+ Some((meta, Some(resource))) => {
+ let rid = state.borrow_mut().resource_table.add_rc_dyn(resource);
+ Ok(Some(CacheMatchResponse(meta, Some(rid))))
+ }
+ None => Ok(None),
+ }
+}
+
+#[op]
+pub async fn op_cache_delete<CA>(
+ state: Rc<RefCell<OpState>>,
+ request: CacheDeleteRequest,
+) -> Result<bool, AnyError>
+where
+ CA: Cache + 'static,
+{
+ let cache = get_cache::<CA>(&state)?;
+ cache.delete(request).await
+}
+
+pub fn get_cache<CA>(state: &Rc<RefCell<OpState>>) -> Result<CA, AnyError>
+where
+ CA: Cache + 'static,
+{
+ let mut state = state.borrow_mut();
+ if let Some(cache) = state.try_borrow::<CA>() {
+ Ok(cache.clone())
+ } else {
+ let create_cache = state.borrow::<CreateCache<CA>>().clone();
+ let cache = create_cache.0();
+ state.put(cache);
+ Ok(state.borrow::<CA>().clone())
+ }
+}
+
+#[derive(Clone)]
+pub struct CreateCache<C: Cache + 'static>(pub Arc<dyn Fn() -> C>);
+
+pub fn init<CA: Cache + 'static>(
+ maybe_create_cache: Option<CreateCache<CA>>,
+) -> Extension {
+ Extension::builder()
+ .js(include_js_files!(
+ prefix "deno:ext/cache",
+ "01_cache.js",
+ ))
+ .ops(vec![
+ op_cache_storage_open::decl::<CA>(),
+ op_cache_storage_has::decl::<CA>(),
+ op_cache_storage_delete::decl::<CA>(),
+ op_cache_put::decl::<CA>(),
+ op_cache_match::decl::<CA>(),
+ op_cache_delete::decl::<CA>(),
+ ])
+ .state(move |state| {
+ if let Some(create_cache) = maybe_create_cache.clone() {
+ state.put(create_cache);
+ }
+ Ok(())
+ })
+ .build()
+}
+
+pub fn get_declaration() -> PathBuf {
+ PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_cache.d.ts")
+}