/
client-web-socket.ts
161 lines (133 loc) · 4.99 KB
/
client-web-socket.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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import * as d from '../../declarations';
import { emitBuildLog, emitBuildResults, emitBuildStatus, logDisabled, logReload, logWarn } from '../client';
export const initClientWebSocket = (win: d.DevClientWindow, config: d.DevClientConfig) => {
let clientWs: WebSocket;
let reconnectTmrId: any;
let reconnectAttempts = 0;
let requestBuildResultsTmrId: any;
let hasGottenBuildResults = false;
let buildResultsRequests = 0;
function onOpen(this: WebSocket) {
if (reconnectAttempts > 0) {
// we just reconnected
// we'll request the build results and wait on its response
emitBuildStatus(win, 'pending');
}
if (!hasGottenBuildResults) {
requestBuildResultsTmrId = setInterval(() => {
buildResultsRequests++;
if (!hasGottenBuildResults && this.readyState === WebSocket.OPEN && buildResultsRequests < 500) {
const msg: d.DevServerMessage = {
requestBuildResults: true,
};
this.send(JSON.stringify(msg));
} else {
clearInterval(requestBuildResultsTmrId);
}
}, REQUEST_BUILD_RESULTS_INTERVAL_MS);
}
// we just connected, let's just
// double check we don't have a reconnect queued
clearTimeout(reconnectTmrId);
}
function onError() {
// looks like we can't connect to the server
// let's give it another shot in a few seconds
queueReconnect();
}
function onClose(event: { code: number; reason: string }) {
emitBuildStatus(win, 'disabled');
if (event.code > NORMAL_CLOSURE_CODE) {
// the browser's web socket has closed w/ an unexpected code
logWarn(`Dev Server`, `web socket closed: ${event.code} ${event.reason}`);
} else {
logDisabled(`Dev Server`, `Disconnected, attempting to reconnect...`);
}
// web socket closed, let's try to reconnect
queueReconnect();
}
function onMessage(event: any) {
// the browser's web socket received a message from the server
const msg: d.DevServerMessage = JSON.parse(event.data);
if (reconnectAttempts > 0) {
// we got a message and we know we've been trying to reconnect
if (msg.isActivelyBuilding) {
// looks like there's still an active build
return;
}
if (msg.buildResults) {
// this is from a reconnect, and we were just notified w/ build results
// so it's probably best if we do a full page refresh
logReload(`Reconnected to dev server`);
hasGottenBuildResults = true;
buildResultsRequests = 0;
clearInterval(requestBuildResultsTmrId);
win.location.reload(true);
return;
}
}
if (msg.buildLog) {
if (msg.buildLog.progress < 1) {
emitBuildStatus(win, 'pending');
}
emitBuildLog(win, msg.buildLog);
return;
}
if (msg.buildResults) {
// we just got build results from the server
// let's update our app with the data received
hasGottenBuildResults = true;
buildResultsRequests = 0;
clearInterval(requestBuildResultsTmrId);
emitBuildStatus(win, 'default');
emitBuildResults(win, msg.buildResults);
return;
}
}
function connect() {
// ensure we don't have a reconnect timeout running
clearTimeout(reconnectTmrId);
// have the browser open a web socket with the server
clientWs = new win.WebSocket(config.socketUrl, ['xmpp']);
// add all our event listeners to our new web socket
clientWs.addEventListener('open', onOpen);
clientWs.addEventListener('error', onError);
clientWs.addEventListener('close', onClose);
clientWs.addEventListener('message', onMessage);
}
function queueReconnect() {
// either it closed or was a connection error
hasGottenBuildResults = false;
// let's clear out the existing web socket
if (clientWs) {
if (clientWs.readyState === WebSocket.OPEN || clientWs.readyState === WebSocket.CONNECTING) {
// probably fine as is, but let's double check we're closed out
clientWs.close(NORMAL_CLOSURE_CODE);
}
// let's remove all the existing event listeners
clientWs.removeEventListener('open', onOpen);
clientWs.removeEventListener('error', onError);
clientWs.removeEventListener('close', onClose);
clientWs.removeEventListener('message', onMessage);
clientWs = null;
}
// ensure clear out any other pending reconnect timeouts
clearTimeout(reconnectTmrId);
if (reconnectAttempts >= RECONNECT_ATTEMPTS) {
logWarn(`Dev Server`, `Canceling reconnect attempts`);
} else {
// keep track how many times we tried to reconnect
reconnectAttempts++;
// queue up a reconnect in a few seconds
reconnectTmrId = setTimeout(connect, RECONNECT_RETRY_MS);
emitBuildStatus(win, 'disabled');
}
}
// let's do this!
// try to connect up with our web socket server
connect();
};
const RECONNECT_ATTEMPTS = 1000;
const RECONNECT_RETRY_MS = 2500;
const NORMAL_CLOSURE_CODE = 1000;
const REQUEST_BUILD_RESULTS_INTERVAL_MS = 500;