2015-12-28 23:34:32 +00:00
|
|
|
import Backoff from 'backo';
|
|
|
|
|
2017-04-11 01:49:52 +00:00
|
|
|
export default class Socket {
|
2016-01-15 01:27:30 +00:00
|
|
|
constructor(host) {
|
2015-12-29 21:23:07 +00:00
|
|
|
const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws';
|
2017-06-13 02:25:59 +00:00
|
|
|
this.url = `${protocol}://${host}/ws${window.location.pathname}`;
|
2015-12-29 21:23:07 +00:00
|
|
|
|
2015-12-28 23:34:32 +00:00
|
|
|
this.connectTimeout = 20000;
|
|
|
|
this.pingTimeout = 30000;
|
|
|
|
this.backoff = new Backoff({
|
|
|
|
min: 1000,
|
|
|
|
max: 5000,
|
|
|
|
jitter: 0.25
|
|
|
|
});
|
2017-04-11 01:49:52 +00:00
|
|
|
this.handlers = [];
|
2018-10-15 23:04:49 +00:00
|
|
|
this.connected = false;
|
2015-12-28 23:34:32 +00:00
|
|
|
|
|
|
|
this.connect();
|
|
|
|
}
|
|
|
|
|
|
|
|
connect() {
|
2015-12-29 21:23:07 +00:00
|
|
|
this.ws = new WebSocket(this.url);
|
2015-12-28 23:34:32 +00:00
|
|
|
|
|
|
|
this.timeoutConnect = setTimeout(() => {
|
|
|
|
this.ws.close();
|
|
|
|
this.retry();
|
|
|
|
}, this.connectTimeout);
|
|
|
|
|
|
|
|
this.ws.onopen = () => {
|
2018-10-15 23:04:49 +00:00
|
|
|
this.connected = true;
|
2017-05-29 04:16:24 +00:00
|
|
|
this.emit('_connected', true);
|
2015-12-28 23:34:32 +00:00
|
|
|
clearTimeout(this.timeoutConnect);
|
|
|
|
this.backoff.reset();
|
|
|
|
this.setTimeoutPing();
|
|
|
|
};
|
|
|
|
|
|
|
|
this.ws.onclose = () => {
|
2018-10-15 23:04:49 +00:00
|
|
|
if (this.connected) {
|
|
|
|
this.connected = false;
|
|
|
|
this.emit('_connected', false);
|
|
|
|
}
|
2015-12-28 23:34:32 +00:00
|
|
|
clearTimeout(this.timeoutConnect);
|
|
|
|
clearTimeout(this.timeoutPing);
|
|
|
|
if (!this.closing) {
|
|
|
|
this.retry();
|
|
|
|
}
|
|
|
|
this.closing = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
this.ws.onerror = () => {
|
|
|
|
clearTimeout(this.timeoutConnect);
|
|
|
|
clearTimeout(this.timeoutPing);
|
|
|
|
this.closing = true;
|
|
|
|
this.ws.close();
|
|
|
|
this.retry();
|
|
|
|
};
|
|
|
|
|
2018-04-05 23:46:22 +00:00
|
|
|
this.ws.onmessage = e => {
|
2015-12-28 23:34:32 +00:00
|
|
|
this.setTimeoutPing();
|
|
|
|
|
|
|
|
const msg = JSON.parse(e.data);
|
|
|
|
|
|
|
|
if (msg.type === 'ping') {
|
|
|
|
this.send('pong');
|
2018-10-15 23:04:49 +00:00
|
|
|
return;
|
2015-12-28 23:34:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this.emit(msg.type, msg.data);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
retry() {
|
|
|
|
setTimeout(() => this.connect(), this.backoff.duration());
|
|
|
|
}
|
|
|
|
|
|
|
|
send(type, data) {
|
|
|
|
this.ws.send(JSON.stringify({ type, data }));
|
|
|
|
}
|
|
|
|
|
|
|
|
setTimeoutPing() {
|
|
|
|
clearTimeout(this.timeoutPing);
|
|
|
|
this.timeoutPing = setTimeout(() => {
|
|
|
|
this.closing = true;
|
|
|
|
this.ws.close();
|
|
|
|
this.connect();
|
|
|
|
}, this.pingTimeout);
|
|
|
|
}
|
2017-04-11 01:49:52 +00:00
|
|
|
|
|
|
|
onMessage(handler) {
|
|
|
|
this.handlers.push(handler);
|
|
|
|
}
|
|
|
|
|
|
|
|
emit(type, data) {
|
|
|
|
for (let i = 0; i < this.handlers.length; i++) {
|
|
|
|
this.handlers[i](type, data);
|
|
|
|
}
|
|
|
|
}
|
2015-12-28 23:34:32 +00:00
|
|
|
}
|