forked from cryptotavares/metamask-desktop
-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathweb-socket-stream.ts
105 lines (84 loc) · 2.39 KB
/
web-socket-stream.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import { Duplex } from 'stream';
import { WebSocket as WSWebSocket } from 'ws';
import log from './utils/log';
import { timeoutPromise } from './utils/utils';
const INTERVAL_WAIT_FOR_CONNECTED = 500;
const TIMEOUT_WAIT_FOR_CONNECTED = 3000;
export type BrowserWebSocket = WebSocket;
export type NodeWebSocket = WSWebSocket;
export class WebSocketStream extends Duplex {
private webSocket: BrowserWebSocket | NodeWebSocket;
private isBrowser: boolean;
constructor(webSocket: BrowserWebSocket | NodeWebSocket) {
super({ objectMode: true });
this.webSocket = webSocket;
this.isBrowser = !(this.webSocket as any).on;
if (this.isBrowser) {
(this.webSocket as BrowserWebSocket).addEventListener(
'message',
(event) => this.onMessage(event.data),
);
} else {
(this.webSocket as NodeWebSocket).on('message', (message) =>
this.onMessage(message),
);
}
}
public init() {
// For consistency with EncryptedWebSocketStream to avoid further code branches
}
public _read() {
return undefined;
}
public async _write(msg: any, _: string, cb: () => void) {
log.debug('Sending message to web socket');
const rawData = typeof msg === 'string' ? msg : JSON.stringify(msg);
try {
await this.waitForSocketConnected(this.webSocket);
} catch (error) {
log.error('Timeout waiting for web socket to be writable');
cb();
return;
}
this.webSocket.send(rawData);
cb();
}
private async onMessage(rawData: any) {
let data = rawData;
try {
data = JSON.parse(data);
} catch {
// Ignore as data is not a serialised object
}
log.debug('Received web socket message');
this.push(data);
}
private async waitForSocketConnected(
socket: BrowserWebSocket | NodeWebSocket,
): Promise<void> {
let interval: any;
return timeoutPromise(
new Promise<void>((resolve) => {
const isReady = () => socket.readyState === 1;
if (isReady()) {
resolve();
return;
}
interval = setInterval(() => {
if (isReady()) {
clearInterval(interval);
resolve();
}
}, INTERVAL_WAIT_FOR_CONNECTED);
}),
TIMEOUT_WAIT_FOR_CONNECTED,
{
cleanUp: () => {
if (interval) {
clearInterval(interval);
}
},
},
);
}
}