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                // Creating the worker global scope initializes its name (step 8)
383                // and, for shared workers, its type (step 10.3 of run a worker).
384                let global = SharedWorkerGlobalScope::new(
385                    init,
386                    worker_name.into(),
387                    worker_type,
388                    worker_url.url(),
389                    worker,
390                    parent_event_loop_sender,
391                    devtools_mpsc_port,
392                    runtime,
393                    own_sender,
394                    receiver,
395                    closing,
396                    #[cfg(feature = "webgpu")]
397                    gpu_id_hub,
398                    control_receiver,
399                    insecure_requests_policy,
400                    font_context,
401                    &debugger_global,
402                    cx,
403                );
404                let scope = global.upcast::<WorkerGlobalScope>();
405                let global_scope = global.upcast::<GlobalScope>();
406                debugger_global.fire_add_debuggee(cx, global_scope, pipeline_id, Some(worker_id));
407
408                let fetch_client = ModuleFetchClient {
409                    insecure_requests_policy,
410                    has_trustworthy_ancestor_origin: current_global_ancestor_trustworthy,
411                    policy_container,
412                    client: request_client,
413                    pipeline_id,
414                    origin,
415                };
416
417                // Step 11. Let destination be "sharedworker" if is shared is true, and
418                // "worker" otherwise.
419                // Step 12. Obtain script by switching on options["type"]:
420                match worker_type {
421                    WorkerType::Classic => {
422                        fetch_a_classic_worker_script(
423                            scope,
424                            worker_url,
425                            fetch_client,
426                            Destination::SharedWorker,
427                            webview_id,
428                            referrer,
429                        );
430                    },
431                    WorkerType::Module => {
432                        let worker_scope = DomRoot::from_ref(scope);
433                        fetch_a_module_worker_script_graph(
434                            cx,
435                            global_scope,
436                            worker_url.url(),
437                            fetch_client,
438                            Destination::SharedWorker,
439                            referrer,
440                            credentials,
441                            move |cx, module_tree| {
442                                worker_scope.on_complete(cx, module_tree.map(Script::Module));
443                            },
444                        );
445                    },
446                }
447
448                let reporter_name = format!("shared-worker-reporter-{}", worker_id);
449                scope
450                    .upcast::<GlobalScope>()
451                    .mem_profiler_chan()
452                    .run_with_memory_reporting(
453                        || {
454                            // Event loop: Run the responsible event loop specified by inside settings until it is destroyed.
455                            while !scope.is_closing() {
456                                run_worker_event_loop(&*global, None, cx);
457                            }
458                        },
459                        reporter_name,
460                        event_loop_sender,
461                        CommonScriptMsg::CollectReports,
462                    );
463
464                scope.clear_js_runtime();
465            })
466            .expect("Thread spawning failed")
467    }
468
469    pub(crate) fn event_loop_sender(&self) -> ScriptEventLoopSender {
470        ScriptEventLoopSender::SharedWorker(self.own_sender.clone())
471    }
472
473    pub(crate) fn new_script_pair(&self) -> (ScriptEventLoopSender, ScriptEventLoopReceiver) {
474        let (sender, receiver) = unbounded();
475        (
476            ScriptEventLoopSender::SharedWorker(sender),
477            ScriptEventLoopReceiver::SharedWorker(receiver),
478        )
479    }
480
481    /// Step 1.1 of onComplete of <https://html.spec.whatwg.org/multipage/#run-a-worker>
482    pub(crate) fn forward_simple_error_at_worker(&self) {
483        let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
484        let worker = self.worker.borrow().clone().expect("worker must be set");
485        self.parent_event_loop_sender
486            .send(CommonScriptMsg::Task(
487                WorkerEvent,
488                Box::new(SimpleWorkerErrorHandler::new(worker)),
489                Some(pipeline_id),
490                TaskSourceName::DOMManipulation,
491            ))
492            .expect("Sending to parent failed");
493    }
494
495    /// Step 11 of onComplete of <https://html.spec.whatwg.org/multipage/#run-a-worker>
496    pub(crate) fn enable_outside_port_message_queue(&self) {
497        let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
498        let worker = self.worker.borrow().clone().expect("worker must be set");
499
500        self.parent_event_loop_sender
501            .send(CommonScriptMsg::Task(
502                WorkerEvent,
503                Box::new(
504                    task!(sharedworker_enable_outside_port_message_queue: move |cx| {
505                        SharedWorker::enable_outside_port_message_queue(worker, cx);
506                    }),
507                ),
508                Some(pipeline_id),
509                TaskSourceName::DOMManipulation,
510            ))
511            .expect("Sending to parent failed");
512    }
513
514    fn handle_connect(
515        &self,
516        port_impl: MessagePortImpl,
517        cx: &mut JSContext,
518    ) -> DomRoot<MessagePort> {
519        // Let inside port be a new MessagePort object in inside settings's realm.
520        let inside_port = MessagePort::new_transferred(
521            self.upcast::<GlobalScope>(),
522            *port_impl.message_port_id(),
523            port_impl.entangled_port_id(),
524            CanGc::from_cx(cx),
525        );
526        self.upcast::<GlobalScope>()
527            .track_message_port(&inside_port, Some(port_impl));
528        inside_port
529    }
530
531    // Step 13. Queue a global task to fire a connect event.
532    fn dispatch_connect_event(&self, inside_port: &MessagePort) {
533        let worker_global = Trusted::new(self);
534        let inside_port = Trusted::new(inside_port);
535
536        self.upcast::<GlobalScope>()
537            .task_manager()
538            .dom_manipulation_task_source()
539            .queue(task!(sharedworker_connect_event: move |cx| {
540                let worker_global = worker_global.root();
541                let worker_global = &*worker_global;
542                let inside_port = inside_port.root();
543
544                rooted!(&in(cx) let mut data = UndefinedValue());
545                DOMString::from("").safe_to_jsval(
546                    cx.into(),
547                    data.handle_mut(),
548                    CanGc::from_cx(cx),
549                );
550
551                let source = WindowProxyOrMessagePortOrServiceWorker::MessagePort(
552                    inside_port.clone(),
553                );
554                let event = MessageEvent::new(
555                    worker_global.upcast::<GlobalScope>(),
556                    Atom::from("connect"),
557                    false,
558                    false,
559                    data.handle(),
560                    DOMString::from(""),
561                    Some(&source),
562                    DOMString::new(),
563                    vec![inside_port],
564                    CanGc::from_cx(cx),
565                );
566
567                event
568                    .upcast::<Event>()
569                    .fire(worker_global.upcast::<EventTarget>(), CanGc::from_cx(cx));
570            }));
571    }
572
573    pub(crate) fn fire_pending_connect(&self, _cx: &mut JSContext) {
574        let inside_port = self
575            .pending_connect
576            .borrow_mut()
577            .take()
578            .map(|inside_port| inside_port.as_rooted());
579        if let Some(inside_port) = inside_port {
580            if self.upcast::<WorkerGlobalScope>().is_closing() {
581                return;
582            }
583            self.dispatch_connect_event(&inside_port);
584        }
585    }
586
587    fn handle_script_event(&self, msg: SharedWorkerScriptMsg, cx: &mut JSContext) {
588        match msg {
589            SharedWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(msg)) => {
590                self.upcast::<WorkerGlobalScope>().process_event(msg, cx);
591            },
592            SharedWorkerScriptMsg::Connect(port_impl) => {
593                let inside_port = self.handle_connect(port_impl, cx);
594                if self.upcast::<WorkerGlobalScope>().is_execution_ready() {
595                    self.dispatch_connect_event(&inside_port);
596                } else {
597                    let mut pending_connect = self.pending_connect.borrow_mut();
598                    debug_assert!(
599                        pending_connect.is_none(),
600                        "SharedWorkerGlobalScope only expects one pre-ready connect in the current implementation"
601                    );
602                    pending_connect.replace(Dom::from_ref(&*inside_port));
603                }
604            },
605            SharedWorkerScriptMsg::CommonWorker(WorkerScriptMsg::DOMMessage(_)) => {
606                // SharedWorker messages arrive through the entangled MessagePort and are
607                // surfaced as connect/message events, not as direct WorkerScriptMsg::DOMMessage.
608                debug_assert!(
609                    false,
610                    "SharedWorkerGlobalScope does not support direct DOMMessage dispatch"
611                );
612            },
613            SharedWorkerScriptMsg::WakeUp => {},
614        }
615    }
616
617    fn handle_mixed_message(&self, msg: MixedMessage, cx: &mut JSContext) -> bool {
618        if self.upcast::<WorkerGlobalScope>().is_closing() {
619            return false;
620        }
621
622        match msg {
623            MixedMessage::Devtools(msg) => match msg {
624                DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, _bool_val) => {},
625                DevtoolScriptControlMsg::Eval(code, id, frame_actor_id, reply) => {
626                    self.debugger_global.fire_eval(
627                        cx,
628                        code.into(),
629                        id,
630                        Some(self.upcast::<WorkerGlobalScope>().worker_id()),
631                        frame_actor_id,
632                        reply,
633                    );
634                },
635                _ => debug!("got an unusable devtools control message inside the worker!"),
636            },
637            MixedMessage::SharedWorker(msg) => {
638                self.handle_script_event(msg, cx);
639            },
640            MixedMessage::Control(SharedWorkerControlMsg::Exit) => {
641                return false;
642            },
643            MixedMessage::Timer => {},
644        }
645
646        true
647    }
648}
649
650impl SharedWorkerGlobalScopeMethods<crate::DomTypeHolder> for SharedWorkerGlobalScope {
651    /// <https://html.spec.whatwg.org/multipage/#dom-sharedworkerglobalscope-name>
652    fn Name(&self) -> DOMString {
653        // The name getter steps are to return this's name.
654        // Its value represents the name that can be used to obtain a reference to the worker using the SharedWorker constructor.
655        self.workerglobalscope.worker_name()
656    }
657
658    /// <https://html.spec.whatwg.org/multipage/#dom-sharedworkerglobalscope-close>
659    fn Close(&self) {
660        // The close() method steps are to close a worker given this.
661        self.upcast::<WorkerGlobalScope>().close()
662    }
663
664    // <https://html.spec.whatwg.org/multipage/#handler-sharedworkerglobalscope-onconnect>
665    event_handler!(connect, GetOnconnect, SetOnconnect);
666}