Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/webroot/rsrc/externals/javelin/lib/WebSocket.js
12242 views
1
/**
2
* @requires javelin-install
3
* @provides javelin-websocket
4
* @javelin
5
*/
6
7
/**
8
* Wraps a WebSocket.
9
*/
10
JX.install('WebSocket', {
11
12
construct: function(uri) {
13
this.setURI(uri);
14
this._resetDelay();
15
},
16
17
properties: {
18
URI: null,
19
20
/**
21
* Called when a connection is established or re-established after an
22
* interruption.
23
*/
24
openHandler: null,
25
26
/**
27
* Called when a message is received.
28
*/
29
messageHandler: null,
30
31
/**
32
* Called when the connection is closed.
33
*
34
* You can return `true` to prevent the socket from reconnecting.
35
*/
36
closeHandler: null
37
},
38
39
members: {
40
/**
41
* The underlying WebSocket.
42
*/
43
_socket: null,
44
45
/**
46
* Is the socket connected?
47
*/
48
_isOpen: false,
49
50
/**
51
* Has the caller asked us to close?
52
*
53
* By default, we reconnect when the connection is interrupted.
54
* This stops us from reconnecting if @{method:close} was called.
55
*/
56
_shouldClose: false,
57
58
/**
59
* Number of milliseconds to wait after a connection failure before
60
* attempting to reconnect.
61
*/
62
_delayUntilReconnect: null,
63
64
65
/**
66
* Open the connection.
67
*/
68
open: function() {
69
if (!window.WebSocket) {
70
return;
71
}
72
73
this._shouldClose = false;
74
75
this._socket = new WebSocket(this.getURI());
76
this._socket.onopen = JX.bind(this, this._onopen);
77
this._socket.onmessage = JX.bind(this, this._onmessage);
78
this._socket.onclose = JX.bind(this, this._onclose);
79
},
80
81
82
/**
83
* Send a message.
84
*
85
* If the connection is not currently open, this method has no effect and
86
* the messages vanishes into the ether.
87
*/
88
send: function(message) {
89
if (this._isOpen) {
90
this._socket.send(message);
91
}
92
},
93
94
95
/**
96
* Close the connection.
97
*/
98
close: function() {
99
if (!this._isOpen) {
100
return;
101
}
102
this._shouldClose = true;
103
this._socket.close();
104
},
105
106
107
/**
108
* Disconnect abruptly, prompting a reconnect.
109
*/
110
reconnect: function() {
111
if (!this._isOpen) {
112
return;
113
}
114
115
this._socket.close();
116
},
117
118
119
/**
120
* Get the current reconnect delay (in milliseconds).
121
*/
122
getReconnectDelay: function() {
123
return this._delayUntilReconnect;
124
},
125
126
127
/**
128
* Callback for connection open.
129
*/
130
_onopen: function() {
131
this._isOpen = true;
132
133
// Since we connected successfully, reset the reconnect delay to 0.
134
135
// This will make us try the first reconnect immediately after a
136
// connection failure. This limits downtime in cases like a service
137
// restart or a load balancer connection timeout.
138
139
// We only do an immediate retry after a successful connection.
140
this._delayUntilReconnect = 0;
141
142
var handler = this.getOpenHandler();
143
if (handler) {
144
handler();
145
}
146
},
147
148
149
/**
150
* Reset the reconnect delay to its base value.
151
*/
152
_resetDelay: function() {
153
this._delayUntilReconnect = 2000;
154
},
155
156
157
/**
158
* Callback for message received.
159
*/
160
_onmessage: function(e) {
161
var data = e.data;
162
163
var handler = this.getMessageHandler();
164
if (handler) {
165
handler(data);
166
}
167
},
168
169
170
/**
171
* Callback for connection close.
172
*/
173
_onclose: function() {
174
this._isOpen = false;
175
176
var done = false;
177
178
var handler = this.getCloseHandler();
179
if (handler) {
180
done = handler();
181
}
182
183
// If we didn't explicitly see a close() call and the close handler
184
// did not return `true` to stop the reconnect, wait a little while
185
// and try to reconnect.
186
if (!done && !this._shouldClose) {
187
setTimeout(JX.bind(this, this._reconnect), this._delayUntilReconnect);
188
}
189
},
190
191
192
/**
193
* Reconnect an interrupted socket.
194
*/
195
_reconnect: function() {
196
// Increase the reconnect delay by a factor of 2. If we fail to open the
197
// connection, the close handler will send us back here. We'll reconnect
198
// more and more slowly until we eventually get a valid connection.
199
if (!this._delayUntilReconnect) {
200
this._resetDelay();
201
} else {
202
this._delayUntilReconnect = this._delayUntilReconnect * 2;
203
}
204
205
// Max out at 5 minutes between attempts.
206
this._delayUntilReconnect = Math.min(this._delayUntilReconnect, 300000);
207
this.open();
208
}
209
210
}
211
});
212
213