avocado-old/packages/net/client/socket.js
2019-05-16 15:19:42 -05:00

97 lines
2.2 KiB
JavaScript

import D from 'debug';
import io from 'socket.io-client';
import {compose, EventEmitter} from '@avocado/core';
import {SocketIoParser, allPackets, idFromPacket} from '../packet';
const debug = D('@avocado:client:socket');
const decorate = compose(
EventEmitter,
);
export class SocketClient extends decorate(class {}) {
constructor(address, options = {}) {
super();
this.address = address;
this.isConnected = false;
this.isReconnecting = false;
this.options = {
parser: SocketIoParser,
path: '/avocado',
perMessageDeflate: false,
reconnection: false,
...options
};
this.socket = null;
this.connect();
}
connect() {
if (this.socket) {
this.socket.destroy();
}
this.socket = io(this.address, {
...this.options,
});
this.socket.on('connect', () => {
debug('connect');
this.isConnected = true;
this.emit('connect');
});
this.socket.on('connect_error', () => {
debug('connect_error');
this.tryReconnect();
});
this.socket.on('connect_timeout', () => {
debug('connect_timeout');
this.tryReconnect();
});
this.socket.on('disconnect', () => {
this.isConnected = false;
this.emit('disconnect');
debug('disconnect');
this.tryReconnect();
});
for (const Packet of allPackets()) {
const id = idFromPacket(Packet);
this.socket.on(id, (data) => {
this.emit('packet', new Packet(data));
});
}
}
disconnect() {
this.socket.disconnect();
}
send(packet) {
const id = idFromPacket(packet.constructor);
this.socket.binary(true).emit(id, packet.data);
}
tryReconnect() {
if (this.isReconnecting) {
return;
}
this.isReconnecting = true;
let backoff = 100;
const tryToReconnect = () => {
debug('try to reconnect');
if (this.isConnected) {
debug('is connected');
this.isReconnecting = false;
return;
}
this.connect();
backoff = Math.min(2000, backoff * 1.5);
debug('backoff', backoff);
setTimeout(tryToReconnect, backoff);
}
setTimeout(tryToReconnect, 0);
}
}