Serenity Operating System
1/*
2 * Copyright (c) 2022, Ben Abraham <ben.d.abraham@gmail.com>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <AK/RefCounted.h>
10#include <AK/URLParser.h>
11#include <LibJS/Interpreter.h>
12#include <LibWeb/Bindings/MainThreadVM.h>
13#include <LibWeb/Forward.h>
14#include <LibWeb/HTML/MessageEvent.h>
15#include <LibWeb/HTML/MessagePort.h>
16#include <LibWeb/HTML/Scripting/ClassicScript.h>
17#include <LibWeb/HTML/Scripting/WindowEnvironmentSettingsObject.h>
18#include <LibWeb/HTML/Scripting/WorkerEnvironmentSettingsObject.h>
19#include <LibWeb/HTML/WorkerDebugConsoleClient.h>
20#include <LibWeb/Loader/ResourceLoader.h>
21
22#define ENUMERATE_WORKER_EVENT_HANDLERS(E) \
23 E(onmessage, HTML::EventNames::message) \
24 E(onmessageerror, HTML::EventNames::messageerror)
25
26namespace Web::HTML {
27
28struct WorkerOptions {
29 String type { "classic"_string.release_value_but_fixme_should_propagate_errors() };
30 String credentials { "same-origin"_string.release_value_but_fixme_should_propagate_errors() };
31 String name { String {} };
32};
33
34// https://html.spec.whatwg.org/multipage/workers.html#dedicated-workers-and-the-worker-interface
35class Worker : public DOM::EventTarget {
36 WEB_PLATFORM_OBJECT(Worker, DOM::EventTarget);
37
38public:
39 static WebIDL::ExceptionOr<JS::NonnullGCPtr<Worker>> create(String const& script_url, WorkerOptions const options, DOM::Document& document);
40 static WebIDL::ExceptionOr<JS::NonnullGCPtr<Worker>> construct_impl(JS::Realm& realm, String const& script_url, WorkerOptions const options)
41 {
42 auto& window = verify_cast<HTML::Window>(realm.global_object());
43 return Worker::create(script_url, options, window.associated_document());
44 }
45
46 WebIDL::ExceptionOr<void> terminate();
47
48 void post_message(JS::Value message, JS::Value transfer);
49
50 virtual ~Worker() = default;
51
52 MessagePort* implicit_message_port() { return m_implicit_port.ptr(); }
53 JS::GCPtr<MessagePort> outside_message_port() { return m_outside_port; }
54
55#undef __ENUMERATE
56#define __ENUMERATE(attribute_name, event_name) \
57 void set_##attribute_name(WebIDL::CallbackType*); \
58 WebIDL::CallbackType* attribute_name();
59 ENUMERATE_WORKER_EVENT_HANDLERS(__ENUMERATE)
60#undef __ENUMERATE
61
62protected:
63 Worker(String const&, const WorkerOptions, DOM::Document&);
64
65private:
66 static HTML::EventLoop& get_vm_event_loop(JS::VM& target_vm)
67 {
68 return static_cast<Bindings::WebEngineCustomData*>(target_vm.custom_data())->event_loop;
69 }
70
71 virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override;
72 virtual void visit_edges(Cell::Visitor&) override;
73
74 String m_script_url;
75 WorkerOptions m_options;
76
77 JS::GCPtr<DOM::Document> m_document;
78
79 Bindings::WebEngineCustomData m_custom_data;
80
81 NonnullRefPtr<JS::VM> m_worker_vm;
82 NonnullOwnPtr<JS::Interpreter> m_interpreter;
83 JS::GCPtr<WorkerEnvironmentSettingsObject> m_inner_settings;
84 JS::VM::InterpreterExecutionScope m_interpreter_scope;
85 RefPtr<WorkerDebugConsoleClient> m_console;
86
87 JS::NonnullGCPtr<MessagePort> m_implicit_port;
88 JS::GCPtr<MessagePort> m_outside_port;
89
90 // NOTE: These are inside the worker VM.
91 JS::GCPtr<JS::Realm> m_worker_realm;
92 JS::GCPtr<JS::Object> m_worker_scope;
93
94 void run_a_worker(AK::URL& url, EnvironmentSettingsObject& outside_settings, MessagePort& outside_port, WorkerOptions const& options);
95};
96
97}