91 lines
2.0 KiB
JavaScript
91 lines
2.0 KiB
JavaScript
import { Buffer } from 'buffer';
|
|
import { AsyncLock } from './async-lock.mjs';
|
|
|
|
/**
|
|
* Represents an asynchronous byte queue for managing byte data.
|
|
*/
|
|
export class AsyncByteQueue {
|
|
/**
|
|
* Creates an instance of AsyncByteQueue.
|
|
*/
|
|
constructor() {
|
|
/**
|
|
* The buffer to store byte data.
|
|
* @type {Buffer}
|
|
* @private
|
|
*/
|
|
this.data = Buffer.alloc(0);
|
|
|
|
/**
|
|
* The index indicating the head of the byte queue.
|
|
* @type {number}
|
|
* @private
|
|
*/
|
|
this.head = 0;
|
|
|
|
/**
|
|
* The lock used to manage access to the byte queue.
|
|
* @type {AsyncLock}
|
|
* @private
|
|
*/
|
|
this.lock = new AsyncLock();
|
|
}
|
|
|
|
/**
|
|
* Checks if the byte queue is empty.
|
|
* @returns {boolean} True if the byte queue is empty; otherwise, false.
|
|
*/
|
|
empty() {
|
|
return this.head === this.data.byteLength;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the byte at the front of the queue asynchronously.
|
|
* @returns {Promise<number>} A promise that resolves with the byte at the front of the queue.
|
|
*/
|
|
async front() {
|
|
while (this.empty()) {
|
|
await this.lock.acquire();
|
|
}
|
|
this.lock.forceRelease();
|
|
return this.data[this.head];
|
|
}
|
|
|
|
/**
|
|
* Removes and retrieves the byte at the front of the queue asynchronously.
|
|
* @returns {Promise<number>} A promise that resolves with the byte removed from the front of the queue.
|
|
*/
|
|
async popFront() {
|
|
while (this.empty()) {
|
|
await this.lock.acquire();
|
|
}
|
|
|
|
let res = this.data[this.head];
|
|
this.head += 1;
|
|
this._refactor();
|
|
if (!this.empty()) {
|
|
this.lock.forceRelease();
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* Appends byte data to the end of the queue.
|
|
* @param {Buffer} data The byte data to append to the queue.
|
|
*/
|
|
pushBack(data) {
|
|
this.data = Buffer.concat([this.data, data]);
|
|
this.lock.forceRelease();
|
|
}
|
|
|
|
/**
|
|
* Refactors the internal data buffer by discarding processed bytes if necessary.
|
|
* @private
|
|
*/
|
|
_refactor() {
|
|
if (this.head >= (this.data.byteLength >> 1) && this.head >= 16) {
|
|
this.data = this.data.subarray(this.head);
|
|
}
|
|
}
|
|
}
|