lib/client: add human-readable messages for WebSocket error codes

This commit is contained in:
Simon Ser
2025-05-05 18:35:20 +02:00
parent caf6e9978b
commit 6905b9d768

View File

@@ -32,9 +32,33 @@ const RECONNECT_MAX_DELAY_MSEC = 10 * 60 * 1000; // 10min
// WebSocket status codes // WebSocket status codes
// https://www.rfc-editor.org/rfc/rfc6455.html#section-7.4.1 // https://www.rfc-editor.org/rfc/rfc6455.html#section-7.4.1
const NORMAL_CLOSURE = 1000; const WEBSOCKET_CLOSE_CODES = {
const GOING_AWAY = 1001; NORMAL_CLOSURE: 1000,
const UNSUPPORTED_DATA = 1003; GOING_AWAY: 1001,
PROTOCOL_ERROR: 1002,
UNSUPPORTED_DATA: 1003,
NO_STATUS_CODE: 1005,
ABNORMAL_CLOSURE: 1006,
INVALID_FRAME_PAYLOAD_DATA: 1007,
POLICY_VIOLATION: 1008,
MESSAGE_TOO_BIG: 1009,
MISSING_MANDATORY_EXT: 1010,
INTERNAL_SERVER_ERROR: 1011,
TLS_HANDSHAKE_FAILED: 1015,
};
const WEBSOCKET_CLOSE_CODE_NAMES = {
[WEBSOCKET_CLOSE_CODES.GOING_AWAY]: "going away",
[WEBSOCKET_CLOSE_CODES.PROTOCOL_ERROR]: "protocol error",
[WEBSOCKET_CLOSE_CODES.UNSUPPORTED_DATA]: "unsupported data",
[WEBSOCKET_CLOSE_CODES.NO_STATUS_CODE]: "no status code received",
[WEBSOCKET_CLOSE_CODES.ABNORMAL_CLOSURE]: "abnormal closure",
[WEBSOCKET_CLOSE_CODES.INVALID_FRAME_PAYLOAD_DATA]: "invalid frame payload data",
[WEBSOCKET_CLOSE_CODES.POLICY_VIOLATION]: "policy violation",
[WEBSOCKET_CLOSE_CODES.MESSAGE_TOO_BIG]: "message too big",
[WEBSOCKET_CLOSE_CODES.MISSING_MANDATORY_EXT]: "missing mandatory extension",
[WEBSOCKET_CLOSE_CODES.INTERNAL_SERVER_ERROR]: "internal server error",
[WEBSOCKET_CLOSE_CODES.TLS_HANDSHAKE_FAILED]: "TLS handshake failed",
};
// See https://github.com/quakenet/snircd/blob/master/doc/readme.who // See https://github.com/quakenet/snircd/blob/master/doc/readme.who
// Sorted by order of appearance in RPL_WHOSPCRPL // Sorted by order of appearance in RPL_WHOSPCRPL
@@ -69,6 +93,18 @@ class IRCError extends Error {
} }
} }
class WebSocketError extends Error {
constructor(code) {
let text = "Connection error";
let name = WEBSOCKET_CLOSE_CODE_NAMES[code];
if (name) {
text += " (" + name + ")";
}
super(text);
}
}
/** /**
* Implements a simple exponential backoff. * Implements a simple exponential backoff.
*/ */
@@ -189,8 +225,8 @@ export default class Client extends EventTarget {
this.ws.addEventListener("close", (event) => { this.ws.addEventListener("close", (event) => {
console.log("Connection closed (code: " + event.code + ")"); console.log("Connection closed (code: " + event.code + ")");
if (event.code !== NORMAL_CLOSURE && event.code !== GOING_AWAY) { if (event.code !== WEBSOCKET_CLOSE_CODES.NORMAL_CLOSURE && event.code !== WEBSOCKET_CLOSE_CODES.GOING_AWAY) {
this.dispatchError(new Error("Connection error")); this.dispatchError(new WebSocketError(event.code));
} }
this.ws = null; this.ws = null;
@@ -237,7 +273,7 @@ export default class Client extends EventTarget {
this.setPingInterval(0); this.setPingInterval(0);
if (this.ws) { if (this.ws) {
this.ws.close(NORMAL_CLOSURE); this.ws.close(WEBSOCKET_CLOSE_CODES.NORMAL_CLOSURE);
} }
} }
@@ -297,7 +333,7 @@ export default class Client extends EventTarget {
handleMessage(event) { handleMessage(event) {
if (typeof event.data !== "string") { if (typeof event.data !== "string") {
console.error("Received unsupported data type:", event.data); console.error("Received unsupported data type:", event.data);
this.ws.close(UNSUPPORTED_DATA); this.ws.close(WEBSOCKET_CLOSE_CODES.UNSUPPORTED_DATA);
return; return;
} }