mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
fix(ext/node): better support for node:diagnostics_channel
module (#24088)
Closes https://github.com/denoland/deno/issues/24060
This commit is contained in:
parent
45b05db843
commit
330896458d
15 changed files with 749 additions and 106 deletions
|
@ -583,7 +583,7 @@ deno_core::extension!(deno_node,
|
||||||
"node:constants" = "constants.ts",
|
"node:constants" = "constants.ts",
|
||||||
"node:crypto" = "crypto.ts",
|
"node:crypto" = "crypto.ts",
|
||||||
"node:dgram" = "dgram.ts",
|
"node:dgram" = "dgram.ts",
|
||||||
"node:diagnostics_channel" = "diagnostics_channel.ts",
|
"node:diagnostics_channel" = "diagnostics_channel.js",
|
||||||
"node:dns" = "dns.ts",
|
"node:dns" = "dns.ts",
|
||||||
"node:dns/promises" = "dns/promises.ts",
|
"node:dns/promises" = "dns/promises.ts",
|
||||||
"node:domain" = "domain.ts",
|
"node:domain" = "domain.ts",
|
||||||
|
|
430
ext/node/polyfills/diagnostics_channel.js
Normal file
430
ext/node/polyfills/diagnostics_channel.js
Normal file
|
@ -0,0 +1,430 @@
|
||||||
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
// TODO(petamoriken): enable prefer-primordials for node polyfills
|
||||||
|
// deno-lint-ignore-file prefer-primordials ban-untagged-todo
|
||||||
|
|
||||||
|
import { ERR_INVALID_ARG_TYPE } from "ext:deno_node/internal/errors.ts";
|
||||||
|
import { validateFunction } from "ext:deno_node/internal/validators.mjs";
|
||||||
|
import { nextTick } from "node:process";
|
||||||
|
import { primordials } from "ext:core/mod.js";
|
||||||
|
|
||||||
|
const {
|
||||||
|
ArrayPrototypeAt,
|
||||||
|
ArrayPrototypeIndexOf,
|
||||||
|
ArrayPrototypePush,
|
||||||
|
ArrayPrototypeSplice,
|
||||||
|
ObjectDefineProperty,
|
||||||
|
ObjectGetPrototypeOf,
|
||||||
|
ObjectSetPrototypeOf,
|
||||||
|
Promise,
|
||||||
|
PromisePrototypeThen,
|
||||||
|
PromiseReject,
|
||||||
|
PromiseResolve,
|
||||||
|
ReflectApply,
|
||||||
|
SafeFinalizationRegistry,
|
||||||
|
SafeMap,
|
||||||
|
SymbolHasInstance,
|
||||||
|
} = primordials;
|
||||||
|
import { WeakReference } from "ext:deno_node/internal/util.mjs";
|
||||||
|
|
||||||
|
// Can't delete when weakref count reaches 0 as it could increment again.
|
||||||
|
// Only GC can be used as a valid time to clean up the channels map.
|
||||||
|
class WeakRefMap extends SafeMap {
|
||||||
|
#finalizers = new SafeFinalizationRegistry((key) => {
|
||||||
|
this.delete(key);
|
||||||
|
});
|
||||||
|
|
||||||
|
set(key, value) {
|
||||||
|
this.#finalizers.register(value, key);
|
||||||
|
return super.set(key, new WeakReference(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
get(key) {
|
||||||
|
return super.get(key)?.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
incRef(key) {
|
||||||
|
return super.get(key)?.incRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
decRef(key) {
|
||||||
|
return super.get(key)?.decRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function markActive(channel) {
|
||||||
|
ObjectSetPrototypeOf(channel, ActiveChannel.prototype);
|
||||||
|
channel._subscribers = [];
|
||||||
|
channel._stores = new SafeMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
function maybeMarkInactive(channel) {
|
||||||
|
// When there are no more active subscribers or bound, restore to fast prototype.
|
||||||
|
if (!channel._subscribers.length && !channel._stores.size) {
|
||||||
|
ObjectSetPrototypeOf(channel, Channel.prototype);
|
||||||
|
channel._subscribers = undefined;
|
||||||
|
channel._stores = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function defaultTransform(data) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function wrapStoreRun(store, data, next, transform = defaultTransform) {
|
||||||
|
return () => {
|
||||||
|
let context;
|
||||||
|
try {
|
||||||
|
context = transform(data);
|
||||||
|
} catch (err) {
|
||||||
|
nextTick(() => {
|
||||||
|
// TODO(bartlomieju): in Node.js this is using `triggerUncaughtException` API, need
|
||||||
|
// to clarify if we need that or if just throwing the error is enough here.
|
||||||
|
throw err;
|
||||||
|
// triggerUncaughtException(err, false);
|
||||||
|
});
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
return store.run(context, next);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class ActiveChannel {
|
||||||
|
subscribe(subscription) {
|
||||||
|
validateFunction(subscription, "subscription");
|
||||||
|
ArrayPrototypePush(this._subscribers, subscription);
|
||||||
|
channels.incRef(this.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsubscribe(subscription) {
|
||||||
|
const index = ArrayPrototypeIndexOf(this._subscribers, subscription);
|
||||||
|
if (index === -1) return false;
|
||||||
|
|
||||||
|
ArrayPrototypeSplice(this._subscribers, index, 1);
|
||||||
|
|
||||||
|
channels.decRef(this.name);
|
||||||
|
maybeMarkInactive(this);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bindStore(store, transform) {
|
||||||
|
const replacing = this._stores.has(store);
|
||||||
|
if (!replacing) channels.incRef(this.name);
|
||||||
|
this._stores.set(store, transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
unbindStore(store) {
|
||||||
|
if (!this._stores.has(store)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._stores.delete(store);
|
||||||
|
|
||||||
|
channels.decRef(this.name);
|
||||||
|
maybeMarkInactive(this);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasSubscribers() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
publish(data) {
|
||||||
|
for (let i = 0; i < (this._subscribers?.length || 0); i++) {
|
||||||
|
try {
|
||||||
|
const onMessage = this._subscribers[i];
|
||||||
|
onMessage(data, this.name);
|
||||||
|
} catch (err) {
|
||||||
|
nextTick(() => {
|
||||||
|
// TODO(bartlomieju): in Node.js this is using `triggerUncaughtException` API, need
|
||||||
|
// to clarify if we need that or if just throwing the error is enough here.
|
||||||
|
throw err;
|
||||||
|
// triggerUncaughtException(err, false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runStores(data, fn, thisArg, ...args) {
|
||||||
|
let run = () => {
|
||||||
|
this.publish(data);
|
||||||
|
return ReflectApply(fn, thisArg, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const entry of this._stores.entries()) {
|
||||||
|
const store = entry[0];
|
||||||
|
const transform = entry[1];
|
||||||
|
run = wrapStoreRun(store, data, run, transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
return run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Channel {
|
||||||
|
constructor(name) {
|
||||||
|
this._subscribers = undefined;
|
||||||
|
this._stores = undefined;
|
||||||
|
this.name = name;
|
||||||
|
|
||||||
|
channels.set(name, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
static [SymbolHasInstance](instance) {
|
||||||
|
const prototype = ObjectGetPrototypeOf(instance);
|
||||||
|
return prototype === Channel.prototype ||
|
||||||
|
prototype === ActiveChannel.prototype;
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribe(subscription) {
|
||||||
|
markActive(this);
|
||||||
|
this.subscribe(subscription);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsubscribe() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bindStore(store, transform) {
|
||||||
|
markActive(this);
|
||||||
|
this.bindStore(store, transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
unbindStore() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasSubscribers() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
publish() {}
|
||||||
|
|
||||||
|
runStores(_data, fn, thisArg, ...args) {
|
||||||
|
return ReflectApply(fn, thisArg, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const channels = new WeakRefMap();
|
||||||
|
|
||||||
|
export function channel(name) {
|
||||||
|
const channel = channels.get(name);
|
||||||
|
if (channel) return channel;
|
||||||
|
|
||||||
|
if (typeof name !== "string" && typeof name !== "symbol") {
|
||||||
|
throw new ERR_INVALID_ARG_TYPE("channel", ["string", "symbol"], name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Channel(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function subscribe(name, subscription) {
|
||||||
|
return channel(name).subscribe(subscription);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function unsubscribe(name, subscription) {
|
||||||
|
return channel(name).unsubscribe(subscription);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasSubscribers(name) {
|
||||||
|
const channel = channels.get(name);
|
||||||
|
if (!channel) return false;
|
||||||
|
|
||||||
|
return channel.hasSubscribers;
|
||||||
|
}
|
||||||
|
|
||||||
|
const traceEvents = [
|
||||||
|
"start",
|
||||||
|
"end",
|
||||||
|
"asyncStart",
|
||||||
|
"asyncEnd",
|
||||||
|
"error",
|
||||||
|
];
|
||||||
|
|
||||||
|
function assertChannel(value, name) {
|
||||||
|
if (!(value instanceof Channel)) {
|
||||||
|
throw new ERR_INVALID_ARG_TYPE(name, ["Channel"], value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function tracingChannelFrom(nameOrChannels, name) {
|
||||||
|
if (typeof nameOrChannels === "string") {
|
||||||
|
return channel(`tracing:${nameOrChannels}:${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof nameOrChannels === "object" && nameOrChannels !== null) {
|
||||||
|
const channel = nameOrChannels[name];
|
||||||
|
assertChannel(channel, `nameOrChannels.${name}`);
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ERR_INVALID_ARG_TYPE("nameOrChannels", [
|
||||||
|
"string",
|
||||||
|
"object",
|
||||||
|
"Channel",
|
||||||
|
], nameOrChannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
class TracingChannel {
|
||||||
|
constructor(nameOrChannels) {
|
||||||
|
for (const eventName of traceEvents) {
|
||||||
|
ObjectDefineProperty(this, eventName, {
|
||||||
|
__proto__: null,
|
||||||
|
value: tracingChannelFrom(nameOrChannels, eventName),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasSubscribers() {
|
||||||
|
return this.start.hasSubscribers ||
|
||||||
|
this.end.hasSubscribers ||
|
||||||
|
this.asyncStart.hasSubscribers ||
|
||||||
|
this.asyncEnd.hasSubscribers ||
|
||||||
|
this.error.hasSubscribers;
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribe(handlers) {
|
||||||
|
for (const name of traceEvents) {
|
||||||
|
if (!handlers[name]) continue;
|
||||||
|
|
||||||
|
this[name]?.subscribe(handlers[name]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsubscribe(handlers) {
|
||||||
|
let done = true;
|
||||||
|
|
||||||
|
for (const name of traceEvents) {
|
||||||
|
if (!handlers[name]) continue;
|
||||||
|
|
||||||
|
if (!this[name]?.unsubscribe(handlers[name])) {
|
||||||
|
done = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
|
traceSync(fn, context = {}, thisArg, ...args) {
|
||||||
|
if (!this.hasSubscribers) {
|
||||||
|
return ReflectApply(fn, thisArg, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { start, end, error } = this;
|
||||||
|
|
||||||
|
return start.runStores(context, () => {
|
||||||
|
try {
|
||||||
|
const result = ReflectApply(fn, thisArg, args);
|
||||||
|
context.result = result;
|
||||||
|
return result;
|
||||||
|
} catch (err) {
|
||||||
|
context.error = err;
|
||||||
|
error.publish(context);
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
end.publish(context);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
tracePromise(fn, context = {}, thisArg, ...args) {
|
||||||
|
if (!this.hasSubscribers) {
|
||||||
|
return ReflectApply(fn, thisArg, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { start, end, asyncStart, asyncEnd, error } = this;
|
||||||
|
|
||||||
|
function reject(err) {
|
||||||
|
context.error = err;
|
||||||
|
error.publish(context);
|
||||||
|
asyncStart.publish(context);
|
||||||
|
// TODO: Is there a way to have asyncEnd _after_ the continuation?
|
||||||
|
asyncEnd.publish(context);
|
||||||
|
return PromiseReject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolve(result) {
|
||||||
|
context.result = result;
|
||||||
|
asyncStart.publish(context);
|
||||||
|
// TODO: Is there a way to have asyncEnd _after_ the continuation?
|
||||||
|
asyncEnd.publish(context);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return start.runStores(context, () => {
|
||||||
|
try {
|
||||||
|
let promise = ReflectApply(fn, thisArg, args);
|
||||||
|
// Convert thenables to native promises
|
||||||
|
if (!(promise instanceof Promise)) {
|
||||||
|
promise = PromiseResolve(promise);
|
||||||
|
}
|
||||||
|
return PromisePrototypeThen(promise, resolve, reject);
|
||||||
|
} catch (err) {
|
||||||
|
context.error = err;
|
||||||
|
error.publish(context);
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
end.publish(context);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
traceCallback(fn, position = -1, context = {}, thisArg, ...args) {
|
||||||
|
if (!this.hasSubscribers) {
|
||||||
|
return ReflectApply(fn, thisArg, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { start, end, asyncStart, asyncEnd, error } = this;
|
||||||
|
|
||||||
|
function wrappedCallback(err, res) {
|
||||||
|
if (err) {
|
||||||
|
context.error = err;
|
||||||
|
error.publish(context);
|
||||||
|
} else {
|
||||||
|
context.result = res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using runStores here enables manual context failure recovery
|
||||||
|
asyncStart.runStores(context, () => {
|
||||||
|
try {
|
||||||
|
return ReflectApply(callback, this, arguments);
|
||||||
|
} finally {
|
||||||
|
asyncEnd.publish(context);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const callback = ArrayPrototypeAt(args, position);
|
||||||
|
validateFunction(callback, "callback");
|
||||||
|
ArrayPrototypeSplice(args, position, 1, wrappedCallback);
|
||||||
|
|
||||||
|
return start.runStores(context, () => {
|
||||||
|
try {
|
||||||
|
return ReflectApply(fn, thisArg, args);
|
||||||
|
} catch (err) {
|
||||||
|
context.error = err;
|
||||||
|
error.publish(context);
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
end.publish(context);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function tracingChannel(nameOrChannels) {
|
||||||
|
return new TracingChannel(nameOrChannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
channel,
|
||||||
|
hasSubscribers,
|
||||||
|
subscribe,
|
||||||
|
tracingChannel,
|
||||||
|
unsubscribe,
|
||||||
|
Channel,
|
||||||
|
};
|
|
@ -1,93 +0,0 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
|
||||||
|
|
||||||
// TODO(petamoriken): enable prefer-primordials for node polyfills
|
|
||||||
// deno-lint-ignore-file prefer-primordials
|
|
||||||
|
|
||||||
import { ERR_INVALID_ARG_TYPE } from "ext:deno_node/internal/errors.ts";
|
|
||||||
import { validateFunction } from "ext:deno_node/internal/validators.mjs";
|
|
||||||
import { nextTick } from "node:process";
|
|
||||||
|
|
||||||
type Subscriber = (message: unknown, name?: string) => void;
|
|
||||||
|
|
||||||
export class Channel {
|
|
||||||
_subscribers: Subscriber[];
|
|
||||||
name: string;
|
|
||||||
constructor(name: string) {
|
|
||||||
this._subscribers = [];
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
publish(message: unknown) {
|
|
||||||
for (const subscriber of this._subscribers) {
|
|
||||||
try {
|
|
||||||
subscriber(message, this.name);
|
|
||||||
} catch (err) {
|
|
||||||
nextTick(() => {
|
|
||||||
throw err;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
subscribe(subscription: Subscriber) {
|
|
||||||
validateFunction(subscription, "subscription");
|
|
||||||
|
|
||||||
this._subscribers.push(subscription);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsubscribe(subscription: Subscriber) {
|
|
||||||
if (!this._subscribers.includes(subscription)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._subscribers.splice(this._subscribers.indexOf(subscription), 1);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
get hasSubscribers() {
|
|
||||||
return this._subscribers.length > 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const channels: Record<string, Channel> = {};
|
|
||||||
|
|
||||||
export function channel(name: string) {
|
|
||||||
if (typeof name !== "string" && typeof name !== "symbol") {
|
|
||||||
throw new ERR_INVALID_ARG_TYPE("channel", ["string", "symbol"], name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Object.hasOwn(channels, name)) {
|
|
||||||
channels[name] = new Channel(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return channels[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function hasSubscribers(name: string) {
|
|
||||||
if (!Object.hasOwn(channels, name)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return channels[name].hasSubscribers;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function subscribe(name: string, subscription: Subscriber) {
|
|
||||||
const c = channel(name);
|
|
||||||
|
|
||||||
return c.subscribe(subscription);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unsubscribe(name: string, subscription: Subscriber) {
|
|
||||||
const c = channel(name);
|
|
||||||
|
|
||||||
return c.unsubscribe(subscription);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
channel,
|
|
||||||
hasSubscribers,
|
|
||||||
subscribe,
|
|
||||||
unsubscribe,
|
|
||||||
Channel,
|
|
||||||
};
|
|
|
@ -349,9 +349,8 @@ export class NodeErrorAbstraction extends Error {
|
||||||
super(message);
|
super(message);
|
||||||
this.code = code;
|
this.code = code;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
//This number changes depending on the name of this class
|
this.stack = this.stack &&
|
||||||
//20 characters as of now
|
`${name} [${this.code}]${this.stack.slice(this.name.length)}`;
|
||||||
this.stack = this.stack && `${name} [${this.code}]${this.stack.slice(20)}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override toString() {
|
override toString() {
|
||||||
|
@ -614,7 +613,6 @@ export class ERR_INVALID_ARG_TYPE_RANGE extends NodeRangeError {
|
||||||
export class ERR_INVALID_ARG_TYPE extends NodeTypeError {
|
export class ERR_INVALID_ARG_TYPE extends NodeTypeError {
|
||||||
constructor(name: string, expected: string | string[], actual: unknown) {
|
constructor(name: string, expected: string | string[], actual: unknown) {
|
||||||
const msg = createInvalidArgType(name, expected);
|
const msg = createInvalidArgType(name, expected);
|
||||||
|
|
||||||
super("ERR_INVALID_ARG_TYPE", `${msg}.${invalidArgTypeHelper(actual)}`);
|
super("ERR_INVALID_ARG_TYPE", `${msg}.${invalidArgTypeHelper(actual)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,10 @@ import {
|
||||||
} from "ext:deno_node/internal/primordials.mjs";
|
} from "ext:deno_node/internal/primordials.mjs";
|
||||||
import { ERR_UNKNOWN_SIGNAL } from "ext:deno_node/internal/errors.ts";
|
import { ERR_UNKNOWN_SIGNAL } from "ext:deno_node/internal/errors.ts";
|
||||||
import { os } from "ext:deno_node/internal_binding/constants.ts";
|
import { os } from "ext:deno_node/internal_binding/constants.ts";
|
||||||
|
import { primordials } from "ext:core/mod.js";
|
||||||
|
const {
|
||||||
|
SafeWeakRef,
|
||||||
|
} = primordials;
|
||||||
|
|
||||||
export const customInspectSymbol = Symbol.for("nodejs.util.inspect.custom");
|
export const customInspectSymbol = Symbol.for("nodejs.util.inspect.custom");
|
||||||
export const kEnumerableProperty = Object.create(null);
|
export const kEnumerableProperty = Object.create(null);
|
||||||
|
@ -135,6 +139,38 @@ export function convertToValidSignal(signal) {
|
||||||
throw new ERR_UNKNOWN_SIGNAL(signal);
|
throw new ERR_UNKNOWN_SIGNAL(signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class WeakReference {
|
||||||
|
#weak = null;
|
||||||
|
#strong = null;
|
||||||
|
#refCount = 0;
|
||||||
|
constructor(object) {
|
||||||
|
this.#weak = new SafeWeakRef(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
incRef() {
|
||||||
|
this.#refCount++;
|
||||||
|
if (this.#refCount === 1) {
|
||||||
|
const derefed = this.#weak.deref();
|
||||||
|
if (derefed !== undefined) {
|
||||||
|
this.#strong = derefed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.#refCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
decRef() {
|
||||||
|
this.#refCount--;
|
||||||
|
if (this.#refCount === 0) {
|
||||||
|
this.#strong = null;
|
||||||
|
}
|
||||||
|
return this.#refCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
get() {
|
||||||
|
return this.#weak.deref();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
promisify.custom = kCustomPromisifiedSymbol;
|
promisify.custom = kCustomPromisifiedSymbol;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
|
@ -261,9 +261,16 @@
|
||||||
"test-dgram-close-during-bind.js",
|
"test-dgram-close-during-bind.js",
|
||||||
"test-dgram-close-signal.js",
|
"test-dgram-close-signal.js",
|
||||||
"test-diagnostics-channel-has-subscribers.js",
|
"test-diagnostics-channel-has-subscribers.js",
|
||||||
|
"test-diagnostics-channel-net.js",
|
||||||
"test-diagnostics-channel-object-channel-pub-sub.js",
|
"test-diagnostics-channel-object-channel-pub-sub.js",
|
||||||
"test-diagnostics-channel-pub-sub.js",
|
"test-diagnostics-channel-pub-sub.js",
|
||||||
"test-diagnostics-channel-symbol-named.js",
|
"test-diagnostics-channel-symbol-named.js",
|
||||||
|
"test-diagnostics-channel-sync-unsubscribe.js",
|
||||||
|
"test-diagnostics-channel-tracing-channel-args-types.js",
|
||||||
|
"test-diagnostics-channel-tracing-channel-callback-run-stores.js",
|
||||||
|
"test-diagnostics-channel-tracing-channel-promise-run-stores.js",
|
||||||
|
"test-diagnostics-channel-tracing-channel-sync-error.js",
|
||||||
|
"test-diagnostics-channel-tracing-channel-sync.js",
|
||||||
"test-diagnostics-channel-udp.js",
|
"test-diagnostics-channel-udp.js",
|
||||||
"test-dns-lookup.js",
|
"test-dns-lookup.js",
|
||||||
"test-dns-memory-error.js",
|
"test-dns-memory-error.js",
|
||||||
|
|
|
@ -628,18 +628,11 @@ NOTE: This file should not be manually edited. Please edit `tests/node_compat/co
|
||||||
- [parallel/test-diagnostics-channel-http-server-start.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-http-server-start.js)
|
- [parallel/test-diagnostics-channel-http-server-start.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-http-server-start.js)
|
||||||
- [parallel/test-diagnostics-channel-http.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-http.js)
|
- [parallel/test-diagnostics-channel-http.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-http.js)
|
||||||
- [parallel/test-diagnostics-channel-memory-leak.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-memory-leak.js)
|
- [parallel/test-diagnostics-channel-memory-leak.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-memory-leak.js)
|
||||||
- [parallel/test-diagnostics-channel-net.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-net.js)
|
|
||||||
- [parallel/test-diagnostics-channel-process.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-process.js)
|
- [parallel/test-diagnostics-channel-process.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-process.js)
|
||||||
- [parallel/test-diagnostics-channel-safe-subscriber-errors.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-safe-subscriber-errors.js)
|
- [parallel/test-diagnostics-channel-safe-subscriber-errors.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-safe-subscriber-errors.js)
|
||||||
- [parallel/test-diagnostics-channel-sync-unsubscribe.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-sync-unsubscribe.js)
|
|
||||||
- [parallel/test-diagnostics-channel-tracing-channel-args-types.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-tracing-channel-args-types.js)
|
|
||||||
- [parallel/test-diagnostics-channel-tracing-channel-async-error.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-tracing-channel-async-error.js)
|
- [parallel/test-diagnostics-channel-tracing-channel-async-error.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-tracing-channel-async-error.js)
|
||||||
- [parallel/test-diagnostics-channel-tracing-channel-async.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-tracing-channel-async.js)
|
- [parallel/test-diagnostics-channel-tracing-channel-async.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-tracing-channel-async.js)
|
||||||
- [parallel/test-diagnostics-channel-tracing-channel-callback-run-stores.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-tracing-channel-callback-run-stores.js)
|
|
||||||
- [parallel/test-diagnostics-channel-tracing-channel-promise-run-stores.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-tracing-channel-promise-run-stores.js)
|
|
||||||
- [parallel/test-diagnostics-channel-tracing-channel-run-stores.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-tracing-channel-run-stores.js)
|
- [parallel/test-diagnostics-channel-tracing-channel-run-stores.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-tracing-channel-run-stores.js)
|
||||||
- [parallel/test-diagnostics-channel-tracing-channel-sync-error.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-tracing-channel-sync-error.js)
|
|
||||||
- [parallel/test-diagnostics-channel-tracing-channel-sync.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-tracing-channel-sync.js)
|
|
||||||
- [parallel/test-diagnostics-channel-worker-threads.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-worker-threads.js)
|
- [parallel/test-diagnostics-channel-worker-threads.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-diagnostics-channel-worker-threads.js)
|
||||||
- [parallel/test-directory-import.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-directory-import.js)
|
- [parallel/test-directory-import.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-directory-import.js)
|
||||||
- [parallel/test-disable-proto-delete.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-disable-proto-delete.js)
|
- [parallel/test-disable-proto-delete.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-disable-proto-delete.js)
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
// deno-fmt-ignore-file
|
||||||
|
// deno-lint-ignore-file
|
||||||
|
|
||||||
|
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
|
||||||
|
// Taken from Node 18.12.1
|
||||||
|
// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually.
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
const common = require('../common');
|
||||||
|
const assert = require('assert');
|
||||||
|
const net = require('net');
|
||||||
|
const dc = require('diagnostics_channel');
|
||||||
|
|
||||||
|
const isNetSocket = (socket) => socket instanceof net.Socket;
|
||||||
|
|
||||||
|
dc.subscribe('net.client.socket', common.mustCall(({ socket }) => {
|
||||||
|
assert.strictEqual(isNetSocket(socket), true);
|
||||||
|
}));
|
||||||
|
|
||||||
|
dc.subscribe('net.server.socket', common.mustCall(({ socket }) => {
|
||||||
|
assert.strictEqual(isNetSocket(socket), true);
|
||||||
|
}));
|
||||||
|
|
||||||
|
const server = net.createServer(common.mustCall((socket) => {
|
||||||
|
socket.destroy();
|
||||||
|
server.close();
|
||||||
|
}));
|
||||||
|
|
||||||
|
server.listen(() => {
|
||||||
|
const { port } = server.address();
|
||||||
|
net.connect(port);
|
||||||
|
});
|
|
@ -0,0 +1,21 @@
|
||||||
|
// deno-fmt-ignore-file
|
||||||
|
// deno-lint-ignore-file
|
||||||
|
|
||||||
|
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
|
||||||
|
// Taken from Node 18.12.1
|
||||||
|
// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually.
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const dc = require('node:diagnostics_channel');
|
||||||
|
|
||||||
|
const channel_name = 'test:channel';
|
||||||
|
const published_data = 'some message';
|
||||||
|
|
||||||
|
const onMessageHandler = common.mustCall(() => dc.unsubscribe(channel_name, onMessageHandler));
|
||||||
|
|
||||||
|
dc.subscribe(channel_name, onMessageHandler);
|
||||||
|
|
||||||
|
// This must not throw.
|
||||||
|
dc.channel(channel_name).publish(published_data);
|
|
@ -0,0 +1,46 @@
|
||||||
|
// deno-fmt-ignore-file
|
||||||
|
// deno-lint-ignore-file
|
||||||
|
|
||||||
|
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
|
||||||
|
// Taken from Node 18.12.1
|
||||||
|
// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually.
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
require('../common');
|
||||||
|
const dc = require('diagnostics_channel');
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
let channel;
|
||||||
|
|
||||||
|
// tracingChannel creating with name
|
||||||
|
channel = dc.tracingChannel('test');
|
||||||
|
assert.strictEqual(channel.start.name, 'tracing:test:start');
|
||||||
|
|
||||||
|
// tracingChannel creating with channels
|
||||||
|
channel = dc.tracingChannel({
|
||||||
|
start: dc.channel('tracing:test:start'),
|
||||||
|
end: dc.channel('tracing:test:end'),
|
||||||
|
asyncStart: dc.channel('tracing:test:asyncStart'),
|
||||||
|
asyncEnd: dc.channel('tracing:test:asyncEnd'),
|
||||||
|
error: dc.channel('tracing:test:error'),
|
||||||
|
});
|
||||||
|
|
||||||
|
// tracingChannel creating without nameOrChannels must throw TypeError
|
||||||
|
assert.throws(() => (channel = dc.tracingChannel(0)), {
|
||||||
|
code: 'ERR_INVALID_ARG_TYPE',
|
||||||
|
name: 'TypeError',
|
||||||
|
message:
|
||||||
|
/The "nameOrChannels" argument must be of type string or an instance of Channel or Object/,
|
||||||
|
});
|
||||||
|
|
||||||
|
// tracingChannel creating without instance of Channel must throw error
|
||||||
|
assert.throws(() => (channel = dc.tracingChannel({ start: '' })), {
|
||||||
|
code: 'ERR_INVALID_ARG_TYPE',
|
||||||
|
message: /The "nameOrChannels\.start" property must be an instance of Channel/,
|
||||||
|
});
|
||||||
|
|
||||||
|
// tracingChannel creating with empty nameOrChannels must throw error
|
||||||
|
assert.throws(() => (channel = dc.tracingChannel({})), {
|
||||||
|
message: /Cannot convert undefined or null to object/,
|
||||||
|
});
|
|
@ -0,0 +1,36 @@
|
||||||
|
// deno-fmt-ignore-file
|
||||||
|
// deno-lint-ignore-file
|
||||||
|
|
||||||
|
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
|
||||||
|
// Taken from Node 18.12.1
|
||||||
|
// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually.
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const { AsyncLocalStorage } = require('async_hooks');
|
||||||
|
const dc = require('diagnostics_channel');
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
const channel = dc.tracingChannel('test');
|
||||||
|
const store = new AsyncLocalStorage();
|
||||||
|
|
||||||
|
const firstContext = { foo: 'bar' };
|
||||||
|
const secondContext = { baz: 'buz' };
|
||||||
|
|
||||||
|
channel.start.bindStore(store, common.mustCall(() => {
|
||||||
|
return firstContext;
|
||||||
|
}));
|
||||||
|
|
||||||
|
channel.asyncStart.bindStore(store, common.mustCall(() => {
|
||||||
|
return secondContext;
|
||||||
|
}));
|
||||||
|
|
||||||
|
assert.strictEqual(store.getStore(), undefined);
|
||||||
|
channel.traceCallback(common.mustCall((cb) => {
|
||||||
|
assert.deepStrictEqual(store.getStore(), firstContext);
|
||||||
|
setImmediate(cb);
|
||||||
|
}), 0, {}, null, common.mustCall(() => {
|
||||||
|
assert.deepStrictEqual(store.getStore(), secondContext);
|
||||||
|
}));
|
||||||
|
assert.strictEqual(store.getStore(), undefined);
|
|
@ -0,0 +1,38 @@
|
||||||
|
// deno-fmt-ignore-file
|
||||||
|
// deno-lint-ignore-file
|
||||||
|
|
||||||
|
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
|
||||||
|
// Taken from Node 18.12.1
|
||||||
|
// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually.
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const { setTimeout } = require('node:timers/promises');
|
||||||
|
const { AsyncLocalStorage } = require('async_hooks');
|
||||||
|
const dc = require('diagnostics_channel');
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
const channel = dc.tracingChannel('test');
|
||||||
|
const store = new AsyncLocalStorage();
|
||||||
|
|
||||||
|
const firstContext = { foo: 'bar' };
|
||||||
|
const secondContext = { baz: 'buz' };
|
||||||
|
|
||||||
|
channel.start.bindStore(store, common.mustCall(() => {
|
||||||
|
return firstContext;
|
||||||
|
}));
|
||||||
|
|
||||||
|
channel.asyncStart.bindStore(store, common.mustNotCall(() => {
|
||||||
|
return secondContext;
|
||||||
|
}));
|
||||||
|
|
||||||
|
assert.strictEqual(store.getStore(), undefined);
|
||||||
|
channel.tracePromise(common.mustCall(async () => {
|
||||||
|
assert.deepStrictEqual(store.getStore(), firstContext);
|
||||||
|
await setTimeout(1);
|
||||||
|
// Should _not_ switch to second context as promises don't have an "after"
|
||||||
|
// point at which to do a runStores.
|
||||||
|
assert.deepStrictEqual(store.getStore(), firstContext);
|
||||||
|
}));
|
||||||
|
assert.strictEqual(store.getStore(), undefined);
|
|
@ -0,0 +1,46 @@
|
||||||
|
// deno-fmt-ignore-file
|
||||||
|
// deno-lint-ignore-file
|
||||||
|
|
||||||
|
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
|
||||||
|
// Taken from Node 18.12.1
|
||||||
|
// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually.
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const dc = require('diagnostics_channel');
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
const channel = dc.tracingChannel('test');
|
||||||
|
|
||||||
|
const expectedError = new Error('test');
|
||||||
|
const input = { foo: 'bar' };
|
||||||
|
const thisArg = { baz: 'buz' };
|
||||||
|
|
||||||
|
function check(found) {
|
||||||
|
assert.deepStrictEqual(found, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlers = {
|
||||||
|
start: common.mustCall(check),
|
||||||
|
end: common.mustCall(check),
|
||||||
|
asyncStart: common.mustNotCall(),
|
||||||
|
asyncEnd: common.mustNotCall(),
|
||||||
|
error: common.mustCall((found) => {
|
||||||
|
check(found);
|
||||||
|
assert.deepStrictEqual(found.error, expectedError);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
channel.subscribe(handlers);
|
||||||
|
try {
|
||||||
|
channel.traceSync(function(err) {
|
||||||
|
assert.deepStrictEqual(this, thisArg);
|
||||||
|
assert.strictEqual(err, expectedError);
|
||||||
|
throw err;
|
||||||
|
}, input, thisArg, expectedError);
|
||||||
|
|
||||||
|
throw new Error('It should not reach this error');
|
||||||
|
} catch (error) {
|
||||||
|
assert.deepStrictEqual(error, expectedError);
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
// deno-fmt-ignore-file
|
||||||
|
// deno-lint-ignore-file
|
||||||
|
|
||||||
|
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
|
||||||
|
// Taken from Node 18.12.1
|
||||||
|
// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually.
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const dc = require('diagnostics_channel');
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
const channel = dc.tracingChannel('test');
|
||||||
|
|
||||||
|
const expectedResult = { foo: 'bar' };
|
||||||
|
const input = { foo: 'bar' };
|
||||||
|
const thisArg = { baz: 'buz' };
|
||||||
|
const arg = { baz: 'buz' };
|
||||||
|
|
||||||
|
function check(found) {
|
||||||
|
assert.strictEqual(found, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlers = {
|
||||||
|
start: common.mustCall(check),
|
||||||
|
end: common.mustCall((found) => {
|
||||||
|
check(found);
|
||||||
|
assert.strictEqual(found.result, expectedResult);
|
||||||
|
}),
|
||||||
|
asyncStart: common.mustNotCall(),
|
||||||
|
asyncEnd: common.mustNotCall(),
|
||||||
|
error: common.mustNotCall()
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.strictEqual(channel.start.hasSubscribers, false);
|
||||||
|
channel.subscribe(handlers);
|
||||||
|
assert.strictEqual(channel.start.hasSubscribers, true);
|
||||||
|
const result1 = channel.traceSync(function(arg1) {
|
||||||
|
assert.strictEqual(arg1, arg);
|
||||||
|
assert.strictEqual(this, thisArg);
|
||||||
|
return expectedResult;
|
||||||
|
}, input, thisArg, arg);
|
||||||
|
assert.strictEqual(result1, expectedResult);
|
||||||
|
|
||||||
|
channel.unsubscribe(handlers);
|
||||||
|
assert.strictEqual(channel.start.hasSubscribers, false);
|
||||||
|
const result2 = channel.traceSync(function(arg1) {
|
||||||
|
assert.strictEqual(arg1, arg);
|
||||||
|
assert.strictEqual(this, thisArg);
|
||||||
|
return expectedResult;
|
||||||
|
}, input, thisArg, arg);
|
||||||
|
assert.strictEqual(result2, expectedResult);
|
|
@ -66,7 +66,7 @@
|
||||||
"node:constants": "../ext/node/polyfills/constants.ts",
|
"node:constants": "../ext/node/polyfills/constants.ts",
|
||||||
"node:crypto": "../ext/node/polyfills/crypto.ts",
|
"node:crypto": "../ext/node/polyfills/crypto.ts",
|
||||||
"node:dgram": "../ext/node/polyfills/dgram.ts",
|
"node:dgram": "../ext/node/polyfills/dgram.ts",
|
||||||
"node:diagnostics_channel": "../ext/node/polyfills/diagnostics_channel.ts",
|
"node:diagnostics_channel": "../ext/node/polyfills/diagnostics_channel.js",
|
||||||
"node:dns": "../ext/node/polyfills/dns.ts",
|
"node:dns": "../ext/node/polyfills/dns.ts",
|
||||||
"node:dns/promises": "../ext/node/polyfills/dns/promises.ts",
|
"node:dns/promises": "../ext/node/polyfills/dns/promises.ts",
|
||||||
"node:domain": "../ext/node/polyfills/domain.ts",
|
"node:domain": "../ext/node/polyfills/domain.ts",
|
||||||
|
|
Loading…
Reference in a new issue