// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// @ts-check
///
///
///
///
import { core, primordials } from "ext:core/mod.js";
import {
op_message_port_create_entangled,
op_message_port_post_message,
op_message_port_recv_message,
} from "ext:core/ops";
const {
ArrayBufferPrototypeGetByteLength,
ArrayPrototypeFilter,
ArrayPrototypeIncludes,
ArrayPrototypePush,
ObjectPrototypeIsPrototypeOf,
ObjectDefineProperty,
Symbol,
SymbolFor,
SymbolIterator,
PromiseResolve,
SafeArrayIterator,
TypeError,
} = primordials;
const {
InterruptedPrototype,
isArrayBuffer,
} = core;
import * as webidl from "ext:deno_webidl/00_webidl.js";
import { createFilteredInspectProxy } from "ext:deno_console/01_console.js";
import {
defineEventHandler,
EventTarget,
MessageEvent,
setEventTargetData,
setIsTrusted,
} from "./02_event.js";
import { isDetachedBuffer } from "./06_streams.js";
import { DOMException } from "./01_dom_exception.js";
// counter of how many message ports are actively refed
// either due to the existence of "message" event listeners or
// explicit calls to ref/unref (in the case of node message ports)
let refedMessagePortsCount = 0;
class MessageChannel {
/** @type {MessagePort} */
#port1;
/** @type {MessagePort} */
#port2;
constructor() {
this[webidl.brand] = webidl.brand;
const { 0: port1Id, 1: port2Id } = opCreateEntangledMessagePort();
const port1 = createMessagePort(port1Id);
const port2 = createMessagePort(port2Id);
this.#port1 = port1;
this.#port2 = port2;
}
get port1() {
webidl.assertBranded(this, MessageChannelPrototype);
return this.#port1;
}
get port2() {
webidl.assertBranded(this, MessageChannelPrototype);
return this.#port2;
}
[SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) {
return inspect(
createFilteredInspectProxy({
object: this,
evaluate: ObjectPrototypeIsPrototypeOf(MessageChannelPrototype, this),
keys: [
"port1",
"port2",
],
}),
inspectOptions,
);
}
}
webidl.configureInterface(MessageChannel);
const MessageChannelPrototype = MessageChannel.prototype;
const _id = Symbol("id");
const MessagePortIdSymbol = _id;
const MessagePortReceiveMessageOnPortSymbol = Symbol(
"MessagePortReceiveMessageOnPort",
);
const _enabled = Symbol("enabled");
const _refed = Symbol("refed");
const _messageEventListenerCount = Symbol("messageEventListenerCount");
const nodeWorkerThreadCloseCb = Symbol("nodeWorkerThreadCloseCb");
const nodeWorkerThreadCloseCbInvoked = Symbol("nodeWorkerThreadCloseCbInvoked");
export const refMessagePort = Symbol("refMessagePort");
/** It is used by 99_main.js and worker_threads to
* unref/ref on the global pollForMessages promise. */
export const unrefPollForMessages = Symbol("unrefPollForMessages");
/**
* @param {number} id
* @returns {MessagePort}
*/
function createMessagePort(id) {
const port = webidl.createBranded(MessagePort);
port[core.hostObjectBrand] = core.hostObjectBrand;
setEventTargetData(port);
port[_id] = id;
port[_enabled] = false;
port[_messageEventListenerCount] = 0;
port[_refed] = false;
return port;
}
function nodeWorkerThreadMaybeInvokeCloseCb(port) {
if (
typeof port[nodeWorkerThreadCloseCb] == "function" &&
!port[nodeWorkerThreadCloseCbInvoked]
) {
port[nodeWorkerThreadCloseCb]();
port[nodeWorkerThreadCloseCbInvoked] = true;
}
}
const _isRefed = Symbol("isRefed");
const _dataPromise = Symbol("dataPromise");
class MessagePort extends EventTarget {
/** @type {number | null} */
[_id] = null;
/** @type {boolean} */
[_enabled] = false;
[_refed] = false;
/** @type {Promise | undefined} */
[_dataPromise] = undefined;
[_messageEventListenerCount] = 0;
constructor() {
super();
ObjectDefineProperty(this, MessagePortReceiveMessageOnPortSymbol, {
__proto__: null,
value: false,
enumerable: false,
});
ObjectDefineProperty(this, nodeWorkerThreadCloseCb, {
__proto__: null,
value: null,
enumerable: false,
});
ObjectDefineProperty(this, nodeWorkerThreadCloseCbInvoked, {
__proto__: null,
value: false,
enumerable: false,
});
webidl.illegalConstructor();
}
/**
* @param {any} message
* @param {object[] | StructuredSerializeOptions} transferOrOptions
*/
postMessage(message, transferOrOptions = { __proto__: null }) {
webidl.assertBranded(this, MessagePortPrototype);
const prefix = "Failed to execute 'postMessage' on 'MessagePort'";
webidl.requiredArguments(arguments.length, 1, prefix);
message = webidl.converters.any(message);
let options;
if (
webidl.type(transferOrOptions) === "Object" &&
transferOrOptions !== undefined &&
transferOrOptions[SymbolIterator] !== undefined
) {
const transfer = webidl.converters["sequence