This commit is contained in:
Andras Schmelczer 2026-09-27 09:04:05 +01:00
commit c869f0a880

View file

@ -5,7 +5,6 @@ import type { WebSocketClientMessage } from "./types/WebSocketClientMessage";
import type { CursorPositionFromClient } from "./types/CursorPositionFromClient";
import type { ClientCursors } from "./types/ClientCursors";
import { WEBSOCKET_RECEIVE_TIMEOUT_MS } from "../consts";
import { removeFromArray } from "../utils/remove-from-array";
import { EventListeners } from "../utils/data-structures/event-listeners";
import { awaitAll } from "../utils/await-all";
@ -26,7 +25,7 @@ export class WebSocketManager {
private receiveTimeoutId: ReturnType<typeof setTimeout> | undefined;
private reconnectTimeoutId: ReturnType<typeof setTimeout> | undefined;
private readonly outstandingPromises: Promise<unknown>[] = [];
private readonly outstandingPromises = new Set<Promise<void>>();
private webSocket: WebSocket | undefined;
private readonly webSocketFactoryImplementation: typeof globalThis.WebSocket;
@ -39,16 +38,12 @@ export class WebSocketManager {
) {
if (webSocketImplementation) {
this.webSocketFactoryImplementation = webSocketImplementation;
} else if (typeof globalThis.WebSocket !== "undefined") {
this.webSocketFactoryImplementation = globalThis.WebSocket;
} else {
if (
typeof globalThis !== "undefined" &&
typeof globalThis.WebSocket === "undefined"
) {
// eslint-disable-next-line
this.webSocketFactoryImplementation = require("ws"); // polyfill for WebSocket in Node.js
} else {
this.webSocketFactoryImplementation = WebSocket;
}
this.webSocketFactoryImplementation =
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-type-assertion -- Node versions without WebSocket use ws.
require("ws") as typeof globalThis.WebSocket;
}
}
@ -75,7 +70,7 @@ export class WebSocketManager {
}
public async waitUntilFinished(): Promise<void> {
await awaitAll(this.outstandingPromises);
await awaitAll([...this.outstandingPromises]);
}
public updateLocalCursors(cursorPositions: CursorPositionFromClient): void {
@ -182,12 +177,12 @@ export class WebSocketManager {
this.webSocket = socket;
this.expectResponse(socket);
this.webSocket.onerror = (): void => {
socket.onerror = (): void => {
this.logger.warn("WebSocket transport error");
this.reconnect(socket);
};
this.webSocket.onopen = (): void => {
socket.onopen = (): void => {
if (this.webSocket !== socket || this.isStopped) return;
try {
const handshake: WebSocketClientMessage = {
@ -209,7 +204,7 @@ export class WebSocketManager {
}
};
this.webSocket.onmessage = (event): void => {
socket.onmessage = (event): void => {
if (this.webSocket !== socket || this.isStopped) return;
try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
@ -229,13 +224,10 @@ export class WebSocketManager {
);
})
.finally(() => {
removeFromArray(
this.outstandingPromises,
messageHandlingPromise
);
this.outstandingPromises.delete(messageHandlingPromise);
});
this.outstandingPromises.push(messageHandlingPromise);
this.outstandingPromises.add(messageHandlingPromise);
} catch (error) {
this.logger.error(
`Error parsing WebSocket message: ${String(error)}`
@ -243,7 +235,7 @@ export class WebSocketManager {
}
};
this.webSocket.onclose = (event): void => {
socket.onclose = (event): void => {
this.logger.warn(
`WebSocket closed with code ${event.code} (${event.reason == "" ? "unknown reason" : event.reason})`
);