summaryrefslogtreecommitdiff
path: root/ext/node/polyfills/diagnostics_channel.ts
blob: 4f54c34313e3b65b2895940ba1d87365d4d00514 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// 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,
};