Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib: add EventTarget-related browser globals #35496

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
worker: make MessageEvent class more Web-compatible
  • Loading branch information
addaleax committed Oct 4, 2020
commit f07229ff3646017ae1ebd3105053626e170e146d
57 changes: 53 additions & 4 deletions lib/internal/worker/io.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const {
ObjectAssign,
ObjectCreate,
ObjectDefineProperty,
ObjectDefineProperties,
ObjectGetOwnPropertyDescriptors,
ObjectGetPrototypeOf,
ObjectSetPrototypeOf,
Expand All @@ -21,7 +22,8 @@ const {
drainMessagePort,
moveMessagePortToContext,
receiveMessageOnPort: receiveMessageOnPort_,
stopMessagePort
stopMessagePort,
checkMessagePort
} = internalBinding('messaging');
const {
getEnvMessagePort
Expand All @@ -38,12 +40,20 @@ const {
kRemoveListener,
} = require('internal/event_target');
const { inspect } = require('internal/util/inspect');
const {
ERR_INVALID_ARG_TYPE
} = require('internal/errors').codes;

const kData = Symbol('kData');
const kIncrementsPortRef = Symbol('kIncrementsPortRef');
const kLastEventId = Symbol('kLastEventId');
const kName = Symbol('kName');
const kOrigin = Symbol('kOrigin');
const kPort = Symbol('kPort');
const kPorts = Symbol('kPorts');
const kWaitingStreams = Symbol('kWaitingStreams');
const kWritableCallbacks = Symbol('kWritableCallbacks');
const kSource = Symbol('kSource');
const kStartedReading = Symbol('kStartedReading');
const kStdioWantsMoreDataCallback = Symbol('kStdioWantsMoreDataCallback');

Expand Down Expand Up @@ -72,19 +82,57 @@ ObjectSetPrototypeOf(MessagePort.prototype, NodeEventTarget.prototype);
MessagePort.prototype.ref = MessagePortPrototype.ref;
MessagePort.prototype.unref = MessagePortPrototype.unref;

function validateMessagePort(port, name) {
if (!checkMessagePort(port))
throw new ERR_INVALID_ARG_TYPE(name, 'MessagePort', port);
}

class MessageEvent extends Event {
constructor(data, target, type) {
constructor(type, {
data = null,
origin = '',
lastEventId = '',
source = null,
ports = [],
} = {}) {
super(type);
this.data = data;
this[kData] = data;
this[kOrigin] = `${origin}`;
this[kLastEventId] = `${lastEventId}`;
this[kSource] = source;
this[kPorts] = [...ports];

if (this[kSource] !== null)
validateMessagePort(this[kSource], 'init.source');
for (let i = 0; i < this[kPorts].length; i++)
validateMessagePort(this[kPorts][i], `init.ports[${i}]`);
}
}

ObjectDefineProperties(MessageEvent.prototype, {
data: {
get() { return this[kData]; }, enumerable: true, configurable: true
},
origin: {
get() { return this[kOrigin]; }, enumerable: true, configurable: true
},
lastEventId: {
get() { return this[kLastEventId]; }, enumerable: true, configurable: true
},
source: {
get() { return this[kSource]; }, enumerable: true, configurable: true
},
ports: {
get() { return this[kPorts]; }, enumerable: true, configurable: true
},
});

ObjectDefineProperty(
MessagePort.prototype,
kCreateEvent,
{
value: function(data, type) {
return new MessageEvent(data, this, type);
return new MessageEvent(type, { data });
},
configurable: false,
writable: false,
Expand Down Expand Up @@ -283,6 +331,7 @@ module.exports = {
moveMessagePortToContext,
MessagePort,
MessageChannel,
MessageEvent,
receiveMessageOnPort,
setupPortReferencing,
ReadableWorkerStdio,
Expand Down
8 changes: 8 additions & 0 deletions src/node_messaging.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1004,6 +1004,12 @@ void MessagePort::Stop(const FunctionCallbackInfo<Value>& args) {
port->Stop();
}

void MessagePort::CheckType(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
args.GetReturnValue().Set(
GetMessagePortConstructorTemplate(env)->HasInstance(args[0]));
}

void MessagePort::Drain(const FunctionCallbackInfo<Value>& args) {
MessagePort* port;
ASSIGN_OR_RETURN_UNWRAP(&port, args[0].As<Object>());
Expand Down Expand Up @@ -1339,6 +1345,7 @@ static void InitMessaging(Local<Object> target,
// These are not methods on the MessagePort prototype, because
// the browser equivalents do not provide them.
env->SetMethod(target, "stopMessagePort", MessagePort::Stop);
env->SetMethod(target, "checkMessagePort", MessagePort::CheckType);
env->SetMethod(target, "drainMessagePort", MessagePort::Drain);
env->SetMethod(target, "receiveMessageOnPort", MessagePort::ReceiveMessage);
env->SetMethod(target, "moveMessagePortToContext",
Expand All @@ -1363,6 +1370,7 @@ static void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(MessagePort::PostMessage);
registry->Register(MessagePort::Start);
registry->Register(MessagePort::Stop);
registry->Register(MessagePort::CheckType);
registry->Register(MessagePort::Drain);
registry->Register(MessagePort::ReceiveMessage);
registry->Register(MessagePort::MoveToContext);
Expand Down
1 change: 1 addition & 0 deletions src/node_messaging.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ class MessagePort : public HandleWrap {
static void PostMessage(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Start(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Stop(const v8::FunctionCallbackInfo<v8::Value>& args);
static void CheckType(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Drain(const v8::FunctionCallbackInfo<v8::Value>& args);
static void ReceiveMessage(const v8::FunctionCallbackInfo<v8::Value>& args);

Expand Down
92 changes: 92 additions & 0 deletions test/parallel/test-worker-message-event.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Flags: --expose-internals
'use strict';
require('../common');
const assert = require('assert');
const { MessageEvent, MessageChannel } = require('internal/worker/io');

const dummyPort = new MessageChannel().port1;

{
for (const [ args, expected ] of [
[
['message'],
{
type: 'message', data: null, origin: '',
lastEventId: '', source: null, ports: []
}
],
[
['message', { data: undefined, origin: 'foo' }],
{
type: 'message', data: null, origin: 'foo',
lastEventId: '', source: null, ports: []
}
],
[
['message', { data: 2, origin: 1, lastEventId: 0 }],
{
type: 'message', data: 2, origin: '1',
lastEventId: '0', source: null, ports: []
}
],
[
['message', { lastEventId: 'foo' }],
{
type: 'message', data: null, origin: '',
lastEventId: 'foo', source: null, ports: []
}
],
[
['messageerror', { lastEventId: 'foo', source: dummyPort }],
{
type: 'messageerror', data: null, origin: '',
lastEventId: 'foo', source: dummyPort, ports: []
}
],
[
['message', { ports: [dummyPort], source: null }],
{
type: 'message', data: null, origin: '',
lastEventId: '', source: null, ports: [dummyPort]
}
],
]) {
const ev = new MessageEvent(...args);
const { type, data, origin, lastEventId, source, ports } = ev;
assert.deepStrictEqual(expected, {
type, data, origin, lastEventId, source, ports
});
}
}

{
assert.throws(() => {
new MessageEvent('message', { source: 1 });
}, {
code: 'ERR_INVALID_ARG_TYPE',
message: /The "init\.source" property must be an instance of MessagePort/,
});
assert.throws(() => {
new MessageEvent('message', { source: {} });
}, {
code: 'ERR_INVALID_ARG_TYPE',
message: /The "init\.source" property must be an instance of MessagePort/,
});
assert.throws(() => {
new MessageEvent('message', { ports: 0 });
}, {
message: /ports is not iterable/,
});
assert.throws(() => {
new MessageEvent('message', { ports: [ null ] });
}, {
code: 'ERR_INVALID_ARG_TYPE',
message: /The "init\.ports\[0\]" property must be an instance of MessagePort/,
});
assert.throws(() => {
new MessageEvent('message', { ports: [ {} ] });
}, {
code: 'ERR_INVALID_ARG_TYPE',
message: /The "init\.ports\[0\]" property must be an instance of MessagePort/,
});
}