perf(renderer): defer worker runtime services

This commit is contained in:
ldm0
2026-09-01 23:21:19 +08:00
committed by Donough Liu
parent 0c8e66219e
commit b081c0d24c
15 changed files with 1270 additions and 364 deletions
@@ -117,6 +117,63 @@ impl JsContextHost {
self.service_worker_task_tx.clone()
}
fn ensure_service_worker_client_for_request_context(
&mut self,
request_context: &ServiceWorkerWindowRequestContext,
) -> ServiceWorkerClientId {
let dispatch_scope = request_context.owner().dispatch_scope();
let client_id = match dispatch_scope {
OwnerDispatchScope::Top => self.service_worker_client_id,
OwnerDispatchScope::Child(handle) => {
if let Some(client_id) = self
.child_browsing_contexts
.get(&handle)
.and_then(|entry| entry.service_worker_client_id())
{
client_id
} else {
let client_id = self
.browser_context_runtime
.allocate_service_worker_client_id();
if let Some(entry) = self.child_browsing_contexts.get_mut(&handle) {
entry.set_service_worker_client_id(client_id);
}
self.set_frame_owner_child_service_worker_client_id(handle, Some(client_id));
client_id
}
}
OwnerDispatchScope::LightweightPopup(popup_id) => {
if let Some(client_id) = self.service_worker_popup_clients.get(&popup_id).copied() {
client_id
} else {
let client_id = self
.browser_context_runtime
.allocate_service_worker_client_id();
self.service_worker_popup_clients
.insert(popup_id, client_id);
client_id
}
}
};
let frame_type = match dispatch_scope {
OwnerDispatchScope::Child(_) => ServiceWorkerClientFrameType::Nested,
OwnerDispatchScope::Top | OwnerDispatchScope::LightweightPopup(_) => {
ServiceWorkerClientFrameType::TopLevel
}
};
let document_owner = Some(request_context.owner().window_document_owner());
self.browser_context_runtime
.register_allocated_service_worker_client(
client_id,
request_context.document_url().clone(),
request_context.serialized_storage_key(),
frame_type,
document_owner,
self.service_worker_task_sender(),
);
client_id
}
fn service_worker_window_owner_for_dispatch_scope(
&self,
dispatch_scope: OwnerDispatchScope,
@@ -571,6 +628,7 @@ impl JsContextHost {
register_document_owner: WindowDocumentOwner,
register_completion_tx: crate::page_task_queue::RendererPageServiceWorkerTaskSender,
) {
self.ensure_service_worker_client_for_request_context(request_context);
let creator_secure_context =
moli_url::is_potentially_trustworthy_url(request_context.document_url());
let network_policy = WorkerNetworkPolicy {
@@ -616,6 +674,7 @@ impl JsContextHost {
let requests = self.pending_service_worker_ready_requests();
let mut attached_any = false;
for (request_id, request_context, completion_tx) in requests {
self.ensure_service_worker_client_for_request_context(&request_context);
if self
.browser_context_runtime
.watch_service_worker_ready_registration(
@@ -990,7 +1049,11 @@ impl JsContextHost {
&mut self,
document_url: &Url,
) -> Option<ServiceWorkerClientId> {
if !matches!(document_url.scheme(), "http" | "https") {
if !matches!(document_url.scheme(), "http" | "https")
|| !self
.browser_context_runtime
.ensure_service_worker_runtime_for_navigation()
{
return None;
}
let storage_key = service_worker_first_party_storage_key(document_url);
@@ -1157,6 +1220,13 @@ impl JsContextHost {
self.clear_pending_service_worker_child_client(handle);
return;
}
if !self
.browser_context_runtime
.ensure_service_worker_runtime_for_navigation()
{
self.clear_pending_service_worker_child_client(handle);
return;
}
if !self.child_browsing_contexts.contains_key(&handle) {
return;
}
@@ -1537,10 +1607,11 @@ impl JsContextHost {
}
pub(crate) fn service_worker_registration_for_client(
&self,
&mut self,
request_context: &ServiceWorkerWindowRequestContext,
client_url: &Url,
) -> Option<ServiceWorkerRegistrationSnapshot> {
self.ensure_service_worker_client_for_request_context(request_context);
self.browser_context_runtime
.service_worker_registration_for_client(
client_url,
@@ -1549,9 +1620,10 @@ impl JsContextHost {
}
pub(crate) fn service_worker_registrations(
&self,
&mut self,
request_context: &ServiceWorkerWindowRequestContext,
) -> Vec<ServiceWorkerRegistrationSnapshot> {
self.ensure_service_worker_client_for_request_context(request_context);
self.browser_context_runtime.service_worker_registrations(
request_context.document_url(),
&request_context.serialized_storage_key(),
@@ -174,8 +174,8 @@ struct RendererBrowserContextRuntimeInner {
message_port_registry: crate::message_port_runtime::SharedMessagePortRegistry,
broadcast_channel_registry: crate::broadcast_channel_runtime::SharedBroadcastChannelRegistry,
browser_resource_runtime: crate::network::BrowserResourceRuntimeBinding,
shared_worker_runtime: crate::shared_worker_runtime::SharedWorkerRuntimeService,
service_worker_runtime: crate::service_worker_runtime::ServiceWorkerRuntimeService,
shared_worker_runtime: shared_workers::LazySharedWorkerRuntime,
service_worker_runtime: service_worker_runtime::LazyServiceWorkerRuntime,
storage_partition_identity: RendererStoragePartitionIdentity,
next_web_storage_opaque_context_nonce: AtomicU64,
next_child_document_loader_id: AtomicU64,
@@ -314,12 +314,12 @@ fn terminate_browser_context_resource_producers(inner: &RendererBrowserContextRu
for handle in dedicated_worker_handles.into_values() {
let _ = handle.terminate_for_devtools();
}
inner
.shared_worker_runtime
.terminate_all_for_context_shutdown();
inner
.service_worker_runtime
.terminate_all_for_context_shutdown();
if let Some(shared_worker_runtime) = inner.shared_worker_runtime.get() {
shared_worker_runtime.terminate_all_for_context_shutdown();
}
if let Some(service_worker_runtime) = inner.service_worker_runtime.get() {
service_worker_runtime.terminate_all_for_context_shutdown();
}
}
impl Default for RendererBrowserContextRuntimeOwner {
@@ -379,7 +379,7 @@ impl RendererBrowserContextRuntime {
Self::from_parts(
message_port_registry,
broadcast_channel_registry,
crate::shared_worker_runtime::new_shared_worker_runtime_service(),
None,
service_worker_resource_store,
browser_resource_runtime,
)
@@ -399,7 +399,7 @@ impl RendererBrowserContextRuntime {
let runtime = Self::from_parts(
message_port_registry,
broadcast_channel_registry,
crate::shared_worker_runtime::new_shared_worker_runtime_service(),
None,
crate::new_shared_service_worker_resource_store(),
browser_resource_runtime,
);
@@ -425,7 +425,7 @@ impl RendererBrowserContextRuntime {
let runtime = Self::from_parts(
message_port_registry,
broadcast_channel_registry,
shared_worker_runtime,
Some(shared_worker_runtime),
crate::new_shared_service_worker_resource_store(),
browser_resource_runtime,
);
@@ -449,7 +449,7 @@ impl RendererBrowserContextRuntime {
crate::network::BrowserResourceRuntimeOwnerRoot::new(browser_resource_runtime_owner);
let runtime = Self::from_parts_with_worker_context_runtime(
restored_worker_context_runtime,
crate::shared_worker_runtime::new_shared_worker_runtime_service(),
None,
service_worker_resource_store,
browser_resource_runtime,
);
@@ -463,7 +463,7 @@ impl RendererBrowserContextRuntime {
fn from_parts(
message_port_registry: crate::message_port_runtime::SharedMessagePortRegistry,
broadcast_channel_registry: crate::broadcast_channel_runtime::SharedBroadcastChannelRegistry,
shared_worker_runtime: crate::shared_worker_runtime::SharedWorkerRuntimeService,
shared_worker_runtime: Option<crate::shared_worker_runtime::SharedWorkerRuntimeService>,
service_worker_resource_store: crate::SharedServiceWorkerResourceStore,
browser_resource_runtime: crate::network::BrowserResourceRuntimeBinding,
) -> Self {
@@ -483,7 +483,7 @@ impl RendererBrowserContextRuntime {
fn from_parts_with_worker_context_runtime(
service_worker_context_runtime: RendererWorkerContextRuntime,
shared_worker_runtime: crate::shared_worker_runtime::SharedWorkerRuntimeService,
shared_worker_runtime: Option<crate::shared_worker_runtime::SharedWorkerRuntimeService>,
service_worker_resource_store: crate::SharedServiceWorkerResourceStore,
browser_resource_runtime: crate::network::BrowserResourceRuntimeBinding,
) -> Self {
@@ -496,17 +496,24 @@ impl RendererBrowserContextRuntime {
NEXT_RENDERER_BROWSER_CONTEXT_RUNTIME_ID.fetch_add(1, Ordering::Relaxed),
);
let renderer_output_transport_tx = RendererOutputTransportSenderSlot::default();
shared_worker_runtime
.configure_target_output_streams(id, renderer_output_transport_tx.clone());
let service_worker_runtime =
crate::service_worker_runtime::
new_service_worker_runtime_service_with_resource_store_and_browser_resource_runtime_binding(
service_worker_resource_store,
service_worker_context_runtime,
browser_resource_runtime.clone(),
id,
renderer_output_transport_tx.clone(),
);
let shared_worker_runtime = match shared_worker_runtime {
Some(service) => shared_workers::LazySharedWorkerRuntime::from_service(
service,
id,
renderer_output_transport_tx.clone(),
),
None => shared_workers::LazySharedWorkerRuntime::new(
id,
renderer_output_transport_tx.clone(),
),
};
let service_worker_runtime = service_worker_runtime::LazyServiceWorkerRuntime::new(
service_worker_resource_store,
service_worker_context_runtime,
browser_resource_runtime.clone(),
id,
renderer_output_transport_tx.clone(),
);
Self {
inner: Arc::new(RendererBrowserContextRuntimeInner {
id,
@@ -551,12 +558,12 @@ impl RendererBrowserContextRuntime {
sender: super::RendererOutputTransportSender,
) {
self.inner.renderer_output_transport_tx.set(sender.clone());
self.inner
.shared_worker_runtime
.bind_target_output_transport(sender.clone());
self.inner
.service_worker_runtime
.bind_target_output_transport(sender);
if let Some(shared_worker_runtime) = self.inner.shared_worker_runtime.get() {
shared_worker_runtime.bind_target_output_transport(sender.clone());
}
if let Some(service_worker_runtime) = self.inner.service_worker_runtime.get() {
service_worker_runtime.bind_target_output_transport(sender);
}
}
pub(crate) fn renderer_output_transport_sender(
@@ -570,15 +577,42 @@ impl RendererBrowserContextRuntime {
}
pub fn moli_memory_diagnostics(&self) -> Value {
let service_worker_diagnostics = self.inner.service_worker_runtime.diagnostics_snapshot();
let shared_worker_runtime_initialized = self.inner.shared_worker_runtime.is_initialized();
let mut shared_worker_diagnostics = self.inner.shared_worker_runtime.get().map_or_else(
|| {
json!({
"matchingEntryCount": 0,
"loadingInstanceCount": 0,
"runningInstanceCount": 0,
"clientCount": 0,
"loadingHostCount": 0,
"runningWorkerIsolateCount": 0,
"pendingServiceLaneEventCount": 0,
})
},
|runtime| runtime.moli_memory_diagnostics(),
);
shared_worker_diagnostics["runtimeInitialized"] = shared_worker_runtime_initialized.into();
let service_worker_runtime_initialized = self.inner.service_worker_runtime.is_initialized();
let deferred_service_worker_window_client_count = self
.inner
.service_worker_runtime
.deferred_window_client_count();
let service_worker_diagnostics = self
.inner
.service_worker_runtime
.get()
.map_or_else(Default::default, |runtime| runtime.diagnostics_snapshot());
json!({
"rendererOutputTransport": self
.inner
.renderer_output_transport_tx
.sender()
.map(|sender| sender.diagnostics()),
"sharedWorker": self.inner.shared_worker_runtime.moli_memory_diagnostics(),
"sharedWorker": shared_worker_diagnostics,
"serviceWorker": {
"runtimeInitialized": service_worker_runtime_initialized,
"deferredWindowClients": deferred_service_worker_window_client_count,
"registrations": service_worker_diagnostics.registration_count,
"runtimeRegistrations": service_worker_diagnostics.registration_count,
"versions": service_worker_diagnostics.version_count,
@@ -607,7 +641,12 @@ impl RendererBrowserContextRuntime {
pub fn shared_worker_runtime_diagnostics_for_diagnostics(
&self,
) -> RendererSharedWorkerRuntimeDiagnostics {
self.inner.shared_worker_runtime.diagnostics_snapshot()
self.inner
.shared_worker_runtime
.get()
.map_or_else(RendererSharedWorkerRuntimeDiagnostics::default, |runtime| {
runtime.diagnostics_snapshot()
})
}
pub(crate) fn message_port_registry(
@@ -633,7 +672,20 @@ impl RendererBrowserContextRuntime {
pub(crate) fn service_worker_runtime(
&self,
) -> crate::service_worker_runtime::ServiceWorkerRuntimeService {
self.inner.service_worker_runtime.clone()
self.inner.service_worker_runtime.get_or_init()
}
pub(crate) fn service_worker_runtime_if_initialized(
&self,
) -> Option<crate::service_worker_runtime::ServiceWorkerRuntimeService> {
self.inner.service_worker_runtime.get()
}
pub(crate) fn ensure_service_worker_runtime_for_navigation(&self) -> bool {
self.inner
.service_worker_runtime
.get_or_init_for_navigation()
.is_some()
}
pub(crate) fn next_web_storage_opaque_context_nonce(
@@ -927,6 +979,76 @@ mod tests {
assert!(runtime.shares_state_with(&clone));
}
#[test]
fn worker_services_stay_deferred_until_first_use() {
let runtime = RendererBrowserContextRuntime::new();
assert_eq!(
runtime.moli_memory_diagnostics()["sharedWorker"]["runtimeInitialized"],
false
);
assert_eq!(
runtime.moli_memory_diagnostics()["serviceWorker"]["runtimeInitialized"],
false
);
let _ = runtime.next_shared_worker_client_owner_id();
let document_url = url::Url::parse("https://deferred-client.test/").unwrap();
let client_queue = crate::page_task_queue::RendererPageServiceWorkerTestHarness::new();
runtime.register_service_worker_client(
document_url.clone(),
moli_storage_key::MoliStorageKey::first_party_from_url(&document_url, None)
.serialized_storage_key(),
crate::service_worker_runtime::ServiceWorkerClientFrameType::TopLevel,
Some(crate::native_bridge::WindowDocumentOwner::for_test(1)),
client_queue.sender(),
);
let (shared_wake_tx, _shared_wake_rx) =
crate::shared_worker_runtime::shared_worker_owner_wake_channel();
runtime.add_shared_worker_owner_wake_sender(shared_wake_tx);
let (service_wake_tx, _service_wake_rx) =
crate::service_worker_runtime::service_worker_owner_wake_channel();
runtime.add_service_worker_owner_wake_sender(service_wake_tx);
runtime.set_service_worker_pause_on_start_for_devtools(true);
assert!(!runtime.ensure_service_worker_runtime_for_navigation());
assert_eq!(
runtime.moli_memory_diagnostics()["sharedWorker"]["runtimeInitialized"],
false
);
assert_eq!(
runtime.moli_memory_diagnostics()["serviceWorker"]["runtimeInitialized"],
false
);
assert_eq!(
runtime.moli_memory_diagnostics()["serviceWorker"]["deferredWindowClients"],
1
);
runtime.inner.shared_worker_runtime.get_or_init();
runtime.service_worker_runtime();
assert_eq!(
runtime.moli_memory_diagnostics()["sharedWorker"]["runtimeInitialized"],
true
);
assert_eq!(
runtime.moli_memory_diagnostics()["serviceWorker"]["runtimeInitialized"],
true
);
assert_eq!(
runtime.moli_memory_diagnostics()["serviceWorker"]["deferredWindowClients"],
0
);
assert_eq!(
runtime
.service_worker_runtime()
.diagnostics_snapshot()
.live_client_count,
1
);
assert!(runtime.service_worker_pause_on_start_for_devtools());
}
#[test]
fn cloned_runtime_shares_child_document_loader_id_sequence() {
let runtime = RendererBrowserContextRuntime::new();
@@ -1,13 +1,365 @@
use std::collections::{HashMap, hash_map::Entry};
use parking_lot::Mutex;
use url::Url;
use crate::{
page_task_queue::RendererPageServiceWorkerTaskSender,
runtime::{RendererRuntimeInspectorMessage, RendererRuntimeInspectorResponseSender},
service_worker_runtime::{
ServiceWorkerRegistrationId, ServiceWorkerRuntimeOwnerWakeSender, ServiceWorkerVersionId,
ServiceWorkerClientFrameType, ServiceWorkerClientId, ServiceWorkerRegistrationId,
ServiceWorkerRuntimeOwnerWakeSender, ServiceWorkerVersionId,
},
window_document_identity::WindowDocumentOwner,
};
use super::RendererBrowserContextRuntime;
/// Keeps the full Service Worker registry dormant while retaining the small
/// amount of browser-context state that must exist before first use.
pub(super) struct LazyServiceWorkerRuntime {
state: Mutex<LazyServiceWorkerRuntimeState>,
resource_store: crate::SharedServiceWorkerResourceStore,
restored_worker_context_runtime: super::RendererWorkerContextRuntime,
browser_resource_runtime: crate::network::BrowserResourceRuntimeBinding,
client_id_allocator: crate::service_worker_runtime::ServiceWorkerClientIdAllocator,
browser_context_runtime_id: crate::runtime::RendererBrowserContextRuntimeId,
output_transport: crate::runtime::RendererOutputTransportSenderSlot,
}
enum LazyServiceWorkerRuntimeState {
Deferred {
owner_wake_senders: Vec<ServiceWorkerRuntimeOwnerWakeSender>,
window_clients: HashMap<ServiceWorkerClientId, DeferredServiceWorkerWindowClient>,
force_update_on_page_load: bool,
pause_new_workers_on_start: bool,
related_pause_on_start_policies: Vec<(u64, u64, String, String)>,
},
Live(crate::service_worker_runtime::ServiceWorkerRuntimeService),
}
struct DeferredServiceWorkerWindowClient {
document_url: Url,
storage_key: String,
frame_type: ServiceWorkerClientFrameType,
document_owner: Option<WindowDocumentOwner>,
completion_tx: RendererPageServiceWorkerTaskSender,
}
impl std::fmt::Debug for LazyServiceWorkerRuntime {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LazyServiceWorkerRuntime")
.field("initialized", &self.is_initialized())
.finish()
}
}
impl LazyServiceWorkerRuntime {
pub(super) fn new(
resource_store: crate::SharedServiceWorkerResourceStore,
restored_worker_context_runtime: super::RendererWorkerContextRuntime,
browser_resource_runtime: crate::network::BrowserResourceRuntimeBinding,
browser_context_runtime_id: crate::runtime::RendererBrowserContextRuntimeId,
output_transport: crate::runtime::RendererOutputTransportSenderSlot,
) -> Self {
Self {
state: Mutex::new(LazyServiceWorkerRuntimeState::Deferred {
owner_wake_senders: Vec::new(),
window_clients: HashMap::new(),
force_update_on_page_load: false,
pause_new_workers_on_start: false,
related_pause_on_start_policies: Vec::new(),
}),
resource_store,
restored_worker_context_runtime,
browser_resource_runtime,
client_id_allocator: Default::default(),
browser_context_runtime_id,
output_transport,
}
}
pub(super) fn get_or_init(&self) -> crate::service_worker_runtime::ServiceWorkerRuntimeService {
let mut state = self.state.lock();
if let LazyServiceWorkerRuntimeState::Live(service) = &*state {
return service.clone();
}
let LazyServiceWorkerRuntimeState::Deferred {
owner_wake_senders,
window_clients,
force_update_on_page_load,
pause_new_workers_on_start,
related_pause_on_start_policies,
} = &mut *state
else {
unreachable!();
};
let owner_wake_senders = std::mem::take(owner_wake_senders);
let window_clients = std::mem::take(window_clients);
let force_update_on_page_load = *force_update_on_page_load;
let pause_new_workers_on_start = *pause_new_workers_on_start;
let related_pause_on_start_policies = std::mem::take(related_pause_on_start_policies);
let service = crate::service_worker_runtime::
new_service_worker_runtime_service_with_resource_store_and_browser_resource_runtime_binding(
self.resource_store.clone(),
self.restored_worker_context_runtime.clone(),
self.browser_resource_runtime.clone(),
self.client_id_allocator.clone(),
self.browser_context_runtime_id,
self.output_transport.clone(),
);
for sender in owner_wake_senders {
service.add_owner_wake_sender(sender);
}
service.set_force_update_on_page_load_for_devtools(force_update_on_page_load);
service.set_pause_new_workers_on_start_for_devtools(pause_new_workers_on_start);
service.set_related_pause_on_start_policies_for_devtools(related_pause_on_start_policies);
for (client_id, client) in window_clients {
let inserted = service.register_allocated_client_with_storage_key(
client_id,
client.document_url,
client.storage_key,
client.frame_type,
client.document_owner,
client.completion_tx,
);
debug_assert!(inserted, "deferred Service Worker client id must be unique");
}
*state = LazyServiceWorkerRuntimeState::Live(service.clone());
service
}
pub(super) fn get(&self) -> Option<crate::service_worker_runtime::ServiceWorkerRuntimeService> {
let state = self.state.lock();
let LazyServiceWorkerRuntimeState::Live(service) = &*state else {
return None;
};
Some(service.clone())
}
/// Returns a live runtime when one already exists or persisted
/// registrations may control the navigation. An empty store stays lazy.
pub(super) fn get_or_init_for_navigation(
&self,
) -> Option<crate::service_worker_runtime::ServiceWorkerRuntimeService> {
if let Some(service) = self.get() {
return Some(service);
}
if self.resource_store.lock().is_empty() {
return None;
}
Some(self.get_or_init())
}
pub(super) fn is_initialized(&self) -> bool {
matches!(*self.state.lock(), LazyServiceWorkerRuntimeState::Live(_))
}
pub(super) fn allocate_client_id(
&self,
) -> crate::service_worker_runtime::ServiceWorkerClientId {
self.client_id_allocator.allocate()
}
pub(super) fn register_window_client(
&self,
client_id: ServiceWorkerClientId,
document_url: Url,
storage_key: String,
frame_type: ServiceWorkerClientFrameType,
document_owner: Option<WindowDocumentOwner>,
completion_tx: RendererPageServiceWorkerTaskSender,
) -> bool {
let service = {
let mut state = self.state.lock();
match &mut *state {
LazyServiceWorkerRuntimeState::Deferred { window_clients, .. } => {
let client = DeferredServiceWorkerWindowClient {
document_url,
storage_key,
frame_type,
document_owner,
completion_tx,
};
return match window_clients.entry(client_id) {
Entry::Vacant(entry) => {
entry.insert(client);
true
}
Entry::Occupied(_) => false,
};
}
LazyServiceWorkerRuntimeState::Live(service) => service.clone(),
}
};
service.register_allocated_client_with_storage_key(
client_id,
document_url,
storage_key,
frame_type,
document_owner,
completion_tx,
)
}
pub(super) fn update_window_client(
&self,
client_id: ServiceWorkerClientId,
document_url: Url,
storage_key: String,
frame_type: ServiceWorkerClientFrameType,
document_owner: Option<WindowDocumentOwner>,
completion_tx: Option<RendererPageServiceWorkerTaskSender>,
) -> bool {
let service = {
let mut state = self.state.lock();
match &mut *state {
LazyServiceWorkerRuntimeState::Deferred { window_clients, .. } => {
let Some(client) = window_clients.get_mut(&client_id) else {
return false;
};
client.document_url = document_url;
client.storage_key = storage_key;
client.frame_type = frame_type;
client.document_owner = document_owner;
if let Some(completion_tx) = completion_tx {
client.completion_tx = completion_tx;
}
return true;
}
LazyServiceWorkerRuntimeState::Live(service) => service.clone(),
}
};
if let Some(completion_tx) = completion_tx {
service.update_client_document_with_storage_key_and_completion_sender(
client_id,
document_url,
storage_key,
frame_type,
document_owner,
completion_tx,
)
} else {
service.update_client_document_with_storage_key(
client_id,
document_url,
storage_key,
frame_type,
document_owner,
)
}
}
pub(super) fn unregister_client(&self, client_id: ServiceWorkerClientId) {
let service = {
let mut state = self.state.lock();
match &mut *state {
LazyServiceWorkerRuntimeState::Deferred { window_clients, .. } => {
window_clients.remove(&client_id);
return;
}
LazyServiceWorkerRuntimeState::Live(service) => service.clone(),
}
};
service.unregister_client(client_id);
}
pub(super) fn deferred_window_client_count(&self) -> usize {
let state = self.state.lock();
match &*state {
LazyServiceWorkerRuntimeState::Deferred { window_clients, .. } => window_clients.len(),
LazyServiceWorkerRuntimeState::Live(_) => 0,
}
}
pub(super) fn add_owner_wake_sender(&self, sender: ServiceWorkerRuntimeOwnerWakeSender) {
let mut state = self.state.lock();
match &mut *state {
LazyServiceWorkerRuntimeState::Deferred {
owner_wake_senders, ..
} => owner_wake_senders.push(sender),
LazyServiceWorkerRuntimeState::Live(service) => service.add_owner_wake_sender(sender),
}
}
pub(super) fn set_force_update_on_page_load(&self, force_update: bool) {
let mut state = self.state.lock();
match &mut *state {
LazyServiceWorkerRuntimeState::Deferred {
force_update_on_page_load,
..
} => *force_update_on_page_load = force_update,
LazyServiceWorkerRuntimeState::Live(service) => {
service.set_force_update_on_page_load_for_devtools(force_update)
}
}
}
pub(super) fn force_update_on_page_load(&self) -> bool {
let state = self.state.lock();
match &*state {
LazyServiceWorkerRuntimeState::Deferred {
force_update_on_page_load,
..
} => *force_update_on_page_load,
LazyServiceWorkerRuntimeState::Live(service) => {
service.force_update_on_page_load_for_devtools()
}
}
}
pub(super) fn set_pause_new_workers_on_start(&self, pause: bool) {
let mut state = self.state.lock();
match &mut *state {
LazyServiceWorkerRuntimeState::Deferred {
pause_new_workers_on_start,
..
} => *pause_new_workers_on_start = pause,
LazyServiceWorkerRuntimeState::Live(service) => {
service.set_pause_new_workers_on_start_for_devtools(pause)
}
}
}
pub(super) fn pause_new_workers_on_start(&self) -> bool {
let state = self.state.lock();
match &*state {
LazyServiceWorkerRuntimeState::Deferred {
pause_new_workers_on_start,
..
} => *pause_new_workers_on_start,
LazyServiceWorkerRuntimeState::Live(service) => {
service.pause_new_workers_on_start_for_devtools()
}
}
}
pub(super) fn set_related_pause_on_start_policies(
&self,
policies: Vec<(u64, u64, String, String)>,
) {
let mut state = self.state.lock();
match &mut *state {
LazyServiceWorkerRuntimeState::Deferred {
related_pause_on_start_policies,
..
} => *related_pause_on_start_policies = policies,
LazyServiceWorkerRuntimeState::Live(service) => {
service.set_related_pause_on_start_policies_for_devtools(policies)
}
}
}
}
impl RendererBrowserContextRuntime {
fn service_worker_runtime_for_existing_registration(
&self,
) -> Option<crate::service_worker_runtime::ServiceWorkerRuntimeService> {
self.inner
.service_worker_runtime
.get_or_init_for_navigation()
}
pub(crate) fn add_service_worker_owner_wake_sender(
&self,
sender: ServiceWorkerRuntimeOwnerWakeSender,
@@ -18,7 +370,10 @@ impl RendererBrowserContextRuntime {
}
pub(crate) fn drain_service_worker_service_lane(&self) -> usize {
self.inner.service_worker_runtime.drain_service_lane()
self.inner
.service_worker_runtime
.get()
.map_or(0, |runtime| runtime.drain_service_lane())
}
pub async fn dispatch_service_worker_runtime_protocol_message(
@@ -27,8 +382,10 @@ impl RendererBrowserContextRuntime {
inspector_session_id: Option<String>,
raw_json: String,
) -> Result<Vec<RendererRuntimeInspectorMessage>, String> {
self.inner
.service_worker_runtime
let Some(runtime) = self.service_worker_runtime_for_existing_registration() else {
return Err("ServiceWorkerRuntimeUnavailable".to_owned());
};
runtime
.dispatch_runtime_protocol_message(
ServiceWorkerVersionId::from_u64_for_binding(version_id),
inspector_session_id,
@@ -44,8 +401,10 @@ impl RendererBrowserContextRuntime {
raw_json: String,
deferred_response: RendererRuntimeInspectorResponseSender,
) -> Result<Vec<RendererRuntimeInspectorMessage>, String> {
self.inner
.service_worker_runtime
let Some(runtime) = self.service_worker_runtime_for_existing_registration() else {
return Err("ServiceWorkerRuntimeUnavailable".to_owned());
};
runtime
.dispatch_runtime_protocol_message_with_deferred_response(
ServiceWorkerVersionId::from_u64_for_binding(version_id),
inspector_session_id,
@@ -60,69 +419,76 @@ impl RendererBrowserContextRuntime {
version_id: u64,
inspector_session_id: Option<String>,
) -> bool {
self.inner
.service_worker_runtime
.detach_runtime_inspector_session(
ServiceWorkerVersionId::from_u64_for_binding(version_id),
inspector_session_id,
)
self.service_worker_runtime_for_existing_registration()
.is_some_and(|runtime| {
runtime.detach_runtime_inspector_session(
ServiceWorkerVersionId::from_u64_for_binding(version_id),
inspector_session_id,
)
})
}
pub fn unregister_service_worker_scope_for_devtools(
&self,
scope_url: &url::Url,
) -> Result<bool, String> {
self.inner
.service_worker_runtime
.devtools_unregister_scope(scope_url)
self.service_worker_runtime_for_existing_registration()
.map_or(Ok(false), |runtime| {
runtime.devtools_unregister_scope(scope_url)
})
}
pub fn start_service_worker_for_devtools(&self, scope_url: &url::Url) -> Result<bool, String> {
self.inner
.service_worker_runtime
.devtools_start_worker_for_scope(scope_url)
self.service_worker_runtime_for_existing_registration()
.map_or(Ok(false), |runtime| {
runtime.devtools_start_worker_for_scope(scope_url)
})
}
pub fn stop_service_worker_for_devtools(&self, version_id: u64) -> Result<bool, String> {
self.inner
.service_worker_runtime
.devtools_stop_worker_version(ServiceWorkerVersionId::from_u64_for_binding(version_id))
self.service_worker_runtime_for_existing_registration()
.map_or(Ok(false), |runtime| {
runtime.devtools_stop_worker_version(ServiceWorkerVersionId::from_u64_for_binding(
version_id,
))
})
}
pub fn stop_all_service_workers_for_devtools(&self) -> Result<usize, String> {
self.inner
.service_worker_runtime
.devtools_stop_all_workers()
self.service_worker_runtime_for_existing_registration()
.map_or(Ok(0), |runtime| runtime.devtools_stop_all_workers())
}
pub fn skip_waiting_service_worker_for_devtools(
&self,
scope_url: &url::Url,
) -> Result<bool, String> {
self.inner
.service_worker_runtime
.devtools_skip_waiting_for_scope(scope_url)
self.service_worker_runtime_for_existing_registration()
.map_or(Ok(false), |runtime| {
runtime.devtools_skip_waiting_for_scope(scope_url)
})
}
pub fn update_service_worker_registration_for_devtools(
&self,
scope_url: &url::Url,
) -> Result<bool, String> {
self.inner
.service_worker_runtime
.devtools_update_registration_for_scope(scope_url, self.clone())
self.service_worker_runtime_for_existing_registration()
.map_or(Ok(false), |runtime| {
runtime.devtools_update_registration_for_scope(scope_url, self.clone())
})
}
pub fn set_service_worker_force_update_on_page_load_for_devtools(&self, force_update: bool) {
self.inner
.service_worker_runtime
.set_force_update_on_page_load_for_devtools(force_update);
.set_force_update_on_page_load(force_update);
}
pub fn service_worker_force_update_on_page_load_for_devtools(&self) -> bool {
self.inner
.service_worker_runtime
.force_update_on_page_load_for_devtools()
.force_update_on_page_load()
}
pub fn controlled_service_worker_window_client_urls_for_devtools(
@@ -130,12 +496,13 @@ impl RendererBrowserContextRuntime {
registration_id: u64,
version_id: u64,
) -> Vec<String> {
self.inner
.service_worker_runtime
.controlled_window_client_urls_for_version_for_devtools(
ServiceWorkerRegistrationId::from_u64_for_binding(registration_id),
ServiceWorkerVersionId::from_u64_for_binding(version_id),
)
self.service_worker_runtime_for_existing_registration()
.map_or_else(Vec::new, |runtime| {
runtime.controlled_window_client_urls_for_version_for_devtools(
ServiceWorkerRegistrationId::from_u64_for_binding(registration_id),
ServiceWorkerVersionId::from_u64_for_binding(version_id),
)
})
}
pub fn controlled_service_worker_window_client_ids_for_devtools(
@@ -143,18 +510,19 @@ impl RendererBrowserContextRuntime {
registration_id: u64,
version_id: u64,
) -> Vec<u64> {
self.inner
.service_worker_runtime
.controlled_window_client_ids_for_version_for_devtools(
ServiceWorkerRegistrationId::from_u64_for_binding(registration_id),
ServiceWorkerVersionId::from_u64_for_binding(version_id),
)
self.service_worker_runtime_for_existing_registration()
.map_or_else(Vec::new, |runtime| {
runtime.controlled_window_client_ids_for_version_for_devtools(
ServiceWorkerRegistrationId::from_u64_for_binding(registration_id),
ServiceWorkerVersionId::from_u64_for_binding(version_id),
)
})
}
pub fn set_service_worker_pause_on_start_for_devtools(&self, pause: bool) {
self.inner
.service_worker_runtime
.set_pause_new_workers_on_start_for_devtools(pause);
.set_pause_new_workers_on_start(pause);
}
pub fn set_service_worker_related_pause_on_start_policies_for_devtools(
@@ -163,7 +531,7 @@ impl RendererBrowserContextRuntime {
) {
self.inner
.service_worker_runtime
.set_related_pause_on_start_policies_for_devtools(policies);
.set_related_pause_on_start_policies(policies);
}
pub fn set_service_worker_pause_on_start_for_version_for_devtools(
@@ -171,41 +539,44 @@ impl RendererBrowserContextRuntime {
version_id: u64,
pause: bool,
) -> bool {
self.inner
.service_worker_runtime
.set_pause_on_start_for_version_for_devtools(
ServiceWorkerVersionId::from_u64_for_binding(version_id),
pause,
)
self.service_worker_runtime_for_existing_registration()
.is_some_and(|runtime| {
runtime.set_pause_on_start_for_version_for_devtools(
ServiceWorkerVersionId::from_u64_for_binding(version_id),
pause,
)
})
}
pub fn service_worker_pause_on_start_for_devtools(&self) -> bool {
self.inner
.service_worker_runtime
.pause_new_workers_on_start_for_devtools()
.pause_new_workers_on_start()
}
pub fn set_service_worker_devtools_attached(&self, version_id: u64, attached: bool) {
self.inner
.service_worker_runtime
.set_devtools_attached_for_version(
if let Some(runtime) = self.service_worker_runtime_for_existing_registration() {
runtime.set_devtools_attached_for_version(
ServiceWorkerVersionId::from_u64_for_binding(version_id),
attached,
);
}
}
pub fn run_service_worker_if_waiting_for_debugger_for_devtools(&self, version_id: u64) -> bool {
self.inner
.service_worker_runtime
.devtools_run_if_waiting_for_debugger(ServiceWorkerVersionId::from_u64_for_binding(
version_id,
))
self.service_worker_runtime_for_existing_registration()
.is_some_and(|runtime| {
runtime.devtools_run_if_waiting_for_debugger(
ServiceWorkerVersionId::from_u64_for_binding(version_id),
)
})
}
pub fn release_all_service_workers_waiting_for_debugger_for_devtools(&self) -> usize {
self.inner
.service_worker_runtime
.devtools_release_all_workers_waiting_for_debugger()
self.service_worker_runtime_for_existing_registration()
.map_or(0, |runtime| {
runtime.devtools_release_all_workers_waiting_for_debugger()
})
}
pub fn deliver_push_message_for_devtools(
@@ -214,13 +585,14 @@ impl RendererBrowserContextRuntime {
registration_id: u64,
data: Option<Vec<u8>>,
) -> Result<bool, String> {
self.inner
.service_worker_runtime
.devtools_deliver_push_message(
origin,
ServiceWorkerRegistrationId::from_u64_for_binding(registration_id),
data,
)
self.service_worker_runtime_for_existing_registration()
.map_or(Ok(false), |runtime| {
runtime.devtools_deliver_push_message(
origin,
ServiceWorkerRegistrationId::from_u64_for_binding(registration_id),
data,
)
})
}
pub fn dispatch_sync_event_for_devtools(
@@ -230,14 +602,15 @@ impl RendererBrowserContextRuntime {
tag: String,
last_chance: bool,
) -> Result<bool, String> {
self.inner
.service_worker_runtime
.devtools_dispatch_sync_event(
origin,
ServiceWorkerRegistrationId::from_u64_for_binding(registration_id),
tag,
last_chance,
)
self.service_worker_runtime_for_existing_registration()
.map_or(Ok(false), |runtime| {
runtime.devtools_dispatch_sync_event(
origin,
ServiceWorkerRegistrationId::from_u64_for_binding(registration_id),
tag,
last_chance,
)
})
}
pub fn dispatch_periodic_sync_event_for_devtools(
@@ -246,12 +619,13 @@ impl RendererBrowserContextRuntime {
registration_id: u64,
tag: String,
) -> Result<bool, String> {
self.inner
.service_worker_runtime
.devtools_dispatch_periodic_sync_event(
origin,
ServiceWorkerRegistrationId::from_u64_for_binding(registration_id),
tag,
)
self.service_worker_runtime_for_existing_registration()
.map_or(Ok(false), |runtime| {
runtime.devtools_dispatch_periodic_sync_event(
origin,
ServiceWorkerRegistrationId::from_u64_for_binding(registration_id),
tag,
)
})
}
}
@@ -78,6 +78,17 @@ impl RendererBrowserContextRuntime {
response: None,
});
}
if self
.inner
.service_worker_runtime
.get_or_init_for_navigation()
.is_none()
{
return Ok(RendererServiceWorkerMainResourceFetch {
reserved_client: None,
response: None,
});
}
let storage_key =
moli_storage_key::MoliStorageKey::first_party_from_url(&request.url, None)
@@ -340,8 +351,7 @@ impl RendererBrowserContextRuntime {
scope_url: &Url,
) -> Option<tokio::sync::oneshot::Receiver<()>> {
let (_, receiver) = self
.inner
.service_worker_runtime
.service_worker_runtime()
.devtools_force_update_registration_for_page_load(scope_url, self.clone());
receiver
}
@@ -354,8 +364,7 @@ impl RendererBrowserContextRuntime {
resource_task_runner: RendererResourceTaskRunner,
destination: ServiceWorkerRequestDestination,
) -> Result<Option<crate::protocol_types::NavigationResponse>> {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.fetch_main_resource_for_worker_client(
client_id,
request,
@@ -376,15 +385,40 @@ impl RendererBrowserContextRuntime {
document_owner: Option<crate::window_document_identity::WindowDocumentOwner>,
completion_tx: crate::page_task_queue::RendererPageServiceWorkerTaskSender,
) -> ServiceWorkerClientId {
self.inner
.service_worker_runtime
.register_client_with_storage_key(
document_url,
storage_key,
frame_type,
document_owner,
completion_tx,
)
let client_id = self.inner.service_worker_runtime.allocate_client_id();
let inserted = self.inner.service_worker_runtime.register_window_client(
client_id,
document_url,
storage_key,
frame_type,
document_owner,
completion_tx,
);
debug_assert!(inserted, "new Service Worker client id must be unused");
client_id
}
pub(crate) fn register_allocated_service_worker_client(
&self,
client_id: ServiceWorkerClientId,
document_url: Url,
storage_key: String,
frame_type: ServiceWorkerClientFrameType,
document_owner: Option<crate::window_document_identity::WindowDocumentOwner>,
completion_tx: crate::page_task_queue::RendererPageServiceWorkerTaskSender,
) -> bool {
self.inner.service_worker_runtime.register_window_client(
client_id,
document_url,
storage_key,
frame_type,
document_owner,
completion_tx,
)
}
pub(crate) fn allocate_service_worker_client_id(&self) -> ServiceWorkerClientId {
self.inner.service_worker_runtime.allocate_client_id()
}
pub(crate) fn register_reserved_service_worker_client(
@@ -394,8 +428,7 @@ impl RendererBrowserContextRuntime {
frame_type: ServiceWorkerClientFrameType,
document_owner: Option<crate::window_document_identity::WindowDocumentOwner>,
) -> ServiceWorkerClientId {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.register_reserved_client_with_storage_key(
document_url,
storage_key,
@@ -411,8 +444,7 @@ impl RendererBrowserContextRuntime {
frame_type: ServiceWorkerClientFrameType,
document_owner: Option<crate::window_document_identity::WindowDocumentOwner>,
) -> ServiceWorkerClientId {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.register_reserved_client_with_storage_key_bypassing_service_worker(
document_url,
storage_key,
@@ -428,8 +460,7 @@ impl RendererBrowserContextRuntime {
client_type: ServiceWorkerClientType,
secure_context: bool,
) -> ServiceWorkerClientId {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.register_reserved_worker_client_with_storage_key(
script_url,
storage_key,
@@ -446,8 +477,7 @@ impl RendererBrowserContextRuntime {
secure_context: bool,
parent_client_id: ServiceWorkerClientId,
) -> Option<ServiceWorkerClientId> {
self.inner
.service_worker_runtime
self.service_worker_runtime_if_initialized()?
.register_reserved_worker_client_inheriting_controller_from_client(
script_url,
storage_key,
@@ -471,15 +501,14 @@ impl RendererBrowserContextRuntime {
frame_type: ServiceWorkerClientFrameType,
document_owner: Option<crate::window_document_identity::WindowDocumentOwner>,
) -> bool {
self.inner
.service_worker_runtime
.update_client_document_with_storage_key(
client_id,
document_url,
storage_key,
frame_type,
document_owner,
)
self.inner.service_worker_runtime.update_window_client(
client_id,
document_url,
storage_key,
frame_type,
document_owner,
None,
)
}
pub(crate) fn update_service_worker_client_document_and_page_endpoint(
@@ -491,16 +520,14 @@ impl RendererBrowserContextRuntime {
document_owner: Option<crate::window_document_identity::WindowDocumentOwner>,
completion_tx: crate::page_task_queue::RendererPageServiceWorkerTaskSender,
) -> bool {
self.inner
.service_worker_runtime
.update_client_document_with_storage_key_and_completion_sender(
client_id,
document_url,
storage_key,
frame_type,
document_owner,
completion_tx,
)
self.inner.service_worker_runtime.update_window_client(
client_id,
document_url,
storage_key,
frame_type,
document_owner,
Some(completion_tx),
)
}
pub(crate) fn unregister_service_worker_scope(
@@ -511,8 +538,7 @@ impl RendererBrowserContextRuntime {
document_owner: crate::window_document_identity::WindowDocumentOwner,
completion_tx: crate::page_task_queue::RendererPageServiceWorkerTaskSender,
) -> ServiceWorkerUnregisterStart {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.start_unregistration_with_storage_key(
scope_url,
storage_key,
@@ -527,8 +553,7 @@ impl RendererBrowserContextRuntime {
client_url: &Url,
storage_key: &str,
) -> Option<ServiceWorkerRegistrationSnapshot> {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.matching_registration_for_client_with_storage_key(client_url, storage_key)
}
@@ -537,8 +562,7 @@ impl RendererBrowserContextRuntime {
document_url: &Url,
storage_key: &str,
) -> Vec<ServiceWorkerRegistrationSnapshot> {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.all_registrations_with_storage_key(document_url, storage_key)
}
@@ -546,8 +570,7 @@ impl RendererBrowserContextRuntime {
&self,
scope_url: &Url,
) -> Option<ServiceWorkerNavigationPreloadState> {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.navigation_preload_state_for_scope(scope_url)
}
@@ -556,8 +579,7 @@ impl RendererBrowserContextRuntime {
scope_url: &Url,
enabled: bool,
) -> Result<(), ServiceWorkerNavigationPreloadStateError> {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.set_navigation_preload_enabled_for_scope(scope_url, enabled)
}
@@ -566,8 +588,7 @@ impl RendererBrowserContextRuntime {
scope_url: &Url,
header_value: String,
) -> Result<(), ServiceWorkerNavigationPreloadStateError> {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.set_navigation_preload_header_value_for_scope(scope_url, header_value)
}
@@ -579,8 +600,7 @@ impl RendererBrowserContextRuntime {
document_owner: crate::window_document_identity::WindowDocumentOwner,
completion_tx: crate::page_task_queue::RendererPageServiceWorkerTaskSender,
) -> bool {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.watch_ready_registration_with_storage_key(
document_url,
storage_key,
@@ -597,18 +617,20 @@ impl RendererBrowserContextRuntime {
document_owner: crate::window_document_identity::WindowDocumentOwner,
completion_tx: crate::page_task_queue::RendererPageServiceWorkerTaskSender,
) {
self.inner
.service_worker_runtime
.watch_registration_lifecycle(scope_url, storage_key, document_owner, completion_tx)
self.service_worker_runtime().watch_registration_lifecycle(
scope_url,
storage_key,
document_owner,
completion_tx,
)
}
pub(crate) fn service_worker_controller_for_client(
&self,
client_id: ServiceWorkerClientId,
) -> Option<ServiceWorkerControlState> {
self.inner
.service_worker_runtime
.matching_controller_for_client(client_id)
self.service_worker_runtime_if_initialized()
.and_then(|runtime| runtime.matching_controller_for_client(client_id))
}
pub(crate) fn service_worker_controller_for_fetch(
@@ -616,24 +638,23 @@ impl RendererBrowserContextRuntime {
client_id: ServiceWorkerClientId,
request_url: &Url,
) -> Option<ServiceWorkerControlState> {
self.inner
.service_worker_runtime
.matching_controller_for_client_fetch(client_id, request_url)
self.service_worker_runtime_if_initialized()
.and_then(|runtime| {
runtime.matching_controller_for_client_fetch(client_id, request_url)
})
}
pub(crate) fn dispatch_service_worker_fetch(
&self,
dispatch: ServiceWorkerFetchDispatch,
) -> bool {
self.inner
.service_worker_runtime
.dispatch_controlled_fetch(dispatch)
self.service_worker_runtime_if_initialized()
.is_some_and(|runtime| runtime.dispatch_controlled_fetch(dispatch))
}
pub(crate) fn abort_service_worker_fetch(&self, internal_id: u64) -> bool {
self.inner
.service_worker_runtime
.abort_controlled_fetch(internal_id)
self.service_worker_runtime_if_initialized()
.is_some_and(|runtime| runtime.abort_controlled_fetch(internal_id))
}
pub(crate) fn abort_service_worker_fetch_with_reason(
@@ -641,9 +662,8 @@ impl RendererBrowserContextRuntime {
internal_id: u64,
reason: Option<V8StructuredClonePayload>,
) -> bool {
self.inner
.service_worker_runtime
.abort_controlled_fetch_with_reason(internal_id, reason)
self.service_worker_runtime_if_initialized()
.is_some_and(|runtime| runtime.abort_controlled_fetch_with_reason(internal_id, reason))
}
pub(crate) fn dispatch_service_worker_message(
@@ -653,9 +673,15 @@ impl RendererBrowserContextRuntime {
source_origin: Option<String>,
payload: V8StructuredClonePayload,
) -> bool {
self.inner
.service_worker_runtime
.dispatch_message_to_version(version_id, source_client_id, source_origin, payload)
self.service_worker_runtime_if_initialized()
.is_some_and(|runtime| {
runtime.dispatch_message_to_version(
version_id,
source_client_id,
source_origin,
payload,
)
})
}
pub fn dispatch_service_worker_notification_click(
@@ -664,8 +690,7 @@ impl RendererBrowserContextRuntime {
title: impl Into<String>,
action: impl Into<String>,
) -> bool {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.dispatch_notification_click_for_scope(scope_url, title.into(), action.into())
}
@@ -674,33 +699,27 @@ impl RendererBrowserContextRuntime {
scope_url: &Url,
title: impl Into<String>,
) -> bool {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.dispatch_notification_close_for_scope(scope_url, title.into())
}
pub fn dispatch_service_worker_push(&self, scope_url: &Url, data: Option<Vec<u8>>) -> bool {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.dispatch_push_for_scope(scope_url, data)
}
pub fn dispatch_service_worker_periodic_sync(&self, scope_url: &Url, tag: &str) -> bool {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.dispatch_periodic_sync_for_scope(scope_url, tag)
}
pub(crate) fn register_service_worker_sync(&self, scope_url: &Url, tag: String) -> bool {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.register_sync_for_scope(scope_url, tag)
}
pub(crate) fn service_worker_sync_tags(&self, scope_url: &Url) -> Vec<String> {
self.inner
.service_worker_runtime
.sync_tags_for_scope(scope_url)
self.service_worker_runtime().sync_tags_for_scope(scope_url)
}
pub(crate) fn register_service_worker_periodic_sync(
@@ -709,14 +728,12 @@ impl RendererBrowserContextRuntime {
tag: String,
min_interval_ms: u64,
) -> bool {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.register_periodic_sync_for_scope(scope_url, tag, min_interval_ms)
}
pub(crate) fn service_worker_periodic_sync_tags(&self, scope_url: &Url) -> Vec<String> {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.periodic_sync_tags_for_scope(scope_url)
}
@@ -725,8 +742,7 @@ impl RendererBrowserContextRuntime {
scope_url: &Url,
tag: &str,
) -> bool {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.unregister_periodic_sync_for_scope(scope_url, tag)
}
@@ -735,8 +751,7 @@ impl RendererBrowserContextRuntime {
scope_url: &Url,
user_visible_only: bool,
) -> Option<ServiceWorkerPushSubscriptionSnapshot> {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.subscribe_push_for_scope(scope_url, user_visible_only)
}
@@ -744,14 +759,12 @@ impl RendererBrowserContextRuntime {
&self,
scope_url: &Url,
) -> Option<ServiceWorkerPushSubscriptionSnapshot> {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.push_subscription_for_scope(scope_url)
}
pub(crate) fn unsubscribe_service_worker_push(&self, scope_url: &Url) -> bool {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.unsubscribe_push_for_scope(scope_url)
}
@@ -764,16 +777,14 @@ impl RendererBrowserContextRuntime {
actions: Vec<ServiceWorkerNotificationAction>,
data: V8StructuredClonePayload,
) -> bool {
self.inner
.service_worker_runtime
.show_notification_for_scope(
scope_url,
title.into(),
tag.into(),
metadata,
actions,
data,
)
self.service_worker_runtime().show_notification_for_scope(
scope_url,
title.into(),
tag.into(),
metadata,
actions,
data,
)
}
pub(crate) fn service_worker_notifications(
@@ -781,8 +792,7 @@ impl RendererBrowserContextRuntime {
scope_url: &Url,
tag: Option<&str>,
) -> Vec<crate::runtime::ServiceWorkerNotificationSnapshot> {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.notifications_for_scope(scope_url, tag)
}
@@ -791,15 +801,13 @@ impl RendererBrowserContextRuntime {
registration_id: crate::runtime::ServiceWorkerRegistrationId,
notification_id: u64,
) -> bool {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.close_notification(registration_id, notification_id)
}
#[cfg(test)]
pub(crate) fn stop_service_worker_hosts_for_test(&self) {
self.inner
.service_worker_runtime
self.service_worker_runtime()
.stop_all_running_hosts_for_test();
}
}
@@ -6,6 +6,7 @@ use crate::{
use moli_shared_worker::{
SharedWorkerClientId, SharedWorkerClientOwnerId, SharedWorkerDescriptor, SharedWorkerInstanceId,
};
use parking_lot::Mutex;
use super::RendererBrowserContextRuntime;
use crate::runtime::{
@@ -13,7 +14,142 @@ use crate::runtime::{
RendererRuntimeInspectorResponseSender,
};
/// Defers the browser-context SharedWorker registry until the first actual
/// `connect_shared_worker` call. ID allocation and owner routing do not require
/// the registry.
pub(super) struct LazySharedWorkerRuntime {
state: Mutex<LazySharedWorkerRuntimeState>,
client_owner_id_allocator: crate::shared_worker_runtime::SharedWorkerClientOwnerIdAllocator,
browser_context_runtime_id: crate::runtime::RendererBrowserContextRuntimeId,
output_transport: crate::runtime::RendererOutputTransportSenderSlot,
}
enum LazySharedWorkerRuntimeState {
Deferred {
owner_wake_senders: Vec<SharedWorkerRuntimeOwnerWakeSender>,
owner_local_host_id: Option<RendererOwnerLocalHostId>,
},
Live(crate::shared_worker_runtime::SharedWorkerRuntimeService),
}
impl std::fmt::Debug for LazySharedWorkerRuntime {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LazySharedWorkerRuntime")
.field("initialized", &self.is_initialized())
.finish()
}
}
impl LazySharedWorkerRuntime {
pub(super) fn new(
browser_context_runtime_id: crate::runtime::RendererBrowserContextRuntimeId,
output_transport: crate::runtime::RendererOutputTransportSenderSlot,
) -> Self {
Self {
state: Mutex::new(LazySharedWorkerRuntimeState::Deferred {
owner_wake_senders: Vec::new(),
owner_local_host_id: None,
}),
client_owner_id_allocator: Default::default(),
browser_context_runtime_id,
output_transport,
}
}
pub(super) fn from_service(
service: crate::shared_worker_runtime::SharedWorkerRuntimeService,
browser_context_runtime_id: crate::runtime::RendererBrowserContextRuntimeId,
output_transport: crate::runtime::RendererOutputTransportSenderSlot,
) -> Self {
service
.configure_target_output_streams(browser_context_runtime_id, output_transport.clone());
Self {
client_owner_id_allocator: service.client_owner_id_allocator(),
state: Mutex::new(LazySharedWorkerRuntimeState::Live(service)),
browser_context_runtime_id,
output_transport,
}
}
pub(super) fn get_or_init(&self) -> crate::shared_worker_runtime::SharedWorkerRuntimeService {
let mut state = self.state.lock();
if let LazySharedWorkerRuntimeState::Live(service) = &*state {
return service.clone();
}
let LazySharedWorkerRuntimeState::Deferred {
owner_wake_senders,
owner_local_host_id,
} = &mut *state
else {
unreachable!();
};
let owner_wake_senders = std::mem::take(owner_wake_senders);
let owner_local_host_id = *owner_local_host_id;
let service = crate::shared_worker_runtime::
new_shared_worker_runtime_service_with_client_owner_id_allocator(
self.client_owner_id_allocator.clone(),
);
service.configure_target_output_streams(
self.browser_context_runtime_id,
self.output_transport.clone(),
);
for sender in owner_wake_senders {
service.add_owner_wake_sender(sender);
}
if let Some(owner_local_host_id) = owner_local_host_id {
service.set_owner_local_host_id(owner_local_host_id);
}
*state = LazySharedWorkerRuntimeState::Live(service.clone());
service
}
pub(super) fn get(&self) -> Option<crate::shared_worker_runtime::SharedWorkerRuntimeService> {
let state = self.state.lock();
let LazySharedWorkerRuntimeState::Live(service) = &*state else {
return None;
};
Some(service.clone())
}
pub(super) fn is_initialized(&self) -> bool {
matches!(*self.state.lock(), LazySharedWorkerRuntimeState::Live(_))
}
pub(super) fn allocate_client_owner_id(&self) -> SharedWorkerClientOwnerId {
self.client_owner_id_allocator.allocate()
}
pub(super) fn add_owner_wake_sender(&self, sender: SharedWorkerRuntimeOwnerWakeSender) {
let mut state = self.state.lock();
match &mut *state {
LazySharedWorkerRuntimeState::Deferred {
owner_wake_senders, ..
} => owner_wake_senders.push(sender),
LazySharedWorkerRuntimeState::Live(service) => service.add_owner_wake_sender(sender),
}
}
pub(super) fn set_owner_local_host_id(&self, owner_local_host_id: RendererOwnerLocalHostId) {
let mut state = self.state.lock();
match &mut *state {
LazySharedWorkerRuntimeState::Deferred {
owner_local_host_id: slot,
..
} => *slot = Some(owner_local_host_id),
LazySharedWorkerRuntimeState::Live(service) => {
service.set_owner_local_host_id(owner_local_host_id)
}
}
}
}
impl RendererBrowserContextRuntime {
fn shared_worker_runtime_if_initialized(
&self,
) -> Option<crate::shared_worker_runtime::SharedWorkerRuntimeService> {
self.inner.shared_worker_runtime.get()
}
pub(crate) fn add_shared_worker_owner_wake_sender(
&self,
sender: SharedWorkerRuntimeOwnerWakeSender,
@@ -37,28 +173,35 @@ impl RendererBrowserContextRuntime {
descriptor: SharedWorkerDescriptor,
params: SharedWorkerLaunchParams,
) -> SharedWorkerClientId {
self.inner.shared_worker_runtime.connect(descriptor, params)
self.inner
.shared_worker_runtime
.get_or_init()
.connect(descriptor, params)
}
pub(crate) fn next_shared_worker_client_owner_id(&self) -> SharedWorkerClientOwnerId {
self.inner.shared_worker_runtime.next_client_owner_id()
self.inner.shared_worker_runtime.allocate_client_owner_id()
}
pub(crate) fn drain_shared_worker_service_lane(&self) -> usize {
self.inner.shared_worker_runtime.drain_service_lane()
self.inner
.shared_worker_runtime
.get()
.map_or(0, |runtime| runtime.drain_service_lane())
}
pub fn close_shared_worker_for_target_close(
&self,
instance_id: SharedWorkerInstanceId,
) -> bool {
self.inner
.shared_worker_runtime
.close_instance_for_devtools_target_close(instance_id)
self.shared_worker_runtime_if_initialized()
.is_some_and(|runtime| runtime.close_instance_for_devtools_target_close(instance_id))
}
pub(crate) fn remove_shared_worker_client(&self, client_id: SharedWorkerClientId) {
self.inner.shared_worker_runtime.remove_client(client_id);
if let Some(runtime) = self.shared_worker_runtime_if_initialized() {
runtime.remove_client(client_id);
}
}
pub(crate) fn continue_shared_worker_fetch(
@@ -66,9 +209,8 @@ impl RendererBrowserContextRuntime {
instance_id: SharedWorkerInstanceId,
request: WorkerPendingFetchContinue,
) -> bool {
self.inner
.shared_worker_runtime
.continue_pending_fetch(instance_id, request)
self.shared_worker_runtime_if_initialized()
.is_some_and(|runtime| runtime.continue_pending_fetch(instance_id, request))
}
pub(crate) fn continue_shared_worker_xhr(
@@ -76,9 +218,8 @@ impl RendererBrowserContextRuntime {
instance_id: SharedWorkerInstanceId,
request: WorkerPendingXhrContinue,
) -> bool {
self.inner
.shared_worker_runtime
.continue_pending_xhr(instance_id, request)
self.shared_worker_runtime_if_initialized()
.is_some_and(|runtime| runtime.continue_pending_xhr(instance_id, request))
}
pub(crate) fn continue_shared_worker_csp_report(
@@ -86,9 +227,8 @@ impl RendererBrowserContextRuntime {
instance_id: SharedWorkerInstanceId,
request: WorkerPendingFetchContinue,
) -> bool {
self.inner
.shared_worker_runtime
.continue_pending_csp_report(instance_id, request)
self.shared_worker_runtime_if_initialized()
.is_some_and(|runtime| runtime.continue_pending_csp_report(instance_id, request))
}
pub(crate) fn continue_shared_worker_fetch_response(
@@ -98,9 +238,15 @@ impl RendererBrowserContextRuntime {
response_code: Option<u16>,
response_headers: Option<Vec<(String, String)>>,
) -> bool {
self.inner
.shared_worker_runtime
.continue_pending_fetch_response(instance_id, request, response_code, response_headers)
self.shared_worker_runtime_if_initialized()
.is_some_and(|runtime| {
runtime.continue_pending_fetch_response(
instance_id,
request,
response_code,
response_headers,
)
})
}
pub(crate) fn continue_shared_worker_xhr_response(
@@ -110,9 +256,15 @@ impl RendererBrowserContextRuntime {
response_code: Option<u16>,
response_headers: Option<Vec<(String, String)>>,
) -> bool {
self.inner
.shared_worker_runtime
.continue_pending_xhr_response(instance_id, request, response_code, response_headers)
self.shared_worker_runtime_if_initialized()
.is_some_and(|runtime| {
runtime.continue_pending_xhr_response(
instance_id,
request,
response_code,
response_headers,
)
})
}
pub(crate) fn fail_shared_worker_fetch(
@@ -121,9 +273,8 @@ impl RendererBrowserContextRuntime {
request: WorkerPendingFetchContinue,
error_text: String,
) -> bool {
self.inner
.shared_worker_runtime
.fail_pending_fetch(instance_id, request, error_text)
self.shared_worker_runtime_if_initialized()
.is_some_and(|runtime| runtime.fail_pending_fetch(instance_id, request, error_text))
}
pub(crate) fn fail_shared_worker_xhr(
@@ -132,9 +283,8 @@ impl RendererBrowserContextRuntime {
request: WorkerPendingXhrContinue,
error_text: String,
) -> bool {
self.inner
.shared_worker_runtime
.fail_pending_xhr(instance_id, request, error_text)
self.shared_worker_runtime_if_initialized()
.is_some_and(|runtime| runtime.fail_pending_xhr(instance_id, request, error_text))
}
pub(crate) fn fail_shared_worker_csp_report(
@@ -143,9 +293,10 @@ impl RendererBrowserContextRuntime {
request: WorkerPendingFetchContinue,
error_text: String,
) -> bool {
self.inner
.shared_worker_runtime
.fail_pending_csp_report(instance_id, request, error_text)
self.shared_worker_runtime_if_initialized()
.is_some_and(|runtime| {
runtime.fail_pending_csp_report(instance_id, request, error_text)
})
}
pub(crate) fn fail_shared_worker_fetch_auth(
@@ -154,9 +305,10 @@ impl RendererBrowserContextRuntime {
request: WorkerPendingFetchContinue,
error_text: String,
) -> bool {
self.inner
.shared_worker_runtime
.fail_pending_fetch_auth(instance_id, request, error_text)
self.shared_worker_runtime_if_initialized()
.is_some_and(|runtime| {
runtime.fail_pending_fetch_auth(instance_id, request, error_text)
})
}
pub(crate) fn fail_shared_worker_xhr_auth(
@@ -165,9 +317,8 @@ impl RendererBrowserContextRuntime {
request: WorkerPendingXhrContinue,
error_text: String,
) -> bool {
self.inner
.shared_worker_runtime
.fail_pending_xhr_auth(instance_id, request, error_text)
self.shared_worker_runtime_if_initialized()
.is_some_and(|runtime| runtime.fail_pending_xhr_auth(instance_id, request, error_text))
}
pub(crate) fn fail_shared_worker_fetch_response(
@@ -176,9 +327,10 @@ impl RendererBrowserContextRuntime {
request: WorkerPendingFetchContinue,
error_text: String,
) -> bool {
self.inner
.shared_worker_runtime
.fail_pending_fetch_response(instance_id, request, error_text)
self.shared_worker_runtime_if_initialized()
.is_some_and(|runtime| {
runtime.fail_pending_fetch_response(instance_id, request, error_text)
})
}
pub(crate) fn fail_shared_worker_xhr_response(
@@ -187,9 +339,10 @@ impl RendererBrowserContextRuntime {
request: WorkerPendingXhrContinue,
error_text: String,
) -> bool {
self.inner
.shared_worker_runtime
.fail_pending_xhr_response(instance_id, request, error_text)
self.shared_worker_runtime_if_initialized()
.is_some_and(|runtime| {
runtime.fail_pending_xhr_response(instance_id, request, error_text)
})
}
pub(crate) fn fulfill_shared_worker_fetch(
@@ -200,13 +353,16 @@ impl RendererBrowserContextRuntime {
response_headers: Vec<(String, String)>,
response_body: RendererSyntheticResponseBody,
) -> bool {
self.inner.shared_worker_runtime.fulfill_pending_fetch(
instance_id,
request,
response_code,
response_headers,
response_body,
)
self.shared_worker_runtime_if_initialized()
.is_some_and(|runtime| {
runtime.fulfill_pending_fetch(
instance_id,
request,
response_code,
response_headers,
response_body,
)
})
}
pub(crate) fn fulfill_shared_worker_xhr(
@@ -217,13 +373,16 @@ impl RendererBrowserContextRuntime {
response_headers: Vec<(String, String)>,
response_body: RendererSyntheticResponseBody,
) -> bool {
self.inner.shared_worker_runtime.fulfill_pending_xhr(
instance_id,
request,
response_code,
response_headers,
response_body,
)
self.shared_worker_runtime_if_initialized()
.is_some_and(|runtime| {
runtime.fulfill_pending_xhr(
instance_id,
request,
response_code,
response_headers,
response_body,
)
})
}
pub(crate) fn fulfill_shared_worker_csp_report(
@@ -234,13 +393,16 @@ impl RendererBrowserContextRuntime {
response_headers: Vec<(String, String)>,
response_body: RendererSyntheticResponseBody,
) -> bool {
self.inner.shared_worker_runtime.fulfill_pending_csp_report(
instance_id,
request,
response_code,
response_headers,
response_body,
)
self.shared_worker_runtime_if_initialized()
.is_some_and(|runtime| {
runtime.fulfill_pending_csp_report(
instance_id,
request,
response_code,
response_headers,
response_body,
)
})
}
pub(crate) fn fulfill_shared_worker_fetch_response(
@@ -251,15 +413,16 @@ impl RendererBrowserContextRuntime {
response_headers: Vec<(String, String)>,
response_body: RendererSyntheticResponseBody,
) -> bool {
self.inner
.shared_worker_runtime
.fulfill_pending_fetch_response(
instance_id,
request,
response_code,
response_headers,
response_body,
)
self.shared_worker_runtime_if_initialized()
.is_some_and(|runtime| {
runtime.fulfill_pending_fetch_response(
instance_id,
request,
response_code,
response_headers,
response_body,
)
})
}
pub(crate) fn fulfill_shared_worker_xhr_response(
@@ -270,15 +433,16 @@ impl RendererBrowserContextRuntime {
response_headers: Vec<(String, String)>,
response_body: RendererSyntheticResponseBody,
) -> bool {
self.inner
.shared_worker_runtime
.fulfill_pending_xhr_response(
instance_id,
request,
response_code,
response_headers,
response_body,
)
self.shared_worker_runtime_if_initialized()
.is_some_and(|runtime| {
runtime.fulfill_pending_xhr_response(
instance_id,
request,
response_code,
response_headers,
response_body,
)
})
}
pub async fn dispatch_shared_worker_runtime_protocol_message(
@@ -287,8 +451,10 @@ impl RendererBrowserContextRuntime {
inspector_session_id: Option<String>,
raw_json: String,
) -> Result<Vec<RendererRuntimeInspectorMessage>, String> {
self.inner
.shared_worker_runtime
let Some(runtime) = self.shared_worker_runtime_if_initialized() else {
return Err("SharedWorkerRuntimeUnavailable".to_owned());
};
runtime
.dispatch_runtime_protocol_message(instance_id, inspector_session_id, raw_json)
.await
}
@@ -300,8 +466,10 @@ impl RendererBrowserContextRuntime {
raw_json: String,
deferred_response: RendererRuntimeInspectorResponseSender,
) -> Result<Vec<RendererRuntimeInspectorMessage>, String> {
self.inner
.shared_worker_runtime
let Some(runtime) = self.shared_worker_runtime_if_initialized() else {
return Err("SharedWorkerRuntimeUnavailable".to_owned());
};
runtime
.dispatch_runtime_protocol_message_with_deferred_response(
instance_id,
inspector_session_id,
@@ -316,8 +484,9 @@ impl RendererBrowserContextRuntime {
instance_id: SharedWorkerInstanceId,
inspector_session_id: Option<String>,
) -> bool {
self.inner
.shared_worker_runtime
.detach_runtime_inspector_session(instance_id, inspector_session_id)
self.shared_worker_runtime_if_initialized()
.is_some_and(|runtime| {
runtime.detach_runtime_inspector_session(instance_id, inspector_session_id)
})
}
}
@@ -3478,12 +3478,24 @@ fn top_level_http_location_navigation_reserves_service_worker_client_until_commi
.await;
let loader =
crate::network::ResourceRequestClient::new(&FetchConfig::default()).expect("loader");
let page_vm = test_page_vm_with_loader_and_document_url(
let browser_context_owner = crate::runtime::RendererBrowserContextRuntime::new();
let browser_context_runtime = browser_context_owner.handle();
browser_context_runtime.service_worker_runtime();
let (owner_wake_tx, _owner_wake_rx) = tokio::sync::mpsc::unbounded_channel();
let runtime_hooks =
PageVmRuntimeHooks::standalone_with_owner_wake_and_browser_context_without_owner_reservation_for_test(
crate::page_task_queue::RendererOwnerWakeSender::new(
owner_wake_tx,
crate::runtime::RendererPageToken::new_for_testing(PageId::new_for_testing(1)),
),
browser_context_runtime.clone(),
);
let page_vm = test_page_vm_with_loader_document_url_and_hooks(
&loader,
Vec::new(),
Url::parse(&format!("{base_url}/start.html")).unwrap(),
runtime_hooks,
);
let browser_context_runtime = page_vm.runtime_hooks.browser_context_runtime.clone();
let browser_context_runtime_after_drop = browser_context_runtime.clone();
let local_executor = page_vm.local_executor.clone();
let next_url = format!("{base_url}/next.html");
@@ -3579,9 +3591,44 @@ fn top_level_http_location_navigation_reserves_service_worker_client_until_commi
server
.await
.expect("top-level reserved navigation response server should finish");
drop(browser_context_owner);
});
}
#[test]
fn top_level_http_location_navigation_without_registrations_keeps_service_worker_runtime_deferred()
{
let loader =
crate::network::ResourceRequestClient::new(&FetchConfig::default()).expect("loader");
let mut page_vm = test_page_vm_with_loader_and_document_url(
&loader,
Vec::new(),
Url::parse("https://deferred-navigation.test/start.html").unwrap(),
);
let browser_context_runtime = page_vm.runtime_hooks.browser_context_runtime.clone();
assert_eq!(
browser_context_runtime.moli_memory_diagnostics()["serviceWorker"]["runtimeInitialized"],
false
);
page_vm
.vm_mut()
.eval("location.href = 'https://deferred-navigation.test/next.html'; 'queued'")
.expect("location navigation should queue");
assert!(page_vm.vm().has_pending_location_navigation());
assert_eq!(
browser_context_runtime.moli_memory_diagnostics()["serviceWorker"]["runtimeInitialized"],
false,
"an empty Service Worker store must not make navigation materialize the runtime"
);
drop(page_vm);
assert_eq!(
browser_context_runtime.moli_memory_diagnostics()["serviceWorker"]["runtimeInitialized"],
false
);
}
#[test]
fn runtime_evaluate_without_enable_uses_inspector_default_context() {
let mut page_vm = test_page_vm();
@@ -63,8 +63,8 @@ pub(crate) use events::{
service_worker_fetch_request_metadata, service_worker_opaque_response_rejection,
};
pub(crate) use ids::{
ServiceWorkerClientId, ServiceWorkerEventId, ServiceWorkerRegistrationId,
ServiceWorkerVersionId,
ServiceWorkerClientId, ServiceWorkerClientIdAllocator, ServiceWorkerEventId,
ServiceWorkerRegistrationId, ServiceWorkerVersionId,
};
pub(crate) use jobs::ServiceWorkerUnregisterStart;
pub(crate) use owner_wake::{
@@ -1,3 +1,8 @@
use std::sync::{
Arc,
atomic::{AtomicU64, Ordering},
};
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub(crate) struct ServiceWorkerRegistrationId(pub(super) u64);
@@ -52,6 +57,25 @@ impl ServiceWorkerClientId {
}
}
#[derive(Clone, Debug)]
pub(crate) struct ServiceWorkerClientIdAllocator {
next: Arc<AtomicU64>,
}
impl Default for ServiceWorkerClientIdAllocator {
fn default() -> Self {
Self {
next: Arc::new(AtomicU64::new(1)),
}
}
}
impl ServiceWorkerClientIdAllocator {
pub(crate) fn allocate(&self) -> ServiceWorkerClientId {
ServiceWorkerClientId(self.next.fetch_add(1, Ordering::Relaxed))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub(crate) struct ServiceWorkerEventId(pub(super) u64);
@@ -170,6 +170,13 @@ impl ServiceWorkerResourceStore {
.collect()
}
pub(crate) fn is_empty(&self) -> bool {
match &self.backend {
ServiceWorkerResourceStoreBackend::Memory(registrations) => registrations.is_empty(),
ServiceWorkerResourceStoreBackend::Json(json) => json.registrations.is_empty(),
}
}
pub(super) fn delete_registration(&mut self, key: &ServiceWorkerRegistrationKey) -> Result<()> {
let mut last_error = None;
for _ in 0..=SERVICE_WORKER_RESOURCE_STORE_MUTATION_RETRY_COUNT {
@@ -299,6 +299,7 @@ pub(crate) fn new_service_worker_runtime_service_with_resource_store_and_browser
resource_store: SharedServiceWorkerResourceStore,
restored_worker_context_runtime: RendererWorkerContextRuntime,
browser_resource_runtime: crate::network::BrowserResourceRuntimeBinding,
client_id_allocator: super::ids::ServiceWorkerClientIdAllocator,
browser_context_runtime_id: crate::runtime::RendererBrowserContextRuntimeId,
output_transport: crate::runtime::RendererOutputTransportSenderSlot,
) -> ServiceWorkerRuntimeService {
@@ -308,6 +309,7 @@ pub(crate) fn new_service_worker_runtime_service_with_resource_store_and_browser
resource_store,
restored_worker_context_runtime,
browser_resource_runtime,
client_id_allocator,
browser_context_runtime_id,
output_transport,
)),
@@ -801,9 +803,7 @@ mod tests {
let controlled_client_ids = controlled_client_documents
.into_iter()
.map(|document_url| {
let client_id = ServiceWorkerClientId(
service.inner.next_client_id.fetch_add(1, Ordering::Relaxed),
);
let client_id = service.inner.client_id_allocator.allocate();
let current_document_url =
service_worker_current_url_for_creation_url(&document_url);
let storage_key =
@@ -1143,8 +1143,7 @@ mod tests {
worker_tx,
);
}
let client_id =
ServiceWorkerClientId(service.inner.next_client_id.fetch_add(1, Ordering::Relaxed));
let client_id = service.inner.client_id_allocator.allocate();
let document_url = service_worker_current_url_for_creation_url(&creation_url);
let storage_key =
ServiceWorkerRegistrationKey::first_party_storage_key_for_url(&document_url);
@@ -23,6 +23,7 @@ impl ServiceWorkerRuntimeService {
)
}
#[cfg(test)]
pub(crate) fn register_client_with_storage_key(
&self,
document_url: Url,
@@ -31,17 +32,43 @@ impl ServiceWorkerRuntimeService {
document_owner: Option<crate::window_document_identity::WindowDocumentOwner>,
completion_tx: RendererPageServiceWorkerTaskSender,
) -> ServiceWorkerClientId {
let client_id = self.register_window_client_with_storage_key(
let client_id = self.inner.client_id_allocator.allocate();
let inserted = self.register_window_client_with_storage_key(
client_id,
document_url,
storage_key,
frame_type,
document_owner,
ServiceWorkerClientEndpoint::Page(completion_tx),
);
debug_assert!(inserted, "new ServiceWorker client id must be unused");
self.mark_client_execution_ready(client_id);
client_id
}
pub(crate) fn register_allocated_client_with_storage_key(
&self,
client_id: ServiceWorkerClientId,
document_url: Url,
storage_key: String,
frame_type: ServiceWorkerClientFrameType,
document_owner: Option<crate::window_document_identity::WindowDocumentOwner>,
completion_tx: RendererPageServiceWorkerTaskSender,
) -> bool {
if !self.register_window_client_with_storage_key(
client_id,
document_url,
storage_key,
frame_type,
document_owner,
ServiceWorkerClientEndpoint::Page(completion_tx),
) {
return false;
}
self.mark_client_execution_ready(client_id);
true
}
pub(crate) fn register_reserved_client_with_storage_key(
&self,
document_url: Url,
@@ -82,7 +109,9 @@ impl ServiceWorkerRuntimeService {
document_owner: Option<crate::window_document_identity::WindowDocumentOwner>,
bypass_service_worker: bool,
) -> ServiceWorkerClientId {
self.register_window_client_with_storage_key(
let client_id = self.inner.client_id_allocator.allocate();
let inserted = self.register_window_client_with_storage_key(
client_id,
document_url,
storage_key,
frame_type,
@@ -90,7 +119,12 @@ impl ServiceWorkerRuntimeService {
ServiceWorkerClientEndpoint::ReservedPage {
bypass_service_worker,
},
)
);
debug_assert!(
inserted,
"new reserved ServiceWorker client id must be unused"
);
client_id
}
pub(crate) fn register_worker_client_with_storage_key(
@@ -105,8 +139,7 @@ impl ServiceWorkerRuntimeService {
client_type,
ServiceWorkerClientType::DedicatedWorker | ServiceWorkerClientType::SharedWorker
));
let client_id =
ServiceWorkerClientId(self.inner.next_client_id.fetch_add(1, Ordering::Relaxed));
let client_id = self.inner.client_id_allocator.allocate();
let current_script_url = service_worker_current_url_for_creation_url(&script_url);
{
let mut state = self.inner.state.lock();
@@ -159,8 +192,7 @@ impl ServiceWorkerRuntimeService {
client_type,
ServiceWorkerClientType::DedicatedWorker | ServiceWorkerClientType::SharedWorker
));
let client_id =
ServiceWorkerClientId(self.inner.next_client_id.fetch_add(1, Ordering::Relaxed));
let client_id = self.inner.client_id_allocator.allocate();
let current_script_url = service_worker_current_url_for_creation_url(&script_url);
{
let mut state = self.inner.state.lock();
@@ -250,8 +282,7 @@ impl ServiceWorkerRuntimeService {
.map(|registration| registration.id)
})
.flatten();
let client_id =
ServiceWorkerClientId(self.inner.next_client_id.fetch_add(1, Ordering::Relaxed));
let client_id = self.inner.client_id_allocator.allocate();
state.live_clients.insert(
client_id,
ServiceWorkerClient {
@@ -304,14 +335,13 @@ impl ServiceWorkerRuntimeService {
fn register_window_client_with_storage_key(
&self,
client_id: ServiceWorkerClientId,
document_url: Url,
storage_key: String,
frame_type: ServiceWorkerClientFrameType,
document_owner: Option<crate::window_document_identity::WindowDocumentOwner>,
endpoint: ServiceWorkerClientEndpoint,
) -> ServiceWorkerClientId {
let client_id =
ServiceWorkerClientId(self.inner.next_client_id.fetch_add(1, Ordering::Relaxed));
) -> bool {
let current_document_url = service_worker_current_url_for_creation_url(&document_url);
let bypass_service_worker = matches!(
&endpoint,
@@ -321,6 +351,9 @@ impl ServiceWorkerRuntimeService {
);
{
let mut state = self.inner.state.lock();
if state.live_clients.contains_key(&client_id) {
return false;
}
self.restore_stored_registrations_for_document_url_locked(
&mut state,
&current_document_url,
@@ -356,7 +389,7 @@ impl ServiceWorkerRuntimeService {
state.record_target_version_updated(version_id);
}
}
client_id
true
}
fn mark_client_execution_ready(&self, client_id: ServiceWorkerClientId) {
@@ -122,7 +122,7 @@ fn target_status_for_lifecycle_state(
pub(super) struct ServiceWorkerRuntimeInner {
pub(super) next_registration_id: AtomicU64,
pub(super) next_version_id: AtomicU64,
pub(super) next_client_id: AtomicU64,
pub(super) client_id_allocator: super::ids::ServiceWorkerClientIdAllocator,
pub(super) next_event_id: AtomicU64,
pub(super) next_force_update_page_load_waiter_id: AtomicU64,
pub(super) next_notification_id: AtomicU64,
@@ -146,13 +146,14 @@ impl ServiceWorkerRuntimeInner {
resource_store: SharedServiceWorkerResourceStore,
restored_worker_context_runtime: RendererWorkerContextRuntime,
browser_resource_runtime: crate::network::BrowserResourceRuntimeBinding,
client_id_allocator: super::ids::ServiceWorkerClientIdAllocator,
browser_context_runtime_id: crate::runtime::RendererBrowserContextRuntimeId,
output_transport: crate::runtime::RendererOutputTransportSenderSlot,
) -> Self {
Self {
next_registration_id: AtomicU64::new(1),
next_version_id: AtomicU64::new(1),
next_client_id: AtomicU64::new(1),
client_id_allocator,
next_event_id: AtomicU64::new(1),
next_force_update_page_load_waiter_id: AtomicU64::new(1),
next_notification_id: AtomicU64::new(1),
@@ -52,8 +52,11 @@ pub(crate) use loading::{
SharedWorkerExecutionPolicy, SharedWorkerLaunchContext, SharedWorkerLaunchParams,
SharedWorkerScriptLoad, SharedWorkerScriptRequestPolicy,
};
pub(crate) use matching::SharedWorkerClientOwnerIdAllocator;
pub(crate) use owner_wake::{
SharedWorkerRuntimeOwnerWake, SharedWorkerRuntimeOwnerWakeSender,
shared_worker_owner_wake_channel,
};
pub(crate) use service::{SharedWorkerRuntimeService, new_shared_worker_runtime_service};
pub(crate) use service::{
SharedWorkerRuntimeService, new_shared_worker_runtime_service_with_client_owner_id_allocator,
};
@@ -1,4 +1,7 @@
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{
Arc,
atomic::{AtomicU64, Ordering},
};
use moli_shared_worker::{
SharedWorkerClientId, SharedWorkerClientOwnerId, SharedWorkerClientRemoval,
@@ -12,14 +15,47 @@ use super::{
host::SharedRendererSharedWorkerHost,
};
#[derive(Clone, Debug)]
pub(crate) struct SharedWorkerClientOwnerIdAllocator {
next: Arc<AtomicU64>,
}
impl Default for SharedWorkerClientOwnerIdAllocator {
fn default() -> Self {
Self {
next: Arc::new(AtomicU64::new(0)),
}
}
}
impl SharedWorkerClientOwnerIdAllocator {
pub(crate) fn allocate(&self) -> SharedWorkerClientOwnerId {
let id = self.next.fetch_add(1, Ordering::Relaxed).saturating_add(1);
SharedWorkerClientOwnerId::from_u64(id)
}
}
#[derive(Default)]
pub(super) struct SharedWorkerMatchingStore {
registry: SharedWorkerRegistry<SharedRendererSharedWorkerHost>,
client_owner_lifecycle: SharedWorkerClientOwnerLifecycleStore,
next_client_owner_id: AtomicU64,
client_owner_id_allocator: SharedWorkerClientOwnerIdAllocator,
}
impl SharedWorkerMatchingStore {
pub(super) fn with_client_owner_id_allocator(
client_owner_id_allocator: SharedWorkerClientOwnerIdAllocator,
) -> Self {
Self {
client_owner_id_allocator,
..Self::default()
}
}
pub(super) fn client_owner_id_allocator(&self) -> SharedWorkerClientOwnerIdAllocator {
self.client_owner_id_allocator.clone()
}
pub(super) fn connect(
&self,
key: SharedWorkerKey,
@@ -100,12 +136,9 @@ impl SharedWorkerMatchingStore {
self.registry.loading_clients_for_instance(instance_id)
}
#[cfg(test)]
pub(super) fn next_client_owner_id(&self) -> SharedWorkerClientOwnerId {
let id = self
.next_client_owner_id
.fetch_add(1, Ordering::Relaxed)
.saturating_add(1);
SharedWorkerClientOwnerId::from_u64(id)
self.client_owner_id_allocator.allocate()
}
fn consume_observed_action<T>(&self, observed: SharedWorkerObservedAction<T>) -> T {
@@ -17,7 +17,7 @@ use crate::runtime::RendererOwnerLocalHostId;
use super::{
host::SharedRendererSharedWorkerHost,
instances::SharedWorkerHostStore,
matching::SharedWorkerMatchingStore,
matching::{SharedWorkerClientOwnerIdAllocator, SharedWorkerMatchingStore},
owner_wake::{
SharedWorkerOwnerWake, SharedWorkerRuntimeOwnerWake, SharedWorkerRuntimeOwnerWakeSender,
},
@@ -25,8 +25,17 @@ use super::{
target_output_streams::SharedWorkerTargetOutputStreams,
};
pub(crate) fn new_shared_worker_runtime_service() -> SharedWorkerRuntimeService {
SharedWorkerRuntimeService::default()
pub(crate) fn new_shared_worker_runtime_service_with_client_owner_id_allocator(
client_owner_id_allocator: SharedWorkerClientOwnerIdAllocator,
) -> SharedWorkerRuntimeService {
SharedWorkerRuntimeService {
inner: Arc::new(SharedWorkerRuntimeInner {
matching: Arc::new(SharedWorkerMatchingStore::with_client_owner_id_allocator(
client_owner_id_allocator,
)),
..SharedWorkerRuntimeInner::default()
}),
}
}
#[derive(Clone)]
@@ -50,6 +59,10 @@ struct SharedWorkerRuntimeInner {
}
impl SharedWorkerRuntimeService {
pub(crate) fn client_owner_id_allocator(&self) -> SharedWorkerClientOwnerIdAllocator {
self.inner.matching.client_owner_id_allocator()
}
pub(crate) fn configure_target_output_streams(
&self,
browser_context_runtime_id: crate::runtime::RendererBrowserContextRuntimeId,
@@ -136,6 +149,7 @@ impl SharedWorkerRuntimeService {
self.inner.owner_wake.signal_service_lane_wake()
}
#[cfg(test)]
pub(crate) fn next_client_owner_id(&self) -> SharedWorkerClientOwnerId {
self.inner.matching.next_client_owner_id()
}