Skip to content

Instantly share code, notes, and snippets.

@jonstuebe
Created December 22, 2023 15:33
Show Gist options
  • Save jonstuebe/6b17109649a19ffd722d0ec7121d2080 to your computer and use it in GitHub Desktop.
Save jonstuebe/6b17109649a19ffd722d0ec7121d2080 to your computer and use it in GitHub Desktop.
A WebSocket class with reconnection support
class ReSocket {
private token: string | undefined;
private socket: WebSocket | undefined;
private listeners: boolean = false;
private currentAttempt: number = 0;
private backoffTime: number = 1000;
private maxAttempts: number = 30;
private timer: NodeJS.Timeout | undefined;
private messageFn: (data: any) => void = (data) => {
//
};
constructor(messageFn: (data: any) => void) {
this.messageFn = messageFn;
}
public updateToken(token: string) {
this.token = token;
if (this.socket) {
this.removeListeners();
this.socket.close();
}
this.init();
}
public destroy() {
if (this.socket) {
this.removeListeners();
this.socket.close();
this.socket = undefined;
}
}
private onOpen() {
console.log("websocket opened");
this.currentAttempt = 0;
if (this.timer) {
clearTimeout(this.timer);
this.timer = undefined;
}
}
private onError(event: Event) {
console.log("on error");
}
private onClose(event: any) {
if (this.listeners) {
this.removeListeners();
}
this.socket?.close();
this.socket = undefined;
this.currentAttempt++;
console.log(
`WebSocket connection failed. Trying to reconnect. This is attempt ${this.currentAttempt} of ${this.maxAttempts}`
);
if (this.currentAttempt >= this.maxAttempts) {
console.error("Failed to establish WebSocket connection.");
return;
}
const backoffTimeMilliseconds =
this.backoffTime * Math.pow(1.5, this.currentAttempt);
this.timer = setTimeout(this.init.bind(this), backoffTimeMilliseconds);
console.log(`Next reconnection attempt in ${backoffTimeMilliseconds}ms.`);
}
private addListeners() {
if (this.socket) {
this.socket.addEventListener("open", this.onOpen.bind(this));
this.socket.addEventListener("close", this.onClose.bind(this));
this.socket.addEventListener("error", this.onError.bind(this));
this.socket.addEventListener("message", this.onMessage.bind(this));
this.listeners = true;
}
}
private removeListeners() {
if (this.socket && this.listeners) {
this.socket.removeEventListener("open", this.onOpen.bind(this));
this.socket.removeEventListener("close", this.onClose.bind(this));
this.socket.removeEventListener("error", this.onError.bind(this));
this.socket.removeEventListener("message", this.onMessage.bind(this));
this.listeners = false;
}
}
private onMessage(event: MessageEvent<any>) {
this.messageFn(event.data);
}
private init() {
if (this.token === undefined) {
throw new Error("no token found");
}
this.socket = new WebSocket(`${WS_API_URL}?token=${this.token}`);
this.addListeners();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment