diff --git a/dist/index.d.ts b/dist/index.d.ts
index 63f8ea2..37d56ea 100644
--- a/dist/index.d.ts
+++ b/dist/index.d.ts
@@ -1,20 +1,26 @@
+///
import DhtNode from "@hyperswarm/dht-relay";
-export default class DHT {
+import Hyperswarm from "hyperswarm";
+import EventEmitter from "node:events";
+export default class HyperswarmWeb extends EventEmitter {
private _options;
private _relays;
- private _activeRelays;
- private _maxConnections;
- private _inited;
- constructor(opts?: {});
+ private _activeRelay;
+ private _discovery;
+ constructor(opts?: any);
ready(): Promise;
- get relays(): string[];
- get relayServers(): string[];
- addRelay(pubkey: string): Promise;
- removeRelay(pubkey: string): boolean;
- clearRelays(): void;
+ private ensureConnection;
private isServerAvailable;
connect(pubkey: string, options?: {}): Promise;
- private fillConnections;
+ get relays(): string[];
+ addRelay(pubkey: string): Promise;
+ removeRelay(pubkey: string): boolean;
+ clearRelays(): void;
+ on(eventName: string | symbol, listener: (...args: any[]) => void): Hyperswarm;
+ addListener(eventName: string | symbol, listener: (...args: any[]) => void): this;
+ off(eventName: string | symbol, listener: (...args: any[]) => void): Hyperswarm;
+ removeListener(eventName: string | symbol, listener: (...args: any[]) => void): this;
+ emit(eventName: string | symbol, ...args: any[]): boolean;
+ once(eventName: string | symbol, listener: (...args: any[]) => void): this;
}
-export declare function hashDataKey(dataKey: string): Uint8Array;
//# sourceMappingURL=index.d.ts.map
\ No newline at end of file
diff --git a/dist/index.d.ts.map b/dist/index.d.ts.map
index b91cced..72b9be5 100644
--- a/dist/index.d.ts.map
+++ b/dist/index.d.ts.map
@@ -1 +1 @@
-{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,OAAO,MAAM,uBAAuB,CAAC;AAgB5C,MAAM,CAAC,OAAO,OAAO,GAAG;IACtB,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,aAAa,CAA0C;IAC/D,OAAO,CAAC,eAAe,CAAM;IAC7B,OAAO,CAAC,OAAO,CAAS;gBAEZ,IAAI,KAAK;IAMrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAStB,IAAI,MAAM,IAAI,MAAM,EAAE,CAErB;IAED,IAAI,YAAY,IAAI,MAAM,EAAE,CAE3B;IAEY,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAiChD,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAepC,WAAW,IAAI,IAAI;YAIZ,iBAAiB;IAazB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC;YAmB/C,eAAe;CAkD9B;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAEvD"}
\ No newline at end of file
+{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,OAAO,MAAM,uBAAuB,CAAC;AAW5C,OAAO,UAAU,MAAM,YAAY,CAAC;AAEpC,OAAO,YAAY,MAAM,aAAa,CAAC;AAEvC,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,YAAY;IACrD,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,UAAU,CAAsB;gBAC5B,IAAI,GAAE,GAAQ;IAO1B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAIR,gBAAgB;YAgDhB,iBAAiB;IAYzB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC;IAQ7D,IAAI,MAAM,IAAI,MAAM,EAAE,CAErB;IAEY,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7C,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAUpC,WAAW,IAAI,IAAI;IAI1B,EAAE,CACA,SAAS,EAAE,MAAM,GAAG,MAAM,EAC1B,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,GACjC,UAAU;IAGb,WAAW,CACT,SAAS,EAAE,MAAM,GAAG,MAAM,EAC1B,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,GACjC,IAAI;IAIP,GAAG,CACD,SAAS,EAAE,MAAM,GAAG,MAAM,EAC1B,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,GACjC,UAAU;IAIb,cAAc,CACZ,SAAS,EAAE,MAAM,GAAG,MAAM,EAC1B,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,GACjC,IAAI;IAGP,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO;IAIzD,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,GAAG,IAAI;CAG3E"}
\ No newline at end of file
diff --git a/dist/index.js b/dist/index.js
index fae8faf..10759ed 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -2,73 +2,57 @@
import DhtNode from "@hyperswarm/dht-relay";
// @ts-ignore
import Stream from "@hyperswarm/dht-relay/ws";
-// @ts-ignore
-// @ts-ignore
-import { blake2b, hexToBuf } from "libskynet";
-// @ts-ignore
-import { registryRead } from "libkmodule";
-import { unpack } from "msgpackr";
+import { createClient } from "@lumeweb/kernel-peer-discovery-client";
+import { load } from "@lumeweb/libkernel-universal";
import randomNumber from "random-number-csprng";
-const REGISTRY_DHT_KEY = "lumeweb-dht-node";
-export default class DHT {
+import EventEmitter from "node:events";
+export default class HyperswarmWeb extends EventEmitter {
_options;
- _relays = new Map();
- _activeRelays = new Map();
- _maxConnections = 10;
- _inited = false;
+ _relays = new Set();
+ _activeRelay;
+ _discovery;
constructor(opts = {}) {
- // @ts-ignore
+ super();
opts.custodial = false;
this._options = opts;
+ this._discovery = createClient();
}
ready() {
- if (this._inited) {
- return Promise.resolve();
- }
- this._inited = true;
- return this.fillConnections();
+ return this.ensureConnection();
}
- get relays() {
- return [...this._relays.keys()];
- }
- get relayServers() {
- return [...this._relays.values()];
- }
- async addRelay(pubkey) {
- let entry = await registryRead(hexToBuf(pubkey).shift(), hashDataKey(REGISTRY_DHT_KEY));
- if (entry[1] || !entry[0]?.exists) {
- return false;
+ async ensureConnection() {
+ const logErr = (await load()).logErr;
+ if (this._activeRelay) {
+ return;
}
- let host;
- try {
- host = unpack(entry[0].entryData);
+ const relays = this.relays;
+ do {
+ const index = await randomNumber(0, relays.length - 1);
+ const relay = relays[index];
+ let ret;
+ try {
+ ret = await this._discovery.discover(relay);
+ }
+ catch (e) {
+ logErr(e);
+ relays.splice(index, 1);
+ continue;
+ }
+ ret = ret;
+ const connection = `wss://${ret.host}:${ret.port}`;
+ if (!(await this.isServerAvailable(connection))) {
+ relays.splice(index, 1);
+ continue;
+ }
+ this._activeRelay = new DhtNode(new Stream(true, new WebSocket(connection)), this._options);
+ this._activeRelay.on("close", () => {
+ this._activeRelay = undefined;
+ });
+ } while (relays.length > 0);
+ if (!this._activeRelay) {
+ throw new Error("Failed to find an available relay");
}
- catch (e) {
- return false;
- }
- const [domain, port] = host.split(":");
- if (isNaN(parseInt(port))) {
- return false;
- }
- this._relays.set(pubkey, `wss://${domain}:${port}/`);
- if (this._inited) {
- await this.fillConnections();
- }
- return true;
- }
- removeRelay(pubkey) {
- if (!this._relays.has(pubkey)) {
- return false;
- }
- if (this._activeRelays.has(pubkey)) {
- this._activeRelays.get(pubkey).destroy();
- this._activeRelays.delete(pubkey);
- }
- this._relays.delete(pubkey);
- return true;
- }
- clearRelays() {
- [...this._relays.keys()].forEach(this.removeRelay);
+ await this._activeRelay.dht.ready();
}
async isServerAvailable(connection) {
return new Promise((resolve) => {
@@ -83,71 +67,43 @@ export default class DHT {
});
}
async connect(pubkey, options = {}) {
- if (this._activeRelays.size === 0) {
- await this.fillConnections();
+ if (!this._activeRelay) {
+ await this.ensureConnection();
}
- if (this._activeRelays.size === 0) {
- throw new Error("Failed to find an available relay");
- }
- let index = 0;
- if (this._activeRelays.size > 1) {
- index = await randomNumber(0, this._activeRelays.size - 1);
- }
- const node = this._activeRelays.get([...this._activeRelays.keys()][index]);
- return node.connect(pubkey, options);
+ return this._activeRelay.connect(pubkey, options);
}
- async fillConnections() {
- let available = [];
- const updateAvailable = () => {
- available = [...this._relays.keys()].filter((x) => ![...this._activeRelays.keys()].includes(x));
- };
- updateAvailable();
- let relayPromises = [];
- while (this._activeRelays.size <=
- Math.min(this._maxConnections, available.length)) {
- if (0 === available.length) {
- break;
- }
- let relayIndex = 0;
- if (available.length > 1) {
- relayIndex = await randomNumber(0, available.length - 1);
- }
- const pubkey = available[relayIndex];
- const connection = this._relays.get(available[relayIndex]);
- if (!(await this.isServerAvailable(connection))) {
- available.splice(relayIndex, 1);
- this.removeRelay(available[relayIndex]);
- continue;
- }
- const node = new DhtNode(new Stream(true, new WebSocket(connection)), this._options);
- this._activeRelays.set(available[relayIndex], node);
- updateAvailable();
- relayPromises.push(node.ready());
- node._protocol._stream.on("close", () => {
- this._activeRelays.delete(pubkey);
- });
+ get relays() {
+ return [...this._relays.values()];
+ }
+ async addRelay(pubkey) {
+ this._relays.add(pubkey);
+ }
+ removeRelay(pubkey) {
+ if (!this._relays.has(pubkey)) {
+ return false;
}
- return Promise.allSettled(relayPromises);
+ this._relays.delete(pubkey);
+ return true;
+ }
+ clearRelays() {
+ this._relays.clear();
+ }
+ on(eventName, listener) {
+ return this._activeRelay?.on(eventName, listener);
+ }
+ addListener(eventName, listener) {
+ return this.on(eventName, listener);
+ }
+ off(eventName, listener) {
+ return this._activeRelay?.off(eventName, listener);
+ }
+ removeListener(eventName, listener) {
+ return this.on(eventName, listener);
+ }
+ emit(eventName, ...args) {
+ return this._activeRelay?.emit(eventName, ...args);
+ }
+ once(eventName, listener) {
+ return this._activeRelay?.once(eventName, listener);
}
}
-export function hashDataKey(dataKey) {
- return blake2b(encodeUtf8String(dataKey));
-}
-function encodeUtf8String(str) {
- const byteArray = stringToUint8ArrayUtf8(str);
- const encoded = new Uint8Array(8 + byteArray.length);
- encoded.set(encodeNumber(byteArray.length));
- encoded.set(byteArray, 8);
- return encoded;
-}
-function stringToUint8ArrayUtf8(str) {
- return new TextEncoder().encode(str);
-}
-function encodeNumber(num) {
- const encoded = new Uint8Array(8);
- for (let index = 0; index < encoded.length; index++) {
- encoded[index] = num & 0xff;
- num = num >> 8;
- }
- return encoded;
-}