-
Notifications
You must be signed in to change notification settings - Fork 331
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
implement MessagePort and MessageChannel
- Loading branch information
Showing
8 changed files
with
267 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
#include "message-channel.h" | ||
|
||
#include <workerd/api/events.h> | ||
#include <workerd/jsg/jsg.h> | ||
|
||
namespace workerd::api { | ||
|
||
MessagePort::~MessagePort() noexcept(false) { | ||
// Technically we should dispatch a close event whenever this object | ||
// is garbage collected. Unfortunately, we cannot guarantee that the destructor | ||
// will always have the isolate lock. | ||
// Let's keep in mind that the destructor might be running during v8 GC | ||
// in which you shouldn't execute any javascript at all. | ||
// dispatchEvent(js, Event::constructor(kj::str("close"), kj::none)); | ||
} | ||
|
||
jsg::Ref<MessagePort> MessagePort::constructor() { | ||
return jsg::alloc<MessagePort>(); | ||
} | ||
|
||
void MessagePort::disentangle(jsg::Lock &js) { | ||
KJ_IF_SOME(e, entangledWith) { | ||
// Fire an event named close at otherPort. | ||
e->dispatchEvent(js, CloseEvent::constructor()); | ||
e->entangledWith = kj::none; | ||
} | ||
entangledWith = kj::none; | ||
} | ||
|
||
void MessagePort::entangle(jsg::Lock &js, jsg::Ref<MessagePort> port) { | ||
disentangle(js); | ||
entangledWith = port.addRef(); | ||
port->entangledWith = JSG_THIS; | ||
} | ||
|
||
void MessagePort::postMessage(jsg::Lock &js, | ||
jsg::Value message, | ||
kj::OneOf<kj::Maybe<StructuredSerializeOptions>, kj::Array<jsg::Value>> options) {} | ||
|
||
void MessagePort::start(jsg::Lock &js) { | ||
// The start() method steps are to enable this's port message queue, if it is not already enabled. | ||
if (messageQueue == kj::none) { | ||
messageQueue = kj::Vector<Message>(); | ||
} | ||
} | ||
|
||
void MessagePort::stop(jsg::Lock &js) {} | ||
|
||
void MessagePort::close(jsg::Lock &js) { | ||
// Set this's [[Detached]] internal slot value to true. | ||
detached = true; | ||
// If this is entangled, disentangle it. | ||
disentangle(js); | ||
// The close event will be fired even if the port is not explicitly closed. | ||
dispatchEvent(js, CloseEvent::constructor()); | ||
} | ||
|
||
MessageChannel::MessageChannel(jsg::Lock &js) | ||
: port1(MessagePort::constructor()), | ||
port2(MessagePort::constructor()) {} | ||
|
||
jsg::Ref<MessageChannel> MessageChannel::constructor(jsg::Lock &js) { | ||
return jsg::alloc<MessageChannel>(js); | ||
} | ||
|
||
} // namespace workerd::api |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// Copyright (c) 2017-2022 Cloudflare, Inc. | ||
// Licensed under the Apache 2.0 license found in the LICENSE file or at: | ||
// https://opensource.org/licenses/Apache-2.0 | ||
|
||
#pragma once | ||
|
||
#include <workerd/api/basics.h> | ||
#include <workerd/jsg/jsg.h> | ||
|
||
#include <kj/array.h> | ||
|
||
namespace workerd::api { | ||
|
||
// Implements MessagePort web-spec | ||
// Ref: https://html.spec.whatwg.org/multipage/web-messaging.html#message-ports | ||
class MessagePort: public EventTarget { | ||
public: | ||
MessagePort() = default; | ||
~MessagePort() noexcept(false); | ||
KJ_DISALLOW_COPY(MessagePort); | ||
|
||
static jsg::Ref<MessagePort> constructor(); | ||
|
||
struct StructuredSerializeOptions { | ||
kj::Array<jsg::Object> transfer{}; | ||
|
||
JSG_STRUCT(transfer); | ||
}; | ||
|
||
void postMessage(jsg::Lock& js, | ||
jsg::Value message, | ||
kj::OneOf<kj::Maybe<StructuredSerializeOptions>, kj::Array<jsg::Value>> options); | ||
void start(jsg::Lock& js); | ||
void stop(jsg::Lock& js); | ||
void close(jsg::Lock& js); | ||
|
||
JSG_RESOURCE_TYPE(MessagePort) { | ||
JSG_NESTED_TYPE(EventTarget); | ||
JSG_METHOD(postMessage); | ||
JSG_METHOD(start); | ||
JSG_METHOD(stop); | ||
JSG_METHOD(close); | ||
} | ||
|
||
// Ref: https://html.spec.whatwg.org/multipage/web-messaging.html#disentangle | ||
void disentangle(jsg::Lock& js); | ||
|
||
// Ref: https://html.spec.whatwg.org/multipage/web-messaging.html#entangle | ||
void entangle(jsg::Lock& js, jsg::Ref<MessagePort> port); | ||
|
||
private: | ||
bool detached = false; | ||
|
||
kj::Maybe<jsg::HashableV8Ref<v8::Object>> onmessage; | ||
kj::Maybe<jsg::HashableV8Ref<v8::Object>> onmessageerror; | ||
|
||
// Each MessagePort object can be entangled with another (a symmetric relationship) | ||
kj::Maybe<jsg::Ref<MessagePort>> entangledWith{}; | ||
|
||
class Message { | ||
public: | ||
Message() = default; | ||
}; | ||
|
||
bool isMessageQueueEnabled() const { | ||
return messageQueue != kj::none; | ||
} | ||
|
||
// Each MessagePort object also has a task source called the port message queue, | ||
// A port message queue can be enabled or disabled, and is initially disabled. | ||
// Once enabled, a port can never be disabled again | ||
kj::Maybe<kj::Vector<Message>> messageQueue{}; | ||
|
||
bool hasBeenShipped = false; | ||
}; | ||
|
||
// Implements MessageChannel web-spec | ||
// Ref: https://html.spec.whatwg.org/multipage/web-messaging.html#message-channels | ||
class MessageChannel: public jsg::Object { | ||
public: | ||
explicit MessageChannel(jsg::Lock& js); | ||
|
||
static jsg::Ref<MessageChannel> constructor(jsg::Lock& js); | ||
|
||
jsg::Ref<MessagePort> getPort1() { | ||
return port1.addRef(); | ||
} | ||
|
||
jsg::Ref<MessagePort> getPort2() { | ||
return port2.addRef(); | ||
} | ||
|
||
JSG_RESOURCE_TYPE(MessageChannel) { | ||
JSG_READONLY_PROTOTYPE_PROPERTY(port1, getPort1); | ||
JSG_READONLY_PROTOTYPE_PROPERTY(port2, getPort2); | ||
} | ||
|
||
void visitForMemoryInfo(jsg::MemoryTracker& tracker) const { | ||
tracker.trackField("port1", port1); | ||
tracker.trackField("port2", port2); | ||
} | ||
|
||
void visitForGc(jsg::GcVisitor& visitor) { | ||
visitor.visit(port1); | ||
visitor.visit(port2); | ||
} | ||
|
||
private: | ||
jsg::Ref<MessagePort> port1; | ||
jsg::Ref<MessagePort> port2; | ||
}; | ||
|
||
#define EW_MESSAGE_CHANNEL_ISOLATE_TYPES \ | ||
api::MessageChannel, api::MessagePort, api::MessagePort::StructuredSerializeOptions | ||
|
||
} // namespace workerd::api |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.