mirror of
https://github.com/trezor/trezor-suite.git
synced 2026-03-23 15:47:18 +01:00
feat(websocket-client): differentiable error type
This commit is contained in:
@@ -27,6 +27,8 @@ type WebsocketClientEvents = {
|
||||
export type WebsocketRequest = Record<string, any>;
|
||||
export type WebsocketResponse = WebSocket.Data;
|
||||
|
||||
export class WebsocketError extends Error {}
|
||||
|
||||
export class WebsocketClient<Events extends Record<string, any>> extends TypedEmitter<
|
||||
Events & WebsocketClientEvents
|
||||
> {
|
||||
@@ -56,7 +58,7 @@ export class WebsocketClient<Events extends Record<string, any>> extends TypedEm
|
||||
protected initWebsocket({ url, timeout, headers, agent }: WebsocketOptions) {
|
||||
// url validation
|
||||
if (typeof url !== 'string') {
|
||||
throw new Error('websocket_no_url');
|
||||
throw new WebsocketError('websocket_no_url');
|
||||
}
|
||||
if (url.startsWith('http')) {
|
||||
url = url.replace('http', 'ws');
|
||||
@@ -86,7 +88,7 @@ export class WebsocketClient<Events extends Record<string, any>> extends TypedEm
|
||||
private onTimeout() {
|
||||
const { ws } = this;
|
||||
if (!ws) return;
|
||||
this.messages.rejectAll(new Error('websocket_timeout'));
|
||||
this.messages.rejectAll(new WebsocketError('websocket_timeout'));
|
||||
ws.close();
|
||||
}
|
||||
|
||||
@@ -96,7 +98,7 @@ export class WebsocketClient<Events extends Record<string, any>> extends TypedEm
|
||||
|
||||
sendMessage(message: WebsocketRequest, { timeout }: { timeout?: number } = {}) {
|
||||
const { ws } = this;
|
||||
if (!ws || !this.isConnected()) throw new Error('websocket_not_initialized');
|
||||
if (!ws || !this.isConnected()) throw new WebsocketError('websocket_not_initialized');
|
||||
const { promiseId, promise } = this.messages.create(timeout);
|
||||
|
||||
const req = { id: promiseId.toString(), ...message };
|
||||
@@ -112,7 +114,7 @@ export class WebsocketClient<Events extends Record<string, any>> extends TypedEm
|
||||
|
||||
protected sendRawMessage(message: WebSocket.Data) {
|
||||
const { ws } = this;
|
||||
if (!ws || !this.isConnected()) throw new Error('websocket_not_initialized');
|
||||
if (!ws || !this.isConnected()) throw new WebsocketError('websocket_not_initialized');
|
||||
|
||||
ws.send(message, {
|
||||
binary: typeof message !== 'string',
|
||||
@@ -168,7 +170,7 @@ export class WebsocketClient<Events extends Record<string, any>> extends TypedEm
|
||||
// set connection timeout before WebSocket initialization
|
||||
const connectionTimeout = setTimeout(
|
||||
() => {
|
||||
ws.emit('error', new Error('websocket_timeout'));
|
||||
ws.emit('error', new WebsocketError('websocket_timeout'));
|
||||
try {
|
||||
ws.once('error', () => {}); // hack; ws throws uncaughtably when there's no error listener
|
||||
ws.close();
|
||||
@@ -182,7 +184,7 @@ export class WebsocketClient<Events extends Record<string, any>> extends TypedEm
|
||||
ws.once('error', error => {
|
||||
clearTimeout(connectionTimeout);
|
||||
this.onClose();
|
||||
dfd.reject(new Error(error.message));
|
||||
dfd.reject(new WebsocketError(error.message));
|
||||
});
|
||||
ws.on('open', () => {
|
||||
clearTimeout(connectionTimeout);
|
||||
@@ -235,7 +237,7 @@ export class WebsocketClient<Events extends Record<string, any>> extends TypedEm
|
||||
clearTimeout(this.pingTimeout);
|
||||
|
||||
this.ws?.removeAllListeners();
|
||||
this.messages.rejectAll(new Error('Websocket closed unexpectedly'));
|
||||
this.messages.rejectAll(new WebsocketError('Websocket closed unexpectedly'));
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
import { WebsocketError } from './client';
|
||||
|
||||
/**
|
||||
* Provides `EventEmitter` interface for native browser `WebSocket`,
|
||||
* same, as `ws` package provides.
|
||||
@@ -31,7 +33,10 @@ class WSWrapper extends EventEmitter {
|
||||
// fire an event named error at the WebSocket object.
|
||||
// https://stackoverflow.com/a/31003057
|
||||
this._ws.onerror = _event => {
|
||||
this.emit('error', new Error(`WsWrapper error. Ready state: ${this.readyState}`));
|
||||
this.emit(
|
||||
'error',
|
||||
new WebsocketError(`WsWrapper error. Ready state: ${this.readyState}`),
|
||||
);
|
||||
};
|
||||
|
||||
this._ws.onmessage = message => {
|
||||
@@ -47,7 +52,7 @@ class WSWrapper extends EventEmitter {
|
||||
|
||||
send(message: any) {
|
||||
if (this.readyState !== WSWrapper.OPEN) {
|
||||
throw new Error(`Connection is not open. state: ${this.readyState}`);
|
||||
throw new WebsocketError(`Connection is not open. state: ${this.readyState}`);
|
||||
}
|
||||
this._ws.send(message);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
import { WebsocketError } from './client';
|
||||
|
||||
/**
|
||||
* Provides `EventEmitter` interface for React Native `WebSocket`,
|
||||
* same, as `ws` package provides.
|
||||
@@ -37,7 +39,10 @@ class WSWrapper extends EventEmitter {
|
||||
// fire an event named error at the WebSocket object.
|
||||
// https://stackoverflow.com/a/31003057
|
||||
this._ws.onerror = _event => {
|
||||
this.emit('error', new Error(`WsWrapper error. Ready state: ${this.readyState}`));
|
||||
this.emit(
|
||||
'error',
|
||||
new WebsocketError(`WsWrapper error. Ready state: ${this.readyState}`),
|
||||
);
|
||||
};
|
||||
|
||||
this._ws.onmessage = message => {
|
||||
@@ -53,7 +58,7 @@ class WSWrapper extends EventEmitter {
|
||||
|
||||
send(message: any) {
|
||||
if (this.readyState !== WSWrapper.OPEN) {
|
||||
throw new Error(`Connection is not open. state: ${this.readyState}`);
|
||||
throw new WebsocketError(`Connection is not open. state: ${this.readyState}`);
|
||||
}
|
||||
this._ws.send(message);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user