mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
refactor(ext/cache): use concrete error type (#26109)
This commit is contained in:
parent
3df8f16500
commit
938a8ebe34
5 changed files with 88 additions and 38 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1354,6 +1354,7 @@ dependencies = [
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
"serde",
|
"serde",
|
||||||
"sha2",
|
"sha2",
|
||||||
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
1
ext/cache/Cargo.toml
vendored
1
ext/cache/Cargo.toml
vendored
|
@ -19,4 +19,5 @@ deno_core.workspace = true
|
||||||
rusqlite.workspace = true
|
rusqlite.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
sha2.workspace = true
|
sha2.workspace = true
|
||||||
|
thiserror.workspace = true
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
|
|
60
ext/cache/lib.rs
vendored
60
ext/cache/lib.rs
vendored
|
@ -7,7 +7,6 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use deno_core::error::type_error;
|
use deno_core::error::type_error;
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::serde::Deserialize;
|
use deno_core::serde::Deserialize;
|
||||||
use deno_core::serde::Serialize;
|
use deno_core::serde::Serialize;
|
||||||
|
@ -19,6 +18,20 @@ use deno_core::ResourceId;
|
||||||
mod sqlite;
|
mod sqlite;
|
||||||
pub use sqlite::SqliteBackedCache;
|
pub use sqlite::SqliteBackedCache;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum CacheError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Sqlite(#[from] rusqlite::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
JoinError(#[from] tokio::task::JoinError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Resource(deno_core::error::AnyError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Other(deno_core::error::AnyError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Io(#[from] std::io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct CreateCache<C: Cache + 'static>(pub Arc<dyn Fn() -> C>);
|
pub struct CreateCache<C: Cache + 'static>(pub Arc<dyn Fn() -> C>);
|
||||||
|
|
||||||
|
@ -92,26 +105,31 @@ pub struct CacheDeleteRequest {
|
||||||
pub trait Cache: Clone + 'static {
|
pub trait Cache: Clone + 'static {
|
||||||
type CacheMatchResourceType: Resource;
|
type CacheMatchResourceType: Resource;
|
||||||
|
|
||||||
async fn storage_open(&self, cache_name: String) -> Result<i64, AnyError>;
|
async fn storage_open(&self, cache_name: String) -> Result<i64, CacheError>;
|
||||||
async fn storage_has(&self, cache_name: String) -> Result<bool, AnyError>;
|
async fn storage_has(&self, cache_name: String) -> Result<bool, CacheError>;
|
||||||
async fn storage_delete(&self, cache_name: String) -> Result<bool, AnyError>;
|
async fn storage_delete(
|
||||||
|
&self,
|
||||||
|
cache_name: String,
|
||||||
|
) -> Result<bool, CacheError>;
|
||||||
|
|
||||||
/// Put a resource into the cache.
|
/// Put a resource into the cache.
|
||||||
async fn put(
|
async fn put(
|
||||||
&self,
|
&self,
|
||||||
request_response: CachePutRequest,
|
request_response: CachePutRequest,
|
||||||
resource: Option<Rc<dyn Resource>>,
|
resource: Option<Rc<dyn Resource>>,
|
||||||
) -> Result<(), AnyError>;
|
) -> Result<(), CacheError>;
|
||||||
|
|
||||||
async fn r#match(
|
async fn r#match(
|
||||||
&self,
|
&self,
|
||||||
request: CacheMatchRequest,
|
request: CacheMatchRequest,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
Option<(CacheMatchResponseMeta, Option<Self::CacheMatchResourceType>)>,
|
Option<(CacheMatchResponseMeta, Option<Self::CacheMatchResourceType>)>,
|
||||||
AnyError,
|
CacheError,
|
||||||
>;
|
>;
|
||||||
async fn delete(&self, request: CacheDeleteRequest)
|
async fn delete(
|
||||||
-> Result<bool, AnyError>;
|
&self,
|
||||||
|
request: CacheDeleteRequest,
|
||||||
|
) -> Result<bool, CacheError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[op2(async)]
|
#[op2(async)]
|
||||||
|
@ -119,7 +137,7 @@ pub trait Cache: Clone + 'static {
|
||||||
pub async fn op_cache_storage_open<CA>(
|
pub async fn op_cache_storage_open<CA>(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[string] cache_name: String,
|
#[string] cache_name: String,
|
||||||
) -> Result<i64, AnyError>
|
) -> Result<i64, CacheError>
|
||||||
where
|
where
|
||||||
CA: Cache,
|
CA: Cache,
|
||||||
{
|
{
|
||||||
|
@ -131,7 +149,7 @@ where
|
||||||
pub async fn op_cache_storage_has<CA>(
|
pub async fn op_cache_storage_has<CA>(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[string] cache_name: String,
|
#[string] cache_name: String,
|
||||||
) -> Result<bool, AnyError>
|
) -> Result<bool, CacheError>
|
||||||
where
|
where
|
||||||
CA: Cache,
|
CA: Cache,
|
||||||
{
|
{
|
||||||
|
@ -143,7 +161,7 @@ where
|
||||||
pub async fn op_cache_storage_delete<CA>(
|
pub async fn op_cache_storage_delete<CA>(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[string] cache_name: String,
|
#[string] cache_name: String,
|
||||||
) -> Result<bool, AnyError>
|
) -> Result<bool, CacheError>
|
||||||
where
|
where
|
||||||
CA: Cache,
|
CA: Cache,
|
||||||
{
|
{
|
||||||
|
@ -155,13 +173,19 @@ where
|
||||||
pub async fn op_cache_put<CA>(
|
pub async fn op_cache_put<CA>(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[serde] request_response: CachePutRequest,
|
#[serde] request_response: CachePutRequest,
|
||||||
) -> Result<(), AnyError>
|
) -> Result<(), CacheError>
|
||||||
where
|
where
|
||||||
CA: Cache,
|
CA: Cache,
|
||||||
{
|
{
|
||||||
let cache = get_cache::<CA>(&state)?;
|
let cache = get_cache::<CA>(&state)?;
|
||||||
let resource = match request_response.response_rid {
|
let resource = match request_response.response_rid {
|
||||||
Some(rid) => Some(state.borrow_mut().resource_table.take_any(rid)?),
|
Some(rid) => Some(
|
||||||
|
state
|
||||||
|
.borrow_mut()
|
||||||
|
.resource_table
|
||||||
|
.take_any(rid)
|
||||||
|
.map_err(CacheError::Resource)?,
|
||||||
|
),
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
cache.put(request_response, resource).await
|
cache.put(request_response, resource).await
|
||||||
|
@ -172,7 +196,7 @@ where
|
||||||
pub async fn op_cache_match<CA>(
|
pub async fn op_cache_match<CA>(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[serde] request: CacheMatchRequest,
|
#[serde] request: CacheMatchRequest,
|
||||||
) -> Result<Option<CacheMatchResponse>, AnyError>
|
) -> Result<Option<CacheMatchResponse>, CacheError>
|
||||||
where
|
where
|
||||||
CA: Cache,
|
CA: Cache,
|
||||||
{
|
{
|
||||||
|
@ -191,7 +215,7 @@ where
|
||||||
pub async fn op_cache_delete<CA>(
|
pub async fn op_cache_delete<CA>(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[serde] request: CacheDeleteRequest,
|
#[serde] request: CacheDeleteRequest,
|
||||||
) -> Result<bool, AnyError>
|
) -> Result<bool, CacheError>
|
||||||
where
|
where
|
||||||
CA: Cache,
|
CA: Cache,
|
||||||
{
|
{
|
||||||
|
@ -199,7 +223,7 @@ where
|
||||||
cache.delete(request).await
|
cache.delete(request).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_cache<CA>(state: &Rc<RefCell<OpState>>) -> Result<CA, AnyError>
|
pub fn get_cache<CA>(state: &Rc<RefCell<OpState>>) -> Result<CA, CacheError>
|
||||||
where
|
where
|
||||||
CA: Cache,
|
CA: Cache,
|
||||||
{
|
{
|
||||||
|
@ -211,7 +235,9 @@ where
|
||||||
state.put(cache);
|
state.put(cache);
|
||||||
Ok(state.borrow::<CA>().clone())
|
Ok(state.borrow::<CA>().clone())
|
||||||
} else {
|
} else {
|
||||||
Err(type_error("CacheStorage is not available in this context"))
|
Err(CacheError::Other(type_error(
|
||||||
|
"CacheStorage is not available in this context",
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
50
ext/cache/sqlite.rs
vendored
50
ext/cache/sqlite.rs
vendored
|
@ -30,6 +30,7 @@ use crate::serialize_headers;
|
||||||
use crate::vary_header_matches;
|
use crate::vary_header_matches;
|
||||||
use crate::Cache;
|
use crate::Cache;
|
||||||
use crate::CacheDeleteRequest;
|
use crate::CacheDeleteRequest;
|
||||||
|
use crate::CacheError;
|
||||||
use crate::CacheMatchRequest;
|
use crate::CacheMatchRequest;
|
||||||
use crate::CacheMatchResponseMeta;
|
use crate::CacheMatchResponseMeta;
|
||||||
use crate::CachePutRequest;
|
use crate::CachePutRequest;
|
||||||
|
@ -102,7 +103,7 @@ impl Cache for SqliteBackedCache {
|
||||||
/// Open a cache storage. Internally, this creates a row in the
|
/// Open a cache storage. Internally, this creates a row in the
|
||||||
/// sqlite db if the cache doesn't exist and returns the internal id
|
/// sqlite db if the cache doesn't exist and returns the internal id
|
||||||
/// of the cache.
|
/// of the cache.
|
||||||
async fn storage_open(&self, cache_name: String) -> Result<i64, AnyError> {
|
async fn storage_open(&self, cache_name: String) -> Result<i64, CacheError> {
|
||||||
let db = self.connection.clone();
|
let db = self.connection.clone();
|
||||||
let cache_storage_dir = self.cache_storage_dir.clone();
|
let cache_storage_dir = self.cache_storage_dir.clone();
|
||||||
spawn_blocking(move || {
|
spawn_blocking(move || {
|
||||||
|
@ -121,14 +122,14 @@ impl Cache for SqliteBackedCache {
|
||||||
)?;
|
)?;
|
||||||
let responses_dir = get_responses_dir(cache_storage_dir, cache_id);
|
let responses_dir = get_responses_dir(cache_storage_dir, cache_id);
|
||||||
std::fs::create_dir_all(responses_dir)?;
|
std::fs::create_dir_all(responses_dir)?;
|
||||||
Ok::<i64, AnyError>(cache_id)
|
Ok::<i64, CacheError>(cache_id)
|
||||||
})
|
})
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if a cache with the provided name exists.
|
/// Check if a cache with the provided name exists.
|
||||||
/// Note: this doesn't check the disk, it only checks the sqlite db.
|
/// Note: this doesn't check the disk, it only checks the sqlite db.
|
||||||
async fn storage_has(&self, cache_name: String) -> Result<bool, AnyError> {
|
async fn storage_has(&self, cache_name: String) -> Result<bool, CacheError> {
|
||||||
let db = self.connection.clone();
|
let db = self.connection.clone();
|
||||||
spawn_blocking(move || {
|
spawn_blocking(move || {
|
||||||
let db = db.lock();
|
let db = db.lock();
|
||||||
|
@ -140,13 +141,16 @@ impl Cache for SqliteBackedCache {
|
||||||
Ok(count > 0)
|
Ok(count > 0)
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
Ok::<bool, AnyError>(cache_exists)
|
Ok::<bool, CacheError>(cache_exists)
|
||||||
})
|
})
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete a cache storage. Internally, this deletes the row in the sqlite db.
|
/// Delete a cache storage. Internally, this deletes the row in the sqlite db.
|
||||||
async fn storage_delete(&self, cache_name: String) -> Result<bool, AnyError> {
|
async fn storage_delete(
|
||||||
|
&self,
|
||||||
|
cache_name: String,
|
||||||
|
) -> Result<bool, CacheError> {
|
||||||
let db = self.connection.clone();
|
let db = self.connection.clone();
|
||||||
let cache_storage_dir = self.cache_storage_dir.clone();
|
let cache_storage_dir = self.cache_storage_dir.clone();
|
||||||
spawn_blocking(move || {
|
spawn_blocking(move || {
|
||||||
|
@ -167,7 +171,7 @@ impl Cache for SqliteBackedCache {
|
||||||
std::fs::remove_dir_all(cache_dir)?;
|
std::fs::remove_dir_all(cache_dir)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok::<bool, AnyError>(maybe_cache_id.is_some())
|
Ok::<bool, CacheError>(maybe_cache_id.is_some())
|
||||||
})
|
})
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
|
@ -176,10 +180,12 @@ impl Cache for SqliteBackedCache {
|
||||||
&self,
|
&self,
|
||||||
request_response: CachePutRequest,
|
request_response: CachePutRequest,
|
||||||
resource: Option<Rc<dyn Resource>>,
|
resource: Option<Rc<dyn Resource>>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), CacheError> {
|
||||||
let db = self.connection.clone();
|
let db = self.connection.clone();
|
||||||
let cache_storage_dir = self.cache_storage_dir.clone();
|
let cache_storage_dir = self.cache_storage_dir.clone();
|
||||||
let now = SystemTime::now().duration_since(UNIX_EPOCH)?;
|
let now = SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.expect("SystemTime is before unix epoch");
|
||||||
|
|
||||||
if let Some(resource) = resource {
|
if let Some(resource) = resource {
|
||||||
let body_key = hash(&format!(
|
let body_key = hash(&format!(
|
||||||
|
@ -193,7 +199,11 @@ impl Cache for SqliteBackedCache {
|
||||||
let mut file = tokio::fs::File::create(response_path).await?;
|
let mut file = tokio::fs::File::create(response_path).await?;
|
||||||
let mut buf = BufMutView::new(64 * 1024);
|
let mut buf = BufMutView::new(64 * 1024);
|
||||||
loop {
|
loop {
|
||||||
let (size, buf2) = resource.clone().read_byob(buf).await?;
|
let (size, buf2) = resource
|
||||||
|
.clone()
|
||||||
|
.read_byob(buf)
|
||||||
|
.await
|
||||||
|
.map_err(CacheError::Other)?;
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -224,7 +234,7 @@ impl Cache for SqliteBackedCache {
|
||||||
request: CacheMatchRequest,
|
request: CacheMatchRequest,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
Option<(CacheMatchResponseMeta, Option<CacheResponseResource>)>,
|
Option<(CacheMatchResponseMeta, Option<CacheResponseResource>)>,
|
||||||
AnyError,
|
CacheError,
|
||||||
> {
|
> {
|
||||||
let db = self.connection.clone();
|
let db = self.connection.clone();
|
||||||
let cache_storage_dir = self.cache_storage_dir.clone();
|
let cache_storage_dir = self.cache_storage_dir.clone();
|
||||||
|
@ -290,19 +300,17 @@ impl Cache for SqliteBackedCache {
|
||||||
}
|
}
|
||||||
Err(err) => return Err(err.into()),
|
Err(err) => return Err(err.into()),
|
||||||
};
|
};
|
||||||
return Ok(Some((cache_meta, Some(CacheResponseResource::new(file)))));
|
Ok(Some((cache_meta, Some(CacheResponseResource::new(file)))))
|
||||||
}
|
}
|
||||||
Some((cache_meta, None)) => {
|
Some((cache_meta, None)) => Ok(Some((cache_meta, None))),
|
||||||
return Ok(Some((cache_meta, None)));
|
None => Ok(None),
|
||||||
}
|
|
||||||
None => return Ok(None),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn delete(
|
async fn delete(
|
||||||
&self,
|
&self,
|
||||||
request: CacheDeleteRequest,
|
request: CacheDeleteRequest,
|
||||||
) -> Result<bool, AnyError> {
|
) -> Result<bool, CacheError> {
|
||||||
let db = self.connection.clone();
|
let db = self.connection.clone();
|
||||||
spawn_blocking(move || {
|
spawn_blocking(move || {
|
||||||
// TODO(@satyarohith): remove the response body from disk if one exists
|
// TODO(@satyarohith): remove the response body from disk if one exists
|
||||||
|
@ -311,17 +319,17 @@ impl Cache for SqliteBackedCache {
|
||||||
"DELETE FROM request_response_list WHERE cache_id = ?1 AND request_url = ?2",
|
"DELETE FROM request_response_list WHERE cache_id = ?1 AND request_url = ?2",
|
||||||
(request.cache_id, &request.request_url),
|
(request.cache_id, &request.request_url),
|
||||||
)?;
|
)?;
|
||||||
Ok::<bool, AnyError>(rows_effected > 0)
|
Ok::<bool, CacheError>(rows_effected > 0)
|
||||||
})
|
})
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn insert_cache_asset(
|
async fn insert_cache_asset(
|
||||||
db: Arc<Mutex<rusqlite::Connection>>,
|
db: Arc<Mutex<Connection>>,
|
||||||
put: CachePutRequest,
|
put: CachePutRequest,
|
||||||
response_body_key: Option<String>,
|
response_body_key: Option<String>,
|
||||||
) -> Result<Option<String>, deno_core::anyhow::Error> {
|
) -> Result<Option<String>, CacheError> {
|
||||||
spawn_blocking(move || {
|
spawn_blocking(move || {
|
||||||
let maybe_response_body = {
|
let maybe_response_body = {
|
||||||
let db = db.lock();
|
let db = db.lock();
|
||||||
|
@ -339,7 +347,7 @@ async fn insert_cache_asset(
|
||||||
response_body_key,
|
response_body_key,
|
||||||
put.response_status,
|
put.response_status,
|
||||||
put.response_status_text,
|
put.response_status_text,
|
||||||
SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs(),
|
SystemTime::now().duration_since(UNIX_EPOCH).expect("SystemTime is before unix epoch").as_secs(),
|
||||||
),
|
),
|
||||||
|row| {
|
|row| {
|
||||||
let response_body_key: Option<String> = row.get(0)?;
|
let response_body_key: Option<String> = row.get(0)?;
|
||||||
|
@ -347,7 +355,7 @@ async fn insert_cache_asset(
|
||||||
},
|
},
|
||||||
)?
|
)?
|
||||||
};
|
};
|
||||||
Ok::<Option<String>, AnyError>(maybe_response_body)
|
Ok::<Option<String>, CacheError>(maybe_response_body)
|
||||||
}).await?
|
}).await?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
//! exceptions.
|
//! exceptions.
|
||||||
|
|
||||||
use deno_broadcast_channel::BroadcastChannelError;
|
use deno_broadcast_channel::BroadcastChannelError;
|
||||||
|
use deno_cache::CacheError;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::serde_json;
|
use deno_core::serde_json;
|
||||||
use deno_core::url;
|
use deno_core::url;
|
||||||
|
@ -154,6 +155,18 @@ pub fn get_nix_error_class(error: &nix::Error) -> &'static str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_cache_error(error: &CacheError) -> &'static str {
|
||||||
|
match error {
|
||||||
|
CacheError::Sqlite(_) => "Error",
|
||||||
|
CacheError::JoinError(_) => "Error",
|
||||||
|
CacheError::Resource(err) => {
|
||||||
|
deno_core::error::get_custom_error_class(err).unwrap_or("Error")
|
||||||
|
}
|
||||||
|
CacheError::Other(e) => get_error_class_name(e).unwrap_or("Error"),
|
||||||
|
CacheError::Io(err) => get_io_error_class(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_broadcast_channel_error(error: &BroadcastChannelError) -> &'static str {
|
fn get_broadcast_channel_error(error: &BroadcastChannelError) -> &'static str {
|
||||||
match error {
|
match error {
|
||||||
BroadcastChannelError::Resource(err) => {
|
BroadcastChannelError::Resource(err) => {
|
||||||
|
@ -173,6 +186,7 @@ pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> {
|
||||||
.or_else(|| deno_web::get_error_class_name(e))
|
.or_else(|| deno_web::get_error_class_name(e))
|
||||||
.or_else(|| deno_webstorage::get_not_supported_error_class_name(e))
|
.or_else(|| deno_webstorage::get_not_supported_error_class_name(e))
|
||||||
.or_else(|| deno_websocket::get_network_error_class_name(e))
|
.or_else(|| deno_websocket::get_network_error_class_name(e))
|
||||||
|
.or_else(|| e.downcast_ref::<CacheError>().map(get_cache_error))
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
e.downcast_ref::<BroadcastChannelError>()
|
e.downcast_ref::<BroadcastChannelError>()
|
||||||
.map(get_broadcast_channel_error)
|
.map(get_broadcast_channel_error)
|
||||||
|
|
Loading…
Reference in a new issue