mirror of
https://github.com/lexmount/moli.git
synced 2026-10-03 00:00:44 +00:00
simplify indexeddb storage bucket integration
This commit is contained in:
@@ -258,7 +258,6 @@ pub(crate) use self::image_data::{
|
||||
ImageDataClonePayload, build_image_data_object_from_clone_payload,
|
||||
image_data_clone_payload_from_object, is_image_data_object,
|
||||
};
|
||||
pub(in crate::context_bootstrap) use self::indexed_db::IndexedDbStorageBucketContext;
|
||||
pub(crate) use self::indexed_db::{
|
||||
IndexedDbTaskId, discard_indexed_db_task_by_id, flush_blocked_indexed_db_requests,
|
||||
flush_indexed_db_task_by_id, flush_next_indexed_db_task, indexed_db_has_pending_tasks,
|
||||
|
||||
@@ -8,12 +8,11 @@ use super::{
|
||||
INDEXED_DB_TRANSACTION_DB_KEY_SLOT, INDEXED_DB_TRANSACTION_FINISHED_SLOT,
|
||||
INDEXED_DB_TRANSACTION_HANDLE_SLOT, IdbKeyRangeQuery, IndexEntry, IndexInfo, IndexedDbError,
|
||||
IndexedDbExecutionOwner, IndexedDbExternalObject, IndexedDbManager,
|
||||
IndexedDbObjectStoreMetadata, IndexedDbQuotaCheck, IndexedDbRuntimeArray,
|
||||
IndexedDbStorageBucketContext, IndexedDbStorageScope, IndexedDbValue, IndexedDbWrapperKind,
|
||||
Key, KeyPath, ObjectStoreInfo, PreparedObjectStoreWrite, PreparedObjectStoreWriteError,
|
||||
TransactionHandle, TransactionMode, context_host_ptr_from_global_bridge,
|
||||
dispatch_version_change_event, global_constructor_prototype,
|
||||
indexed_db_database_store_metadata, indexed_db_object_store_database,
|
||||
IndexedDbObjectStoreMetadata, IndexedDbRuntimeArray, IndexedDbStorageScope, IndexedDbValue,
|
||||
IndexedDbWrapperKind, Key, KeyPath, ObjectStoreInfo, PreparedObjectStoreWrite,
|
||||
PreparedObjectStoreWriteError, TransactionHandle, TransactionMode,
|
||||
context_host_ptr_from_global_bridge, dispatch_version_change_event,
|
||||
global_constructor_prototype, indexed_db_database_store_metadata,
|
||||
indexed_db_object_store_metadata, indexed_db_runtime_array, indexed_db_typed_execution_owner,
|
||||
indexed_db_typed_storage_scope, new_null_prototype_object, object_bool_property,
|
||||
object_hidden_value, object_number_property, object_property_as_object, object_string_property,
|
||||
|
||||
@@ -2,8 +2,8 @@ use super::*;
|
||||
|
||||
mod dom_string_list;
|
||||
mod errors;
|
||||
mod manager;
|
||||
mod origin;
|
||||
mod storage;
|
||||
|
||||
pub(in crate::context_bootstrap::indexed_db) use self::dom_string_list::{
|
||||
idb_dom_string_list_backing_values, install_dom_string_list_template_bindings,
|
||||
@@ -12,18 +12,15 @@ pub(in crate::context_bootstrap::indexed_db) use self::dom_string_list::{
|
||||
pub(in crate::context_bootstrap::indexed_db) use self::errors::{
|
||||
dom_exception_value, request_error_object,
|
||||
};
|
||||
pub(in crate::context_bootstrap) use self::manager::indexed_db_usage_bytes_for_storage_key;
|
||||
pub(crate) use self::manager::set_indexed_db_manager_for_context;
|
||||
pub(in crate::context_bootstrap::indexed_db) use self::manager::with_indexed_db_manager;
|
||||
#[cfg(test)]
|
||||
pub(crate) use self::manager::{
|
||||
indexed_db_manager_context_slot_present_for_test,
|
||||
indexed_db_manager_isolate_slot_present_for_test,
|
||||
};
|
||||
pub(in crate::context_bootstrap::indexed_db) use self::origin::{
|
||||
current_storage_scope, origin_allows_indexed_db, storage_scope_for_current_partition,
|
||||
storage_scope_for_window_execution_context,
|
||||
};
|
||||
pub(in crate::context_bootstrap) use self::storage::indexed_db_usage_bytes_for_storage_key;
|
||||
pub(crate) use self::storage::set_indexed_db_manager_for_context;
|
||||
#[cfg(test)]
|
||||
pub(crate) use self::storage::{
|
||||
indexed_db_manager_context_slot_present_for_test,
|
||||
indexed_db_manager_isolate_slot_present_for_test,
|
||||
};
|
||||
pub(in crate::context_bootstrap::indexed_db) use self::storage::{
|
||||
storage_bucket_quota_check_for_object_store, storage_bucket_quota_check_for_transaction,
|
||||
validate_storage_bucket_indexed_db_context, with_indexed_db_manager,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
//! IndexedDB manager access bound to the current V8 context.
|
||||
|
||||
use super::{IndexedDbError, IndexedDbManager};
|
||||
use crate::context_bootstrap::indexed_db::WeakIndexedDbManager;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct IndexedDbManagerSlot(pub(crate) Option<WeakIndexedDbManager>);
|
||||
|
||||
pub(crate) fn set_indexed_db_manager_for_context(
|
||||
context: v8::Local<'_, v8::Context>,
|
||||
manager: Option<WeakIndexedDbManager>,
|
||||
) {
|
||||
let _previous = context.set_slot(std::rc::Rc::new(IndexedDbManagerSlot(manager)));
|
||||
}
|
||||
|
||||
pub(in crate::context_bootstrap::indexed_db) fn with_indexed_db_manager<R>(
|
||||
scope: &mut v8::PinScope<'_, '_>,
|
||||
f: impl FnOnce(&mut IndexedDbManager) -> std::result::Result<R, IndexedDbError>,
|
||||
) -> std::result::Result<R, IndexedDbError> {
|
||||
let manager = scope
|
||||
.get_current_context()
|
||||
.get_slot::<IndexedDbManagerSlot>()
|
||||
.as_deref()
|
||||
.and_then(|slot| slot.0.as_ref())
|
||||
.and_then(WeakIndexedDbManager::upgrade)
|
||||
.ok_or_else(|| {
|
||||
IndexedDbError::InvalidState("IndexedDB browser context is closed".to_owned())
|
||||
})?;
|
||||
let mut manager = manager.lock();
|
||||
f(&mut manager)
|
||||
}
|
||||
|
||||
pub(in crate::context_bootstrap) fn indexed_db_usage_bytes_for_storage_key(
|
||||
scope: &mut v8::PinScope<'_, '_>,
|
||||
storage_key: &str,
|
||||
) -> u64 {
|
||||
let usage = with_indexed_db_manager(scope, |manager| manager.origin_usage_bytes(storage_key));
|
||||
usage.unwrap_or(0)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn indexed_db_manager_context_slot_present_for_test(
|
||||
scope: &mut v8::PinScope<'_, '_>,
|
||||
) -> bool {
|
||||
scope
|
||||
.get_current_context()
|
||||
.get_slot::<IndexedDbManagerSlot>()
|
||||
.is_some()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn indexed_db_manager_isolate_slot_present_for_test(
|
||||
scope: &mut v8::PinScope<'_, '_>,
|
||||
) -> bool {
|
||||
scope.get_slot::<IndexedDbManagerSlot>().is_some()
|
||||
}
|
||||
@@ -2,7 +2,6 @@ use super::*;
|
||||
|
||||
pub(in crate::context_bootstrap::indexed_db) fn current_storage_scope(
|
||||
scope: &mut v8::PinScope<'_, '_>,
|
||||
bucket_context: Option<IndexedDbStorageBucketContext>,
|
||||
) -> Option<IndexedDbStorageScope> {
|
||||
if let Some(host_ptr) = context_host_ptr_from_global_bridge(scope) {
|
||||
let active_child_handle = crate::native_bridge::active_child_window_handle(scope);
|
||||
@@ -14,7 +13,6 @@ pub(in crate::context_bootstrap::indexed_db) fn current_storage_scope(
|
||||
let identity = host.browser_context_runtime().storage_partition_identity();
|
||||
return Some(IndexedDbStorageScope::new(
|
||||
storage_key,
|
||||
bucket_context,
|
||||
identity.browser_context_id(),
|
||||
identity.profile_partition_id(),
|
||||
));
|
||||
@@ -23,7 +21,6 @@ pub(in crate::context_bootstrap::indexed_db) fn current_storage_scope(
|
||||
let identity = crate::worker::worker_storage_partition_identity(scope)?;
|
||||
Some(IndexedDbStorageScope::new(
|
||||
storage_key,
|
||||
bucket_context,
|
||||
identity.browser_context_id(),
|
||||
identity.profile_partition_id(),
|
||||
))
|
||||
@@ -32,7 +29,6 @@ pub(in crate::context_bootstrap::indexed_db) fn current_storage_scope(
|
||||
pub(in crate::context_bootstrap::indexed_db) fn storage_scope_for_window_execution_context(
|
||||
scope: &mut v8::PinScope<'_, '_>,
|
||||
execution_context: crate::native_bridge::WindowExecutionContextIdentity,
|
||||
bucket_context: Option<IndexedDbStorageBucketContext>,
|
||||
) -> Option<IndexedDbStorageScope> {
|
||||
let host_ptr = context_host_ptr_from_global_bridge(scope)?;
|
||||
let host = unsafe { &mut *host_ptr };
|
||||
@@ -51,7 +47,6 @@ pub(in crate::context_bootstrap::indexed_db) fn storage_scope_for_window_executi
|
||||
let identity = host.browser_context_runtime().storage_partition_identity();
|
||||
Some(IndexedDbStorageScope::new(
|
||||
storage_context.storage_key().serialized_storage_key(),
|
||||
bucket_context,
|
||||
identity.browser_context_id(),
|
||||
identity.profile_partition_id(),
|
||||
))
|
||||
@@ -60,14 +55,12 @@ pub(in crate::context_bootstrap::indexed_db) fn storage_scope_for_window_executi
|
||||
pub(in crate::context_bootstrap::indexed_db) fn storage_scope_for_current_partition(
|
||||
scope: &mut v8::PinScope<'_, '_>,
|
||||
storage_key: impl Into<String>,
|
||||
bucket_context: Option<IndexedDbStorageBucketContext>,
|
||||
) -> Option<IndexedDbStorageScope> {
|
||||
if let Some(host_ptr) = context_host_ptr_from_global_bridge(scope) {
|
||||
let host = unsafe { &mut *host_ptr };
|
||||
let identity = host.browser_context_runtime().storage_partition_identity();
|
||||
return Some(IndexedDbStorageScope::new(
|
||||
storage_key,
|
||||
bucket_context,
|
||||
identity.browser_context_id(),
|
||||
identity.profile_partition_id(),
|
||||
));
|
||||
@@ -75,7 +68,6 @@ pub(in crate::context_bootstrap::indexed_db) fn storage_scope_for_current_partit
|
||||
let identity = crate::worker::worker_storage_partition_identity(scope)?;
|
||||
Some(IndexedDbStorageScope::new(
|
||||
storage_key,
|
||||
bucket_context,
|
||||
identity.browser_context_id(),
|
||||
identity.profile_partition_id(),
|
||||
))
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
use super::*;
|
||||
use crate::context_bootstrap::indexed_db::WeakIndexedDbManager;
|
||||
use crate::context_bootstrap::storage_buckets::{
|
||||
storage_bucket_quota_owner_for_locator, with_storage_bucket_store_entry,
|
||||
};
|
||||
|
||||
pub(in crate::context_bootstrap::indexed_db) struct StorageBucketIndexedDbQuotaCommit {
|
||||
pub quota_check: IndexedDbQuotaCheck,
|
||||
_reservation: moli_storage_service::StorageQuotaReservation,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct IndexedDbManagerSlot(pub(crate) Option<WeakIndexedDbManager>);
|
||||
|
||||
pub(crate) fn set_indexed_db_manager_for_context(
|
||||
context: v8::Local<'_, v8::Context>,
|
||||
manager: Option<WeakIndexedDbManager>,
|
||||
) {
|
||||
let _previous = context.set_slot(std::rc::Rc::new(IndexedDbManagerSlot(manager)));
|
||||
}
|
||||
|
||||
pub(in crate::context_bootstrap::indexed_db) fn with_indexed_db_manager<R>(
|
||||
scope: &mut v8::PinScope<'_, '_>,
|
||||
f: impl FnOnce(&mut IndexedDbManager) -> std::result::Result<R, IndexedDbError>,
|
||||
) -> std::result::Result<R, IndexedDbError> {
|
||||
let manager = scope
|
||||
.get_current_context()
|
||||
.get_slot::<IndexedDbManagerSlot>()
|
||||
.as_deref()
|
||||
.and_then(|slot| slot.0.as_ref())
|
||||
.and_then(WeakIndexedDbManager::upgrade)
|
||||
.ok_or_else(|| {
|
||||
IndexedDbError::InvalidState("IndexedDB browser context is closed".to_owned())
|
||||
})?;
|
||||
let mut manager = manager.lock();
|
||||
f(&mut manager)
|
||||
}
|
||||
|
||||
pub(in crate::context_bootstrap) fn indexed_db_usage_bytes_for_storage_key(
|
||||
scope: &mut v8::PinScope<'_, '_>,
|
||||
storage_key: &str,
|
||||
) -> u64 {
|
||||
let usage = with_indexed_db_manager(scope, |manager| manager.origin_usage_bytes(storage_key));
|
||||
usage.unwrap_or(0)
|
||||
}
|
||||
|
||||
pub(in crate::context_bootstrap::indexed_db) fn storage_bucket_quota_check_for_database<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
database: v8::Local<'s, v8::Object>,
|
||||
) -> Option<std::result::Result<StorageBucketIndexedDbQuotaCommit, IndexedDbError>> {
|
||||
let storage_scope = indexed_db_typed_storage_scope(scope, database)?.clone();
|
||||
let locator = if let Some(context) = storage_scope.bucket_context() {
|
||||
let Some(locator) = with_storage_bucket_store_entry(scope, |store| {
|
||||
store.bucket_locator_for_identity(&context.identity)
|
||||
}) else {
|
||||
return Some(Err(IndexedDbError::InvalidState(
|
||||
"StorageBucket IndexedDB quota store is unavailable".to_owned(),
|
||||
)));
|
||||
};
|
||||
let Some(locator) = locator else {
|
||||
return Some(Err(IndexedDbError::InvalidState(
|
||||
"StorageBucket IndexedDB bucket is no longer current".to_owned(),
|
||||
)));
|
||||
};
|
||||
locator
|
||||
} else {
|
||||
moli_storage_service::StorageBucketLocator::default_bucket(storage_scope.storage_key())
|
||||
};
|
||||
let Some(owner) = storage_bucket_quota_owner_for_locator(scope, &locator) else {
|
||||
return Some(Err(IndexedDbError::InvalidState(
|
||||
"StorageBucket IndexedDB aggregate quota owner is unavailable".to_owned(),
|
||||
)));
|
||||
};
|
||||
let reservation = owner.reserve_commit();
|
||||
let (quota, non_indexed_db_usage) = match owner.quota_and_non_indexed_db_usage() {
|
||||
Ok(usage) => usage,
|
||||
Err(error) => {
|
||||
return Some(Err(IndexedDbError::InvalidState(error.to_string())));
|
||||
}
|
||||
};
|
||||
Some(Ok(StorageBucketIndexedDbQuotaCommit {
|
||||
quota_check: IndexedDbQuotaCheck {
|
||||
quota,
|
||||
non_indexed_db_usage,
|
||||
},
|
||||
_reservation: reservation,
|
||||
}))
|
||||
}
|
||||
|
||||
pub(in crate::context_bootstrap::indexed_db) fn validate_storage_bucket_indexed_db_context(
|
||||
scope: &mut v8::PinScope<'_, '_>,
|
||||
context: &IndexedDbStorageBucketContext,
|
||||
) -> std::result::Result<(), IndexedDbError> {
|
||||
let is_current = with_storage_bucket_store_entry(scope, |store| {
|
||||
store.bucket_identity_is_live(&context.identity)
|
||||
})
|
||||
.ok_or_else(|| {
|
||||
IndexedDbError::InvalidState("StorageBucket IndexedDB store is unavailable".to_owned())
|
||||
})?;
|
||||
if is_current {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(IndexedDbError::InvalidState(
|
||||
"StorageBucket IndexedDB bucket is no longer current".to_owned(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::context_bootstrap::indexed_db) fn storage_bucket_quota_check_for_object_store<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
store: v8::Local<'s, v8::Object>,
|
||||
) -> Option<std::result::Result<StorageBucketIndexedDbQuotaCommit, IndexedDbError>> {
|
||||
let database = indexed_db_object_store_database(scope, store)?;
|
||||
storage_bucket_quota_check_for_database(scope, database)
|
||||
}
|
||||
|
||||
pub(in crate::context_bootstrap::indexed_db) fn storage_bucket_quota_check_for_transaction<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
transaction: v8::Local<'s, v8::Object>,
|
||||
) -> Option<std::result::Result<StorageBucketIndexedDbQuotaCommit, IndexedDbError>> {
|
||||
let database = object_property_as_object(scope, transaction, "db")?;
|
||||
storage_bucket_quota_check_for_database(scope, database)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn indexed_db_manager_context_slot_present_for_test(
|
||||
scope: &mut v8::PinScope<'_, '_>,
|
||||
) -> bool {
|
||||
scope
|
||||
.get_current_context()
|
||||
.get_slot::<IndexedDbManagerSlot>()
|
||||
.is_some()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn indexed_db_manager_isolate_slot_present_for_test(
|
||||
scope: &mut v8::PinScope<'_, '_>,
|
||||
) -> bool {
|
||||
scope.get_slot::<IndexedDbManagerSlot>().is_some()
|
||||
}
|
||||
@@ -22,7 +22,7 @@ use super::{
|
||||
storage_scope_for_window_execution_context, store_request_error,
|
||||
sync_transaction_object_store_names_from_database, throw_type_error, transaction_db_key,
|
||||
transaction_handle_from_value, unregister_open_database_connection,
|
||||
unregister_readwrite_transaction, v8_string, v8str, validate_storage_bucket_indexed_db_context,
|
||||
unregister_readwrite_transaction, v8_string, v8str, validate_storage_bucket_scope,
|
||||
with_indexed_db_manager,
|
||||
};
|
||||
|
||||
|
||||
@@ -47,13 +47,13 @@ fn idb_factory_effective_storage_scope<'s>(
|
||||
})
|
||||
.or_else(|| {
|
||||
owner.execution_context().and_then(|execution_context| {
|
||||
storage_scope_for_window_execution_context(scope, execution_context, None)
|
||||
storage_scope_for_window_execution_context(scope, execution_context)
|
||||
})
|
||||
})
|
||||
.or_else(|| {
|
||||
context_host_ptr_from_global_bridge(scope)
|
||||
.is_none()
|
||||
.then(|| current_storage_scope(scope, None))
|
||||
.then(|| current_storage_scope(scope))
|
||||
.flatten()
|
||||
})?;
|
||||
origin_allows_indexed_db(storage_scope.storage_key()).then_some(storage_scope)
|
||||
|
||||
@@ -32,10 +32,7 @@ pub(in crate::context_bootstrap::indexed_db) fn idb_factory_databases_callback<'
|
||||
return;
|
||||
};
|
||||
let origin = storage_scope.storage_key().to_owned();
|
||||
let bucket_context = storage_scope.bucket_context().cloned();
|
||||
if let Some(context) = bucket_context.as_ref()
|
||||
&& let Err(error) = validate_storage_bucket_indexed_db_context(scope, context)
|
||||
{
|
||||
if let Err(error) = validate_storage_bucket_scope(scope, &storage_scope) {
|
||||
let error = request_error_object(scope, &error);
|
||||
schedule_databases_promise_settlement(
|
||||
scope,
|
||||
|
||||
+1
-4
@@ -38,7 +38,6 @@ pub(in crate::context_bootstrap::indexed_db) fn idb_factory_delete_database_call
|
||||
};
|
||||
let _ = ensure_indexed_db_runtime_state(scope);
|
||||
let origin = storage_scope.storage_key().to_owned();
|
||||
let bucket_context = storage_scope.bucket_context().cloned();
|
||||
let request_storage_scope = storage_scope.clone();
|
||||
let Some(request) =
|
||||
create_open_request_object(scope, args.this(), owner, request_storage_scope)
|
||||
@@ -46,9 +45,7 @@ pub(in crate::context_bootstrap::indexed_db) fn idb_factory_delete_database_call
|
||||
rv.set_undefined();
|
||||
return;
|
||||
};
|
||||
if let Some(context) = bucket_context.as_ref()
|
||||
&& let Err(error) = validate_storage_bucket_indexed_db_context(scope, context)
|
||||
{
|
||||
if let Err(error) = validate_storage_bucket_scope(scope, &storage_scope) {
|
||||
let error = request_error_object(scope, &error);
|
||||
store_request_error(scope, request, error);
|
||||
rv.set(request.into());
|
||||
|
||||
@@ -47,7 +47,6 @@ pub(in crate::context_bootstrap::indexed_db) fn idb_factory_open_callback<'s>(
|
||||
return;
|
||||
};
|
||||
let origin = storage_scope.storage_key().to_owned();
|
||||
let bucket_context = storage_scope.bucket_context().cloned();
|
||||
let request_storage_scope = storage_scope.clone();
|
||||
let _ = ensure_indexed_db_runtime_state(scope);
|
||||
|
||||
@@ -57,9 +56,7 @@ pub(in crate::context_bootstrap::indexed_db) fn idb_factory_open_callback<'s>(
|
||||
rv.set_undefined();
|
||||
return;
|
||||
};
|
||||
if let Some(context) = bucket_context.as_ref()
|
||||
&& let Err(error) = validate_storage_bucket_indexed_db_context(scope, context)
|
||||
{
|
||||
if let Err(error) = validate_storage_bucket_scope(scope, &storage_scope) {
|
||||
let error = request_error_object(scope, &error);
|
||||
store_request_error(scope, request, error);
|
||||
rv.set(request.into());
|
||||
|
||||
@@ -19,6 +19,7 @@ mod operation_state;
|
||||
mod runtime;
|
||||
mod slots;
|
||||
mod state;
|
||||
mod storage_bucket;
|
||||
mod stores;
|
||||
mod tasks;
|
||||
mod typed_state;
|
||||
@@ -32,6 +33,10 @@ use self::event_target::*;
|
||||
use self::operation_state::*;
|
||||
use self::runtime::*;
|
||||
use self::slots::*;
|
||||
use self::storage_bucket::{
|
||||
storage_bucket_quota_check_for_object_store, storage_bucket_quota_check_for_transaction,
|
||||
validate_storage_bucket_scope,
|
||||
};
|
||||
use self::stores::*;
|
||||
use self::tasks::*;
|
||||
use self::typed_state::*;
|
||||
@@ -66,14 +71,13 @@ pub(crate) use self::install::install_worker_indexed_db_runtime_state;
|
||||
pub(super) use self::install::{
|
||||
ensure_indexed_db_runtime_state, install_indexed_db_template_bindings, window_indexed_db_getter,
|
||||
};
|
||||
pub(in crate::context_bootstrap) use self::runtime::scoped_storage_bucket_indexed_db_factory;
|
||||
pub use self::state::{
|
||||
SharedIndexedDbManager, WeakIndexedDbManager, clear_indexed_db_origin,
|
||||
clear_indexed_db_origins_with_prefix, downgrade_indexed_db_manager,
|
||||
indexed_db_origin_usage_bytes, indexed_db_origins_with_prefix_usage_bytes,
|
||||
new_indexed_db_manager,
|
||||
};
|
||||
pub(in crate::context_bootstrap) use self::types::IndexedDbStorageBucketContext;
|
||||
pub(in crate::context_bootstrap) use self::storage_bucket::scoped_storage_bucket_indexed_db_factory;
|
||||
pub use moli_indexeddb::{
|
||||
IndexedDbQuotaCheck, Key, ObjectStoreOptions, OpenOptions, TransactionMode,
|
||||
};
|
||||
|
||||
@@ -256,9 +256,16 @@ fn ensure_runtime_factory_field<'s>(
|
||||
pub(crate) fn scoped_indexed_db_factory<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
storage_key: &str,
|
||||
) -> Option<v8::Local<'s, v8::Object>> {
|
||||
let storage_scope = storage_scope_for_current_partition(scope, storage_key)?;
|
||||
build_scoped_indexed_db_factory(scope, storage_scope)
|
||||
}
|
||||
|
||||
pub(super) fn build_scoped_indexed_db_factory<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
storage_scope: IndexedDbStorageScope,
|
||||
) -> Option<v8::Local<'s, v8::Object>> {
|
||||
let factory = build_indexed_db_factory_object(scope)?;
|
||||
let storage_scope = storage_scope_for_current_partition(scope, storage_key, None)?;
|
||||
register_indexed_db_wrapper(
|
||||
scope,
|
||||
factory,
|
||||
@@ -277,7 +284,7 @@ pub(crate) fn bind_indexed_db_factory_to_window_execution_context<'s>(
|
||||
return false;
|
||||
}
|
||||
let storage_scope = indexed_db_typed_storage_scope(scope, factory)
|
||||
.or_else(|| storage_scope_for_window_execution_context(scope, execution_context, None));
|
||||
.or_else(|| storage_scope_for_window_execution_context(scope, execution_context));
|
||||
register_indexed_db_wrapper_with_owner(
|
||||
scope,
|
||||
factory,
|
||||
@@ -288,23 +295,6 @@ pub(crate) fn bind_indexed_db_factory_to_window_execution_context<'s>(
|
||||
true
|
||||
}
|
||||
|
||||
pub(in crate::context_bootstrap) fn scoped_storage_bucket_indexed_db_factory<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
storage_key: &str,
|
||||
context: &IndexedDbStorageBucketContext,
|
||||
) -> Option<v8::Local<'s, v8::Object>> {
|
||||
let factory = scoped_indexed_db_factory(scope, storage_key)?;
|
||||
let storage_scope =
|
||||
storage_scope_for_current_partition(scope, storage_key, Some(context.clone()))?;
|
||||
register_indexed_db_wrapper(
|
||||
scope,
|
||||
factory,
|
||||
IndexedDbWrapperKind::Factory,
|
||||
Some(storage_scope),
|
||||
);
|
||||
Some(factory)
|
||||
}
|
||||
|
||||
pub(in crate::context_bootstrap::indexed_db) fn indexed_db_factory_storage_scope<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
factory: v8::Local<'s, v8::Object>,
|
||||
@@ -335,12 +325,12 @@ fn build_indexed_db_factory_object<'s>(
|
||||
let storage_scope = owner
|
||||
.execution_context()
|
||||
.and_then(|execution_context| {
|
||||
storage_scope_for_window_execution_context(scope, execution_context, None)
|
||||
storage_scope_for_window_execution_context(scope, execution_context)
|
||||
})
|
||||
.or_else(|| {
|
||||
context_host_ptr_from_global_bridge(scope)
|
||||
.is_none()
|
||||
.then(|| current_storage_scope(scope, None))
|
||||
.then(|| current_storage_scope(scope))
|
||||
.flatten()
|
||||
});
|
||||
register_indexed_db_wrapper_with_owner(
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
//! Storage Bucket identity, liveness, and quota integration for IndexedDB.
|
||||
|
||||
use super::{
|
||||
IndexedDbError, IndexedDbQuotaCheck, IndexedDbStorageScope, build_scoped_indexed_db_factory,
|
||||
indexed_db_object_store_database, indexed_db_typed_storage_scope, object_property_as_object,
|
||||
storage_scope_for_current_partition,
|
||||
};
|
||||
use crate::context_bootstrap::storage_buckets::{
|
||||
storage_bucket_quota_owner_for_locator, with_storage_bucket_store_entry,
|
||||
};
|
||||
use moli_storage_service::{StorageBucketIdentity, StorageBucketLocator};
|
||||
|
||||
pub(in crate::context_bootstrap) fn scoped_storage_bucket_indexed_db_factory<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
identity: &StorageBucketIdentity,
|
||||
) -> Option<v8::Local<'s, v8::Object>> {
|
||||
let storage_scope =
|
||||
storage_scope_for_current_partition(scope, identity.indexed_db_storage_key())?
|
||||
.with_bucket_identity(identity.clone());
|
||||
build_scoped_indexed_db_factory(scope, storage_scope)
|
||||
}
|
||||
|
||||
pub(in crate::context_bootstrap::indexed_db) struct IndexedDbBucketQuotaCommit {
|
||||
pub quota_check: IndexedDbQuotaCheck,
|
||||
_reservation: moli_storage_service::StorageQuotaReservation,
|
||||
}
|
||||
|
||||
fn live_bucket_locator(
|
||||
scope: &mut v8::PinScope<'_, '_>,
|
||||
identity: &StorageBucketIdentity,
|
||||
) -> std::result::Result<StorageBucketLocator, IndexedDbError> {
|
||||
with_storage_bucket_store_entry(scope, |store| store.bucket_locator_for_identity(identity))
|
||||
.ok_or_else(|| {
|
||||
IndexedDbError::InvalidState("StorageBucket IndexedDB store is unavailable".to_owned())
|
||||
})?
|
||||
.ok_or_else(|| {
|
||||
IndexedDbError::InvalidState(
|
||||
"StorageBucket IndexedDB bucket is no longer current".to_owned(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub(in crate::context_bootstrap::indexed_db) fn validate_storage_bucket_scope(
|
||||
scope: &mut v8::PinScope<'_, '_>,
|
||||
storage_scope: &IndexedDbStorageScope,
|
||||
) -> std::result::Result<(), IndexedDbError> {
|
||||
let Some(identity) = storage_scope.bucket_identity() else {
|
||||
return Ok(());
|
||||
};
|
||||
live_bucket_locator(scope, identity).map(|_| ())
|
||||
}
|
||||
|
||||
fn storage_bucket_quota_check_for_database<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
database: v8::Local<'s, v8::Object>,
|
||||
) -> Option<std::result::Result<IndexedDbBucketQuotaCommit, IndexedDbError>> {
|
||||
let storage_scope = indexed_db_typed_storage_scope(scope, database)?;
|
||||
let locator = match storage_scope.bucket_identity() {
|
||||
Some(identity) => match live_bucket_locator(scope, identity) {
|
||||
Ok(locator) => locator,
|
||||
Err(error) => return Some(Err(error)),
|
||||
},
|
||||
None => StorageBucketLocator::default_bucket(storage_scope.storage_key()),
|
||||
};
|
||||
let Some(owner) = storage_bucket_quota_owner_for_locator(scope, &locator) else {
|
||||
return Some(Err(IndexedDbError::InvalidState(
|
||||
"StorageBucket IndexedDB aggregate quota owner is unavailable".to_owned(),
|
||||
)));
|
||||
};
|
||||
let reservation = owner.reserve_commit();
|
||||
let (quota, non_indexed_db_usage) = match owner.quota_and_non_indexed_db_usage() {
|
||||
Ok(usage) => usage,
|
||||
Err(error) => {
|
||||
return Some(Err(IndexedDbError::InvalidState(error.to_string())));
|
||||
}
|
||||
};
|
||||
Some(Ok(IndexedDbBucketQuotaCommit {
|
||||
quota_check: IndexedDbQuotaCheck {
|
||||
quota,
|
||||
non_indexed_db_usage,
|
||||
},
|
||||
_reservation: reservation,
|
||||
}))
|
||||
}
|
||||
|
||||
pub(in crate::context_bootstrap::indexed_db) fn storage_bucket_quota_check_for_object_store<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
store: v8::Local<'s, v8::Object>,
|
||||
) -> Option<std::result::Result<IndexedDbBucketQuotaCommit, IndexedDbError>> {
|
||||
let database = indexed_db_object_store_database(scope, store)?;
|
||||
storage_bucket_quota_check_for_database(scope, database)
|
||||
}
|
||||
|
||||
pub(in crate::context_bootstrap::indexed_db) fn storage_bucket_quota_check_for_transaction<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
transaction: v8::Local<'s, v8::Object>,
|
||||
) -> Option<std::result::Result<IndexedDbBucketQuotaCommit, IndexedDbError>> {
|
||||
let database = object_property_as_object(scope, transaction, "db")?;
|
||||
storage_bucket_quota_check_for_database(scope, database)
|
||||
}
|
||||
@@ -40,7 +40,7 @@ use super::{
|
||||
storage_bucket_quota_check_for_object_store, storage_bucket_quota_check_for_transaction,
|
||||
take_indexed_db_operations_waiting_for_start, take_indexed_db_task_by_id, transaction_db_key,
|
||||
transaction_handle_from_value, unregister_blocked_database_context,
|
||||
unregister_readwrite_transaction, v8_string, v8str, validate_storage_bucket_indexed_db_context,
|
||||
unregister_readwrite_transaction, v8_string, v8str, validate_storage_bucket_scope,
|
||||
with_indexed_db_manager,
|
||||
};
|
||||
use crate::util::enqueue_host_microtask;
|
||||
|
||||
@@ -6,9 +6,7 @@ pub(in crate::context_bootstrap::indexed_db) fn execute_delete_database_request<
|
||||
storage_scope: IndexedDbStorageScope,
|
||||
name: String,
|
||||
) {
|
||||
if let Some(context) = storage_scope.bucket_context()
|
||||
&& let Err(error) = validate_storage_bucket_indexed_db_context(scope, context)
|
||||
{
|
||||
if let Err(error) = validate_storage_bucket_scope(scope, &storage_scope) {
|
||||
let error = request_error_object(scope, &error);
|
||||
store_request_error(scope, request, error);
|
||||
return;
|
||||
|
||||
@@ -12,9 +12,7 @@ pub(in crate::context_bootstrap::indexed_db) fn execute_open_request<'s>(
|
||||
) {
|
||||
let database_name = name.clone();
|
||||
let storage_key = storage_scope.storage_key().to_owned();
|
||||
if let Some(context) = storage_scope.bucket_context()
|
||||
&& let Err(error) = validate_storage_bucket_indexed_db_context(scope, context)
|
||||
{
|
||||
if let Err(error) = validate_storage_bucket_scope(scope, &storage_scope) {
|
||||
let error = request_error_object(scope, &error);
|
||||
store_request_error(scope, request, error);
|
||||
return;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use super::*;
|
||||
use moli_storage_service::StorageBucketIdentity;
|
||||
use std::{cell::RefCell, collections::BTreeMap, rc::Rc};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||
@@ -79,7 +80,7 @@ impl IndexedDbExecutionOwner {
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub(super) struct IndexedDbStorageScope {
|
||||
storage_key: String,
|
||||
bucket_context: Option<IndexedDbStorageBucketContext>,
|
||||
bucket_identity: Option<StorageBucketIdentity>,
|
||||
browser_context_id: String,
|
||||
profile_partition_id: String,
|
||||
}
|
||||
@@ -87,24 +88,28 @@ pub(super) struct IndexedDbStorageScope {
|
||||
impl IndexedDbStorageScope {
|
||||
pub(super) fn new(
|
||||
storage_key: impl Into<String>,
|
||||
bucket_context: Option<IndexedDbStorageBucketContext>,
|
||||
browser_context_id: impl Into<String>,
|
||||
profile_partition_id: impl Into<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
storage_key: storage_key.into(),
|
||||
bucket_context,
|
||||
bucket_identity: None,
|
||||
browser_context_id: browser_context_id.into(),
|
||||
profile_partition_id: profile_partition_id.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn with_bucket_identity(mut self, identity: StorageBucketIdentity) -> Self {
|
||||
self.bucket_identity = Some(identity);
|
||||
self
|
||||
}
|
||||
|
||||
pub(super) fn storage_key(&self) -> &str {
|
||||
&self.storage_key
|
||||
}
|
||||
|
||||
pub(super) fn bucket_context(&self) -> Option<&IndexedDbStorageBucketContext> {
|
||||
self.bucket_context.as_ref()
|
||||
pub(super) fn bucket_identity(&self) -> Option<&StorageBucketIdentity> {
|
||||
self.bucket_identity.as_ref()
|
||||
}
|
||||
|
||||
pub(super) fn browser_context_id(&self) -> &str {
|
||||
@@ -2011,7 +2016,6 @@ mod tests {
|
||||
|
||||
let scope = IndexedDbStorageScope::new(
|
||||
"storage-key:v1;origin=https://example.test",
|
||||
None,
|
||||
"browser-context:test",
|
||||
"profile-partition:test",
|
||||
);
|
||||
@@ -2053,7 +2057,6 @@ mod tests {
|
||||
let mut table = IndexedDbRuntimeStateTable::default();
|
||||
let storage_scope = IndexedDbStorageScope::new(
|
||||
"storage-key:v1;origin=https://task.example",
|
||||
None,
|
||||
"browser-context:task",
|
||||
"profile-partition:task",
|
||||
);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use super::{IndexedDbError, IndexedDbValue, Key};
|
||||
use moli_storage_service::StorageBucketIdentity;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(super) struct IdbKeyRangeQuery {
|
||||
@@ -28,11 +27,6 @@ pub(super) struct PreparedObjectStoreWrite<'s> {
|
||||
pub(super) value: v8::Local<'s, v8::Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub(in crate::context_bootstrap) struct IndexedDbStorageBucketContext {
|
||||
pub(in crate::context_bootstrap) identity: StorageBucketIdentity,
|
||||
}
|
||||
|
||||
pub(super) enum PreparedObjectStoreWriteError {
|
||||
Backend(IndexedDbError),
|
||||
DomException {
|
||||
|
||||
@@ -1247,13 +1247,9 @@ pub(in crate::context_bootstrap) fn storage_bucket_indexed_db_getter_callback<'s
|
||||
rv.set_undefined();
|
||||
return;
|
||||
};
|
||||
let context = IndexedDbStorageBucketContext {
|
||||
identity: handle.identity.clone(),
|
||||
};
|
||||
let value =
|
||||
scoped_storage_bucket_indexed_db_factory(scope, &handle.indexed_db_storage_key, &context)
|
||||
.map(Into::into)
|
||||
.unwrap_or_else(|| v8::undefined(scope).into());
|
||||
let value = scoped_storage_bucket_indexed_db_factory(scope, &handle.identity)
|
||||
.map(Into::into)
|
||||
.unwrap_or_else(|| v8::undefined(scope).into());
|
||||
rv.set(value);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user