From db894376eba4f18af813d4219d4f49e9c7f35257 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Thu, 16 Feb 2023 21:47:49 -0500 Subject: [PATCH] *Add connection retry with backoff support --- package.json | 6 ++++-- src/index.ts | 46 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 52bfca6..d729010 100644 --- a/package.json +++ b/package.json @@ -6,11 +6,13 @@ "dependencies": { "@lumeweb/libkernel-universal": "git+https://git.lumeweb.com/LumeWeb/libkernel-universal.git", "@siaweb/libweb": "git+https://git.lumeweb.com/LumeWeb/libsiaweb.git", + "backoff": "^2.5.0", "eventemitter3": "^5.0.0" }, "devDependencies": { - "@types/node": "^18.11.19", - "prettier": "^2.8.3", + "@types/backoff": "^2.5.2", + "@types/node": "^18.13.0", + "prettier": "^2.8.4", "pretty": "^2.0.0", "typescript": "^4.9.5" } diff --git a/src/index.ts b/src/index.ts index ce8242d..58ba3c9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,13 +4,25 @@ import { hexToBuf, DataFn, ErrTuple } from "@siaweb/libweb"; import type { EventEmitter } from "eventemitter3"; +import backoff, { Backoff } from "backoff"; + export class SwarmClient extends Client { private useDefaultSwarm: boolean; private id: number = 0; + private _autoReconnect: boolean; + private _connectBackoff: Backoff; - constructor(useDefaultDht = true) { + private _ready?: Promise; + + constructor(useDefaultDht = true, autoReconnect = false) { super(); this.useDefaultSwarm = useDefaultDht; + this._autoReconnect = autoReconnect; + this._connectBackoff = backoff.fibonacci(); + + this._connectBackoff.on("ready", () => { + this.start(); + }); } get swarm(): number | undefined { @@ -31,10 +43,19 @@ export class SwarmClient extends Client { return createSocket(resp.id); } async init(): Promise { - return this.callModuleReturn("init", { swarm: this.swarm }); + const ret = await this.callModuleReturn("init", { swarm: this.swarm }); + this._connectBackoff.reset(); + + return ret; } async ready(): Promise { - await this.callModuleReturn("ready", { swarm: this.swarm }); + if (this._ready) { + return this._ready; + } + + this._ready = this.callModuleReturn("ready", { swarm: this.swarm }); + + await this._ready; this.connectModule( "listenConnections", @@ -43,6 +64,25 @@ export class SwarmClient extends Client { this.emit("connection", await createSocket(socketId)); } ); + + this._ready = undefined; + } + + async start(): Promise { + let ready = this.ready(); + + const backoff = () => setImmediate(() => this._connectBackoff.backoff()); + + try { + await this.init(); + } catch (e) { + this.logErr(e); + backoff(); + } + + this.once("close", backoff); + + await ready; } public async addRelay(pubkey: string): Promise {