Skip to main content

script/dom/workers/
sharedworkerglobalscope.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::sync::Arc;
6use std::sync::atomic::AtomicBool;
7use std::thread::{self, JoinHandle};
8
9use crossbeam_channel::{Receiver, Sender, unbounded};
10use devtools_traits::DevtoolScriptControlMsg;
11use dom_struct::dom_struct;
12use fonts::FontContext;
13use js::context::JSContext;
14use js::jsval::UndefinedValue;
15use net_traits::blob_url_store::UrlWithBlobClaim;
16use net_traits::policy_container::{PolicyContainer, RequestPolicyContainer};
17use net_traits::request::{
18    CredentialsMode, Destination, InsecureRequestsPolicy, Origin, PreloadedResources, Referrer,
19    RequestClient,
20};
21use script_bindings::cell::DomRefCell;
22use script_bindings::conversions::SafeToJSValConvertible;
23use servo_base::generic_channel::{GenericReceiver, RoutedReceiver};
24use servo_base::id::ScriptEventLoopId;
25use servo_constellation_traits::{MessagePortImpl, WorkerGlobalScopeInit, WorkerScriptLoadOrigin};
26use servo_url::ServoUrl;
27use style::thread_state::{self, ThreadState};
28use stylo_atoms::Atom;
29
30use crate::dom::abstractworker::{SimpleWorkerErrorHandler, WorkerScriptMsg};
31use crate::dom::abstractworkerglobalscope::{WorkerEventLoopMethods, run_worker_event_loop};
32use crate::dom::bindings::codegen::Bindings::SharedWorkerGlobalScopeBinding;
33use crate::dom::bindings::codegen::Bindings::SharedWorkerGlobalScopeBinding::SharedWorkerGlobalScopeMethods;
34use crate::dom::bindings::codegen::Bindings::WorkerBinding::WorkerType;
35use crate::dom::bindings::codegen::UnionTypes::WindowProxyOrMessagePortOrServiceWorker;
36use crate::dom::bindings::inheritance::Castable;
37use crate::dom::bindings::refcounted::Trusted;
38use crate::dom::bindings::root::{Dom, DomRoot};
39use crate::dom::bindings::str::DOMString;
40use crate::dom::bindings::trace::CustomTraceable;
41use crate::dom::dedicatedworkerglobalscope::fetch_a_classic_worker_script;
42use crate::dom::event::Event;
43use crate::dom::event::messageevent::MessageEvent;
44use crate::dom::eventtarget::EventTarget;
45use crate::dom::globalscope::GlobalScope;
46use crate::dom::html::htmlscriptelement::Script;
47use crate::dom::messageport::MessagePort;
48use crate::dom::sharedworker::{SharedWorker, TrustedSharedWorkerAddress};
49use crate::dom::types::DebuggerGlobalScope;
50#[cfg(feature = "webgpu")]
51use crate::dom::webgpu::identityhub::IdentityHub;
52use crate::dom::workerglobalscope::WorkerGlobalScope;
53use crate::messaging::{CommonScriptMsg, ScriptEventLoopReceiver, ScriptEventLoopSender};
54use crate::script_module::{ModuleFetchClient, fetch_a_module_worker_script_graph};
55use crate::script_runtime::ScriptThreadEventCategory::WorkerEvent;
56use crate::script_runtime::{CanGc, Runtime, ThreadSafeJSContext};
57use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
58use crate::task_source::TaskSourceName;
59
60pub(crate) enum SharedWorkerScriptMsg {
61    CommonWorker(WorkerScriptMsg),
62    #[allow(dead_code)]
63    Connect(MessagePortImpl),
64    WakeUp,
65}
66
67#[allow(dead_code)]
68pub(crate) enum SharedWorkerControlMsg {
69    Exit,
70}
71
72pub(crate) enum MixedMessage {
73    SharedWorker(SharedWorkerScriptMsg),
74    Devtools(DevtoolScriptControlMsg),
75    Control(SharedWorkerControlMsg),
76    Timer,
77}
78
79impl QueuedTaskConversion for SharedWorkerScriptMsg {
80    fn task_source_name(&self) -> Option<&TaskSourceName> {
81        let script_msg = match self {
82            SharedWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(script_msg)) => script_msg,
83            _ => return None,
84        };
85        match script_msg {
86            CommonScriptMsg::Task(_category, _boxed, _pipeline_id, task_source) => {
87                Some(task_source)
88            },
89            _ => None,
90        }
91    }
92
93    fn pipeline_id(&self) -> Option<servo_base::id::PipelineId> {
94        None
95    }
96
97    fn into_queued_task(self) -> Option<QueuedTask> {
98        let script_msg = match self {
99            SharedWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(script_msg)) => script_msg,
100            _ => return None,
101        };
102        let (event_category, task, pipeline_id, task_source) = match script_msg {
103            CommonScriptMsg::Task(category, boxed, pipeline_id, task_source) => {
104                (category, boxed, pipeline_id, task_source)
105            },
106            _ => return None,
107        };
108        Some(QueuedTask {
109            worker: None,
110            event_category,
111            task,
112            pipeline_id,
113            task_source,
114        })
115    }
116
117    fn from_queued_task(queued_task: QueuedTask) -> Self {
118        let script_msg = CommonScriptMsg::Task(
119            queued_task.event_category,
120            queued_task.task,
121            queued_task.pipeline_id,
122            queued_task.task_source,
123        );
124        SharedWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(script_msg))
125    }
126
127    fn inactive_msg() -> Self {
128        panic!("Workers should never receive messages marked as inactive");
129    }
130
131    fn wake_up_msg() -> Self {
132        SharedWorkerScriptMsg::WakeUp
133    }
134
135    fn is_wake_up(&self) -> bool {
136        matches!(self, SharedWorkerScriptMsg::WakeUp)
137    }
138}
139
140unsafe_no_jsmanaged_fields!(TaskQueue<SharedWorkerScriptMsg>);
141
142// https://html.spec.whatwg.org/multipage/#shared-workers-and-the-sharedworkerglobalscope-interface
143#[dom_struct]
144pub(crate) struct SharedWorkerGlobalScope {
145    workerglobalscope: WorkerGlobalScope,
146    #[ignore_malloc_size_of = "Defined in std"]
147    task_queue: TaskQueue<SharedWorkerScriptMsg>,
148    own_sender: Sender<SharedWorkerScriptMsg>,
149    worker: DomRefCell<Option<TrustedSharedWorkerAddress>>,
150    parent_event_loop_sender: ScriptEventLoopSender,
151    pending_connect: DomRefCell<Option<Dom<MessagePort>>>,
152    #[no_trace]
153    control_receiver: Receiver<SharedWorkerControlMsg>,
154    debugger_global: Dom<DebuggerGlobalScope>,
155}
156
157impl WorkerEventLoopMethods for SharedWorkerGlobalScope {
158    type WorkerMsg = SharedWorkerScriptMsg;
159    type ControlMsg = SharedWorkerControlMsg;
160    type Event = MixedMessage;
161
162    fn task_queue(&self) -> &TaskQueue<SharedWorkerScriptMsg> {
163        &self.task_queue
164    }
165
166    fn handle_event(&self, event: MixedMessage, cx: &mut JSContext) -> bool {
167        self.handle_mixed_message(event, cx)
168    }
169
170    fn handle_worker_post_event(
171        &self,
172        _worker: &crate::dom::worker::TrustedWorkerAddress,
173    ) -> Option<crate::dom::dedicatedworkerglobalscope::AutoWorkerReset<'_>> {
174        None
175    }
176
177    fn from_control_msg(msg: SharedWorkerControlMsg) -> MixedMessage {
178        MixedMessage::Control(msg)
179    }
180
181    fn from_worker_msg(msg: SharedWorkerScriptMsg) -> MixedMessage {
182        MixedMessage::SharedWorker(msg)
183    }
184
185    fn from_devtools_msg(msg: DevtoolScriptControlMsg) -> MixedMessage {
186        MixedMessage::Devtools(msg)
187    }
188
189    fn from_timer_msg() -> MixedMessage {
190        MixedMessage::Timer
191    }
192
193    fn control_receiver(&self) -> &Receiver<SharedWorkerControlMsg> {
194        &self.control_receiver
195    }
196}
197
198impl SharedWorkerGlobalScope {
199    #[allow(clippy::too_many_arguments)]
200    #[allow(dead_code)]
201    fn new_inherited(
202        init: WorkerGlobalScopeInit,
203        worker_name: DOMString,
204        worker_type: WorkerType,
205        worker_url: ServoUrl,
206        worker: TrustedSharedWorkerAddress,
207        parent_event_loop_sender: ScriptEventLoopSender,
208        from_devtools_receiver: RoutedReceiver<DevtoolScriptControlMsg>,
209        runtime: Runtime,
210        own_sender: Sender<SharedWorkerScriptMsg>,
211        receiver: Receiver<SharedWorkerScriptMsg>,
212        closing: Arc<AtomicBool>,
213        #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
214        control_receiver: Receiver<SharedWorkerControlMsg>,
215        insecure_requests_policy: InsecureRequestsPolicy,
216        font_context: Option<Arc<FontContext>>,
217        debugger_global: &DebuggerGlobalScope,
218    ) -> SharedWorkerGlobalScope {
219        SharedWorkerGlobalScope {
220            workerglobalscope: WorkerGlobalScope::new_inherited(
221                init,
222                worker_name,
223                worker_type,
224                worker_url,
225                runtime,
226                from_devtools_receiver,
227                closing,
228                #[cfg(feature = "webgpu")]
229                gpu_id_hub,
230                insecure_requests_policy,
231                font_context,
232            ),
233            task_queue: TaskQueue::new(receiver, own_sender.clone()),
234            own_sender,
235            worker: DomRefCell::new(Some(worker)),
236            parent_event_loop_sender,
237            pending_connect: DomRefCell::new(None),
238            control_receiver,
239            debugger_global: Dom::from_ref(debugger_global),
240        }
241    }
242
243    #[allow(clippy::too_many_arguments)]
244    #[allow(dead_code)]
245    pub(crate) fn new(
246        init: WorkerGlobalScopeInit,
247        worker_name: DOMString,
248        worker_type: WorkerType,
249        worker_url: ServoUrl,
250        worker: TrustedSharedWorkerAddress,
251        parent_event_loop_sender: ScriptEventLoopSender,
252        from_devtools_receiver: RoutedReceiver<DevtoolScriptControlMsg>,
253        runtime: Runtime,
254        own_sender: Sender<SharedWorkerScriptMsg>,
255        receiver: Receiver<SharedWorkerScriptMsg>,
256        closing: Arc<AtomicBool>,
257        #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
258        control_receiver: Receiver<SharedWorkerControlMsg>,
259        insecure_requests_policy: InsecureRequestsPolicy,
260        font_context: Option<Arc<FontContext>>,
261        debugger_global: &DebuggerGlobalScope,
262        cx: &mut js::context::JSContext,
263    ) -> DomRoot<SharedWorkerGlobalScope> {
264        let scope = Box::new(SharedWorkerGlobalScope::new_inherited(
265            init,
266            worker_name,
267            worker_type,
268            worker_url,
269            worker,
270            parent_event_loop_sender,
271            from_devtools_receiver,
272            runtime,
273            own_sender,
274            receiver,
275            closing,
276            #[cfg(feature = "webgpu")]
277            gpu_id_hub,
278            control_receiver,
279            insecure_requests_policy,
280            font_context,
281            debugger_global,
282        ));
283        SharedWorkerGlobalScopeBinding::Wrap::<crate::DomTypeHolder>(cx, scope)
284    }
285
286    /// <https://html.spec.whatwg.org/multipage/#run-a-worker>
287    #[expect(unsafe_code)]
288    #[allow(dead_code)]
289    #[allow(clippy::too_many_arguments)]
290    pub(crate) fn run_shared_worker_scope(
291        init: WorkerGlobalScopeInit,
292        worker_name: DOMString,
293        worker_type: WorkerType,
294        worker_url: UrlWithBlobClaim,
295        worker: TrustedSharedWorkerAddress,
296        parent_event_loop_sender: ScriptEventLoopSender,
297        from_devtools_receiver: GenericReceiver<DevtoolScriptControlMsg>,
298        own_sender: Sender<SharedWorkerScriptMsg>,
299        receiver: Receiver<SharedWorkerScriptMsg>,
300        worker_load_origin: WorkerScriptLoadOrigin,
301        closing: Arc<AtomicBool>,
302        #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
303        control_receiver: Receiver<SharedWorkerControlMsg>,
304        context_sender: Sender<ThreadSafeJSContext>,
305        credentials: CredentialsMode,
306        insecure_requests_policy: InsecureRequestsPolicy,
307        policy_container: PolicyContainer,
308        font_context: Option<Arc<FontContext>>,
309    ) -> JoinHandle<()> {
310        let event_loop_id = ScriptEventLoopId::installed()
311            .expect("Should always be in a ScriptThread or in a worker");
312        let current_global = GlobalScope::current().expect("No current global object");
313        let origin = current_global.origin().immutable().clone();
314        let referrer = current_global.get_referrer();
315        let parent = current_global.runtime_handle();
316        let current_global_ancestor_trustworthy = current_global.has_trustworthy_ancestor_origin();
317        let is_nested_browsing_context = current_global.is_nested_browsing_context();
318        let webview_id = current_global.webview_id();
319        let worker_name = worker_name.to_string();
320
321        thread::Builder::new()
322            .name(format!("SWW:{}", worker_url.debug_compact()))
323            .spawn(move || {
324                // Step 4. Let agent be the result of obtaining a dedicated/shared worker agent
325                // given outside settings and is shared. Run the rest of these steps in that
326                // agent.
327                thread_state::initialize(ThreadState::SCRIPT | ThreadState::IN_WORKER);
328                ScriptEventLoopId::install(event_loop_id);
329
330                let WorkerScriptLoadOrigin {
331                    referrer_url,
332                    pipeline_id,
333                    ..
334                } = worker_load_origin;
335
336                let referrer = referrer_url.map(Referrer::ReferrerUrl).unwrap_or(referrer);
337
338                let request_client = RequestClient {
339                    preloaded_resources: PreloadedResources::default(),
340                    policy_container: RequestPolicyContainer::PolicyContainer(
341                        policy_container.clone(),
342                    ),
343                    origin: Origin::Origin(origin.clone()),
344                    is_nested_browsing_context,
345                    insecure_requests_policy,
346                };
347
348                let event_loop_sender = ScriptEventLoopSender::SharedWorker(own_sender.clone());
349
350                let runtime = unsafe {
351                    Runtime::new_with_parent(Some(parent), Some(event_loop_sender.clone()))
352                };
353                // SAFETY: We are in a new thread, so this first cx.
354                // It is OK to have it separated of runtime here,
355                // because it will never outlive it (runtime destruction happens at the end of this function)
356                let mut cx = unsafe { runtime.cx() };
357                let cx = &mut cx;
358                let debugger_global = DebuggerGlobalScope::new(
359                    pipeline_id,
360                    init.to_devtools_sender.clone(),
361                    init.from_devtools_sender
362                        .clone()
363                        .expect("Guaranteed by SharedWorker::Constructor"),
364                    init.mem_profiler_chan.clone(),
365                    init.time_profiler_chan.clone(),
366                    init.script_to_constellation_chan.clone(),
367                    init.script_to_embedder_chan.clone(),
368                    init.resource_threads.clone(),
369                    init.storage_threads.clone(),
370                    #[cfg(feature = "webgpu")]
371                    gpu_id_hub.clone(),
372                    cx,
373                );
374                debugger_global.execute(cx);
375
376                let context_for_interrupt = runtime.thread_safe_js_context();
377                let _ = context_sender.send(context_for_interrupt);
378
379                let devtools_mpsc_port = from_devtools_receiver.route_preserving_errors();
380
381                let worker_id = init.worker_id;
382                let devtools_enabled = init.to_devtools_sender.is_some();
383                // Creating the worker global scope initializes its name (step 8)
384                // and, for shared workers, its type (step 10.3 of run a worker).
385                let global = SharedWorkerGlobalScope::new(
386                    init,
387                    worker_name.into(),
388                    worker_type,
389                    worker_url.url(),
390                    worker,
391                    parent_event_loop_sender,
392                    devtools_mpsc_port,
393                    runtime,
394                    own_sender,
395                    receiver,
396                    closing,
397                    #[cfg(feature = "webgpu")]
398                    gpu_id_hub,
399                    control_receiver,
400                    insecure_requests_policy,
401                    font_context,
402                    &debugger_global,
403                    cx,
404                );
405                let scope = global.upcast::<WorkerGlobalScope>();
406                let global_scope = global.upcast::<GlobalScope>();
407                if devtools_enabled {
408                    debugger_global.fire_add_debuggee(
409                        cx,
410                        global_scope,
411                        pipeline_id,
412                        Some(worker_id),
413                    );
414                }
415
416                let fetch_client = ModuleFetchClient {
417                    insecure_requests_policy,
418                    has_trustworthy_ancestor_origin: current_global_ancestor_trustworthy,
419                    policy_container,
420                    client: request_client,
421                    pipeline_id,
422                    origin,
423                };
424
425                // Step 11. Let destination be "sharedworker" if is shared is true, and
426                // "worker" otherwise.
427                // Step 12. Obtain script by switching on options["type"]:
428                match worker_type {
429                    WorkerType::Classic => {
430                        fetch_a_classic_worker_script(
431                            scope,
432                            worker_url,
433                            fetch_client,
434                            Destination::SharedWorker,
435                            webview_id,
436                            referrer,
437                        );
438                    },
439                    WorkerType::Module => {
440                        let worker_scope = DomRoot::from_ref(scope);
441                        fetch_a_module_worker_script_graph(
442                            cx,
443                            global_scope,
444                            worker_url.url(),
445                            fetch_client,
446                            Destination::SharedWorker,
447                            referrer,
448                            credentials,
449                            move |cx, module_tree| {
450                                worker_scope.on_complete(cx, module_tree.map(Script::Module));
451                            },
452                        );
453                    },
454                }
455
456                let reporter_name = format!("shared-worker-reporter-{}", worker_id);
457                scope
458                    .upcast::<GlobalScope>()
459                    .mem_profiler_chan()
460                    .run_with_memory_reporting(
461                        || {
462                            // Event loop: Run the responsible event loop specified by inside settings until it is destroyed.
463                            while !scope.is_closing() {
464                                run_worker_event_loop(&*global, None, cx);
465                            }
466                        },
467                        reporter_name,
468                        event_loop_sender,
469                        CommonScriptMsg::CollectReports,
470                    );
471
472                scope.clear_js_runtime();
473            })
474            .expect("Thread spawning failed")
475    }
476
477    pub(crate) fn event_loop_sender(&self) -> ScriptEventLoopSender {
478        ScriptEventLoopSender::SharedWorker(self.own_sender.clone())
479    }
480
481    pub(crate) fn new_script_pair(&self) -> (ScriptEventLoopSender, ScriptEventLoopReceiver) {
482        let (sender, receiver) = unbounded();
483        (
484            ScriptEventLoopSender::SharedWorker(sender),
485            ScriptEventLoopReceiver::SharedWorker(receiver),
486        )
487    }
488
489    /// Step 1.1 of onComplete of <https://html.spec.whatwg.org/multipage/#run-a-worker>
490    pub(crate) fn forward_simple_error_at_worker(&self) {
491        let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
492        let worker = self.worker.borrow().clone().expect("worker must be set");
493        self.parent_event_loop_sender
494            .send(CommonScriptMsg::Task(
495                WorkerEvent,
496                Box::new(SimpleWorkerErrorHandler::new(worker)),
497                Some(pipeline_id),
498                TaskSourceName::DOMManipulation,
499            ))
500            .expect("Sending to parent failed");
501    }
502
503    /// Step 11 of onComplete of <https://html.spec.whatwg.org/multipage/#run-a-worker>
504    pub(crate) fn enable_outside_port_message_queue(&self) {
505        let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
506        let worker = self.worker.borrow().clone().expect("worker must be set");
507
508        self.parent_event_loop_sender
509            .send(CommonScriptMsg::Task(
510                WorkerEvent,
511                Box::new(
512                    task!(sharedworker_enable_outside_port_message_queue: move |cx| {
513                        SharedWorker::enable_outside_port_message_queue(worker, cx);
514                    }),
515                ),
516                Some(pipeline_id),
517                TaskSourceName::DOMManipulation,
518            ))
519            .expect("Sending to parent failed");
520    }
521
522    fn handle_connect(
523        &self,
524        port_impl: MessagePortImpl,
525        cx: &mut JSContext,
526    ) -> DomRoot<MessagePort> {
527        // Let inside port be a new MessagePort object in inside settings's realm.
528        let inside_port = MessagePort::new_transferred(
529            self.upcast::<GlobalScope>(),
530            *port_impl.message_port_id(),
531            port_impl.entangled_port_id(),
532            CanGc::from_cx(cx),
533        );
534        self.upcast::<GlobalScope>()
535            .track_message_port(&inside_port, Some(port_impl));
536        inside_port
537    }
538
539    // Step 13. Queue a global task to fire a connect event.
540    fn dispatch_connect_event(&self, inside_port: &MessagePort) {
541        let worker_global = Trusted::new(self);
542        let inside_port = Trusted::new(inside_port);
543
544        self.upcast::<GlobalScope>()
545            .task_manager()
546            .dom_manipulation_task_source()
547            .queue(task!(sharedworker_connect_event: move |cx| {
548                let worker_global = worker_global.root();
549                let worker_global = &*worker_global;
550                let inside_port = inside_port.root();
551
552                rooted!(&in(cx) let mut data = UndefinedValue());
553                DOMString::from("").safe_to_jsval(
554                    cx.into(),
555                    data.handle_mut(),
556                    CanGc::from_cx(cx),
557                );
558
559                let source = WindowProxyOrMessagePortOrServiceWorker::MessagePort(
560                    inside_port.clone(),
561                );
562                let event = MessageEvent::new(
563                    worker_global.upcast::<GlobalScope>(),
564                    Atom::from("connect"),
565                    false,
566                    false,
567                    data.handle(),
568                    DOMString::from(""),
569                    Some(&source),
570                    DOMString::new(),
571                    vec![inside_port],
572                    CanGc::from_cx(cx),
573                );
574
575                event
576                    .upcast::<Event>()
577                    .fire(cx, worker_global.upcast::<EventTarget>());
578            }));
579    }
580
581    pub(crate) fn fire_pending_connect(&self, _cx: &mut JSContext) {
582        let inside_port = self
583            .pending_connect
584            .borrow_mut()
585            .take()
586            .map(|inside_port| inside_port.as_rooted());
587        if let Some(inside_port) = inside_port {
588            if self.upcast::<WorkerGlobalScope>().is_closing() {
589                return;
590            }
591            self.dispatch_connect_event(&inside_port);
592        }
593    }
594
595    fn handle_script_event(&self, msg: SharedWorkerScriptMsg, cx: &mut JSContext) {
596        match msg {
597            SharedWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(msg)) => {
598                self.upcast::<WorkerGlobalScope>().process_event(msg, cx);
599            },
600            SharedWorkerScriptMsg::Connect(port_impl) => {
601                let inside_port = self.handle_connect(port_impl, cx);
602                if self.upcast::<WorkerGlobalScope>().is_execution_ready() {
603                    self.dispatch_connect_event(&inside_port);
604                } else {
605                    let mut pending_connect = self.pending_connect.borrow_mut();
606                    debug_assert!(
607                        pending_connect.is_none(),
608                        "SharedWorkerGlobalScope only expects one pre-ready connect in the current implementation"
609                    );
610                    pending_connect.replace(Dom::from_ref(&*inside_port));
611                }
612            },
613            SharedWorkerScriptMsg::CommonWorker(WorkerScriptMsg::DOMMessage(_)) => {
614                // SharedWorker messages arrive through the entangled MessagePort and are
615                // surfaced as connect/message events, not as direct WorkerScriptMsg::DOMMessage.
616                debug_assert!(
617                    false,
618                    "SharedWorkerGlobalScope does not support direct DOMMessage dispatch"
619                );
620            },
621            SharedWorkerScriptMsg::WakeUp => {},
622        }
623    }
624
625    fn handle_mixed_message(&self, msg: MixedMessage, cx: &mut JSContext) -> bool {
626        if self.upcast::<WorkerGlobalScope>().is_closing() {
627            return false;
628        }
629
630        match msg {
631            MixedMessage::Devtools(msg) => match msg {
632                DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, _bool_val) => {},
633                DevtoolScriptControlMsg::Eval(code, id, frame_actor_id, reply) => {
634                    self.debugger_global.fire_eval(
635                        cx,
636                        code.into(),
637                        id,
638                        Some(self.upcast::<WorkerGlobalScope>().worker_id()),
639                        frame_actor_id,
640                        reply,
641                    );
642                },
643                _ => debug!("got an unusable devtools control message inside the worker!"),
644            },
645            MixedMessage::SharedWorker(msg) => {
646                self.handle_script_event(msg, cx);
647            },
648            MixedMessage::Control(SharedWorkerControlMsg::Exit) => {
649                return false;
650            },
651            MixedMessage::Timer => {},
652        }
653
654        true
655    }
656}
657
658impl SharedWorkerGlobalScopeMethods<crate::DomTypeHolder> for SharedWorkerGlobalScope {
659    /// <https://html.spec.whatwg.org/multipage/#dom-sharedworkerglobalscope-name>
660    fn Name(&self) -> DOMString {
661        // The name getter steps are to return this's name.
662        // Its value represents the name that can be used to obtain a reference to the worker using the SharedWorker constructor.
663        self.workerglobalscope.worker_name()
664    }
665
666    /// <https://html.spec.whatwg.org/multipage/#dom-sharedworkerglobalscope-close>
667    fn Close(&self) {
668        // The close() method steps are to close a worker given this.
669        self.upcast::<WorkerGlobalScope>().close()
670    }
671
672    // <https://html.spec.whatwg.org/multipage/#handler-sharedworkerglobalscope-onconnect>
673    event_handler!(connect, GetOnconnect, SetOnconnect);
674}