Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
sender.js105 linesDownload Raw Back to websocket
1'use strict'
2
3const { WebsocketFrameSend } = require('./frame')
4const { opcodes, sendHints } = require('./constants')
5const FixedQueue = require('../../dispatcher/fixed-queue')
6
7/** @type {typeof Uint8Array} */
8const FastBuffer = Buffer[Symbol.species]
9
10/**
11 * @typedef {object} SendQueueNode
12 * @property {Promise<void> | null} promise
13 * @property {((...args: any[]) => any)} callback
14 * @property {Buffer | null} frame
15 */
16
17class SendQueue {
18  /**
19   * @type {FixedQueue}
20   */
21  #queue = new FixedQueue()
22
23  /**
24   * @type {boolean}
25   */
26  #running = false
27
28  /** @type {import('node:net').Socket} */
29  #socket
30
31  constructor (socket) {
32    this.#socket = socket
33  }
34
35  add (item, cb, hint) {
36    if (hint !== sendHints.blob) {
37      const frame = createFrame(item, hint)
38      if (!this.#running) {
39        // fast-path
40        this.#socket.write(frame, cb)
41      } else {
42        /** @type {SendQueueNode} */
43        const node = {
44          promise: null,
45          callback: cb,
46          frame
47        }
48        this.#queue.push(node)
49      }
50      return
51    }
52
53    /** @type {SendQueueNode} */
54    const node = {
55      promise: item.arrayBuffer().then((ab) => {
56        node.promise = null
57        node.frame = createFrame(ab, hint)
58      }),
59      callback: cb,
60      frame: null
61    }
62
63    this.#queue.push(node)
64
65    if (!this.#running) {
66      this.#run()
67    }
68  }
69
70  async #run () {
71    this.#running = true
72    const queue = this.#queue
73    while (!queue.isEmpty()) {
74      const node = queue.shift()
75      // wait pending promise
76      if (node.promise !== null) {
77        await node.promise
78      }
79      // write
80      this.#socket.write(node.frame, node.callback)
81      // cleanup
82      node.callback = node.frame = null
83    }
84    this.#running = false
85  }
86}
87
88function createFrame (data, hint) {
89  return new WebsocketFrameSend(toBuffer(data, hint)).createFrame(hint === sendHints.string ? opcodes.TEXT : opcodes.BINARY)
90}
91
92function toBuffer (data, hint) {
93  switch (hint) {
94    case sendHints.string:
95      return Buffer.from(data)
96    case sendHints.arrayBuffer:
97    case sendHints.blob:
98      return new FastBuffer(data)
99    case sendHints.typedArray:
100      return new FastBuffer(data.buffer, data.byteOffset, data.byteLength)
101  }
102}
103
104module.exports = { SendQueue }
105