mirror of
https://github.com/RGBCube/serenity
synced 2025-06-30 10:22:13 +00:00
LibWeb+WebWorker: Convert Workers to use MessagePorts for postMessage
This aligns Workers and Window and MessagePorts to all use the same mechanism for transferring serialized messages across realms. It also allows transferring more message ports into a worker. Re-enable the Worker-echo test, as none of the MessagePort tests have themselves been flaky, and those are now using the same underlying implementation.
This commit is contained in:
parent
37f2d49818
commit
b10fee00eb
21 changed files with 159 additions and 222 deletions
|
@ -4,26 +4,24 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Array.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibWeb/Bindings/DedicatedWorkerExposedInterfaces.h>
|
||||
#include <LibWeb/Bindings/Intrinsics.h>
|
||||
#include <LibWeb/Bindings/WorkerGlobalScopePrototype.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/HTML/EventHandler.h>
|
||||
#include <LibWeb/HTML/EventNames.h>
|
||||
#include <LibWeb/HTML/MessageEvent.h>
|
||||
#include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
|
||||
#include <LibWeb/HTML/StructuredSerialize.h>
|
||||
#include <LibWeb/HTML/WorkerGlobalScope.h>
|
||||
#include <LibWeb/HTML/WorkerLocation.h>
|
||||
#include <LibWeb/HTML/WorkerNavigator.h>
|
||||
#include <LibWeb/Page/Page.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
||||
JS_DEFINE_ALLOCATOR(WorkerGlobalScope);
|
||||
|
||||
WorkerGlobalScope::WorkerGlobalScope(JS::Realm& realm, Web::Page& page)
|
||||
WorkerGlobalScope::WorkerGlobalScope(JS::Realm& realm, JS::NonnullGCPtr<Web::Page> page)
|
||||
: DOM::EventTarget(realm)
|
||||
, m_page(page)
|
||||
{
|
||||
|
@ -53,55 +51,14 @@ void WorkerGlobalScope::visit_edges(Cell::Visitor& visitor)
|
|||
|
||||
visitor.visit(m_location);
|
||||
visitor.visit(m_navigator);
|
||||
visitor.visit(m_internal_port);
|
||||
visitor.visit(m_page);
|
||||
}
|
||||
|
||||
void WorkerGlobalScope::set_outside_port(NonnullOwnPtr<Core::BufferedLocalSocket> port)
|
||||
void WorkerGlobalScope::set_internal_port(JS::NonnullGCPtr<MessagePort> port)
|
||||
{
|
||||
m_outside_port = move(port);
|
||||
|
||||
// FIXME: Hide this logic in MessagePort
|
||||
m_outside_port->set_notifications_enabled(true);
|
||||
m_outside_port->on_ready_to_read = [this] {
|
||||
auto& vm = this->vm();
|
||||
auto& realm = this->realm();
|
||||
|
||||
auto num_bytes_ready = MUST(m_outside_port->pending_bytes());
|
||||
switch (m_outside_port_state) {
|
||||
case PortState::Header: {
|
||||
if (num_bytes_ready < 8)
|
||||
break;
|
||||
auto const magic = MUST(m_outside_port->read_value<u32>());
|
||||
if (magic != 0xDEADBEEF) {
|
||||
m_outside_port_state = PortState::Error;
|
||||
break;
|
||||
}
|
||||
m_outside_port_incoming_message_size = MUST(m_outside_port->read_value<u32>());
|
||||
num_bytes_ready -= 8;
|
||||
m_outside_port_state = PortState::Data;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case PortState::Data: {
|
||||
if (num_bytes_ready < m_outside_port_incoming_message_size)
|
||||
break;
|
||||
SerializationRecord rec; // FIXME: Keep in class scope
|
||||
rec.resize(m_outside_port_incoming_message_size / sizeof(u32));
|
||||
MUST(m_outside_port->read_until_filled(to_bytes(rec.span())));
|
||||
|
||||
TemporaryExecutionContext cxt(relevant_settings_object(*this));
|
||||
MessageEventInit event_init {};
|
||||
event_init.data = MUST(structured_deserialize(vm, rec, realm, {}));
|
||||
// FIXME: Fill in the rest of the info from MessagePort
|
||||
|
||||
this->dispatch_event(MessageEvent::create(realm, EventNames::message, event_init));
|
||||
|
||||
m_outside_port_state = PortState::Header;
|
||||
break;
|
||||
}
|
||||
case PortState::Error:
|
||||
VERIFY_NOT_REACHED();
|
||||
break;
|
||||
}
|
||||
};
|
||||
m_internal_port = port;
|
||||
m_internal_port->set_worker_event_target(*this);
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/workers.html#importing-scripts-and-libraries
|
||||
|
@ -146,23 +103,9 @@ JS::NonnullGCPtr<WorkerNavigator> WorkerGlobalScope::navigator() const
|
|||
return *m_navigator;
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<void> WorkerGlobalScope::post_message(JS::Value message, JS::Value)
|
||||
WebIDL::ExceptionOr<void> WorkerGlobalScope::post_message(JS::Value message, StructuredSerializeOptions const& options)
|
||||
{
|
||||
auto& realm = this->realm();
|
||||
auto& vm = this->vm();
|
||||
|
||||
// FIXME: Use the with-transfer variant, which should(?) prepend the magic + size at the front
|
||||
auto data = TRY(structured_serialize(vm, message));
|
||||
|
||||
Array<u32, 2> header = { 0xDEADBEEF, static_cast<u32>(data.size() * sizeof(u32)) };
|
||||
|
||||
if (auto const err = m_outside_port->write_until_depleted(to_readonly_bytes(header.span())); err.is_error())
|
||||
return WebIDL::DataCloneError::create(realm, TRY_OR_THROW_OOM(vm, String::formatted("{}", err.error())));
|
||||
|
||||
if (auto const err = m_outside_port->write_until_depleted(to_readonly_bytes(data.span())); err.is_error())
|
||||
return WebIDL::DataCloneError::create(realm, TRY_OR_THROW_OOM(vm, String::formatted("{}", err.error())));
|
||||
|
||||
return {};
|
||||
return m_internal_port->post_message(message, options);
|
||||
}
|
||||
|
||||
#undef __ENUMERATE
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue