diff --git a/dist/network.d.ts b/dist/network.d.ts
new file mode 100644
index 0000000..a846787
--- /dev/null
+++ b/dist/network.d.ts
@@ -0,0 +1,52 @@
+///
+import WisdomRpcQuery from "./query/wisdom.js";
+import StreamingRpcQuery from "./query/streaming.js";
+import { RpcQueryOptions, StreamHandlerFunction } from "./types.js";
+import SimpleRpcQuery from "./query/simple.js";
+export default class RpcNetwork {
+ constructor(dht?: any);
+ private _dht;
+ get dht(): any;
+ private _majorityThreshold;
+ get majorityThreshold(): number;
+ set majorityThreshold(value: number);
+ private _queryTimeout;
+ get queryTimeout(): number;
+ set queryTimeout(value: number);
+ private _relayTimeout;
+ get relayTimeout(): number;
+ set relayTimeout(value: number);
+ private _relays;
+ get relays(): string[];
+ private _ready?;
+ get ready(): Promise;
+ private _bypassCache;
+ get bypassCache(): boolean;
+ set bypassCache(value: boolean);
+ addRelay(pubkey: string): void;
+ removeRelay(pubkey: string): boolean;
+ clearRelays(): void;
+ wisdomQuery(
+ method: string,
+ module: string,
+ data?: object | any[],
+ bypassCache?: boolean,
+ options?: RpcQueryOptions
+ ): WisdomRpcQuery;
+ streamingQuery(
+ relay: Buffer | string,
+ method: string,
+ module: string,
+ streamHandler: StreamHandlerFunction,
+ data?: object | any[],
+ options?: RpcQueryOptions
+ ): StreamingRpcQuery;
+ simpleQuery(
+ relay: Buffer | string,
+ method: string,
+ module: string,
+ data?: object | any[],
+ options?: RpcQueryOptions
+ ): SimpleRpcQuery;
+}
+//# sourceMappingURL=network.d.ts.map
diff --git a/dist/network.d.ts.map b/dist/network.d.ts.map
new file mode 100644
index 0000000..2de052d
--- /dev/null
+++ b/dist/network.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../src/network.ts"],"names":[],"mappings":";AAAA,OAAO,cAAc,MAAM,mBAAmB,CAAC;AAG/C,OAAO,iBAAiB,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,cAAc,MAAM,mBAAmB,CAAC;AAE/C,MAAM,CAAC,OAAO,OAAO,UAAU;gBACjB,GAAG,MAAY;IAI3B,OAAO,CAAC,IAAI,CAAa;IAEzB,IAAI,GAAG,QAEN;IAED,OAAO,CAAC,kBAAkB,CAAQ;IAElC,IAAI,iBAAiB,IAAI,MAAM,CAE9B;IAED,IAAI,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAElC;IAED,OAAO,CAAC,aAAa,CAAM;IAE3B,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,IAAI,YAAY,CAAC,KAAK,EAAE,MAAM,EAE7B;IAED,OAAO,CAAC,aAAa,CAAK;IAE1B,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,IAAI,YAAY,CAAC,KAAK,EAAE,MAAM,EAE7B;IAED,OAAO,CAAC,OAAO,CAAgB;IAE/B,IAAI,MAAM,IAAI,MAAM,EAAE,CAErB;IAED,OAAO,CAAC,MAAM,CAAC,CAAgB;IAE/B,IAAI,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAKzB;IAED,OAAO,CAAC,YAAY,CAAkB;IAEtC,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,IAAI,WAAW,CAAC,KAAK,EAAE,OAAO,EAE7B;IAEM,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAK9B,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAWpC,WAAW,IAAI,IAAI;IAInB,WAAW,CAChB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,MAAM,GAAG,GAAG,EAAO,EACzB,WAAW,GAAE,OAAe,EAC5B,OAAO,GAAE,eAAoB,GAC5B,cAAc;IAaV,cAAc,CACnB,KAAK,EAAE,MAAM,GAAG,MAAM,EACtB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,qBAAqB,EACpC,IAAI,GAAE,MAAM,GAAG,GAAG,EAAO,EACzB,OAAO,GAAE,eAAoB,GAC5B,iBAAiB;IASb,WAAW,CAChB,KAAK,EAAE,MAAM,GAAG,MAAM,EACtB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,MAAM,GAAG,GAAG,EAAO,EACzB,OAAO,GAAE,eAAoB,GAC5B,cAAc;CAYlB"}
\ No newline at end of file
diff --git a/dist/network.js b/dist/network.js
new file mode 100644
index 0000000..3ed672c
--- /dev/null
+++ b/dist/network.js
@@ -0,0 +1,86 @@
+import WisdomRpcQuery from "./query/wisdom.js";
+// @ts-ignore
+import DHT from "@hyperswarm/dht";
+import StreamingRpcQuery from "./query/streaming.js";
+import SimpleRpcQuery from "./query/simple.js";
+export default class RpcNetwork {
+ constructor(dht = new DHT()) {
+ this._dht = dht;
+ }
+ _dht;
+ get dht() {
+ return this._dht;
+ }
+ _majorityThreshold = 0.75;
+ get majorityThreshold() {
+ return this._majorityThreshold;
+ }
+ set majorityThreshold(value) {
+ this._majorityThreshold = value;
+ }
+ _queryTimeout = 30;
+ get queryTimeout() {
+ return this._queryTimeout;
+ }
+ set queryTimeout(value) {
+ this._queryTimeout = value;
+ }
+ _relayTimeout = 2;
+ get relayTimeout() {
+ return this._relayTimeout;
+ }
+ set relayTimeout(value) {
+ this._relayTimeout = value;
+ }
+ _relays = [];
+ get relays() {
+ return this._relays;
+ }
+ _ready;
+ get ready() {
+ if (!this._ready) {
+ this._ready = this._dht.ready();
+ }
+ return this._ready;
+ }
+ _bypassCache = false;
+ get bypassCache() {
+ return this._bypassCache;
+ }
+ set bypassCache(value) {
+ this._bypassCache = value;
+ }
+ addRelay(pubkey) {
+ this._relays.push(pubkey);
+ this._relays = [...new Set(this._relays)];
+ }
+ removeRelay(pubkey) {
+ if (!this._relays.includes(pubkey)) {
+ return false;
+ }
+ delete this._relays[this._relays.indexOf(pubkey)];
+ this._relays = Object.values(this._relays);
+ return true;
+ }
+ clearRelays() {
+ this._relays = [];
+ }
+ wisdomQuery(method, module, data = {}, bypassCache = false, options = {}) {
+ return new WisdomRpcQuery(this, {
+ method,
+ module,
+ data,
+ bypassCache: bypassCache || this._bypassCache,
+ }, options).run();
+ }
+ streamingQuery(relay, method, module, streamHandler, data = {}, options = {}) {
+ return new StreamingRpcQuery(this, relay, { method, module, data }, { streamHandler, ...options }).run();
+ }
+ simpleQuery(relay, method, module, data = {}, options = {}) {
+ return new SimpleRpcQuery(this, relay, {
+ method,
+ module,
+ data,
+ }, options).run();
+ }
+}
diff --git a/dist/query/base.d.ts b/dist/query/base.d.ts
new file mode 100644
index 0000000..8979931
--- /dev/null
+++ b/dist/query/base.d.ts
@@ -0,0 +1,34 @@
+///
+import { Buffer } from "buffer";
+import RpcNetwork from "../network.js";
+import { RpcQueryOptions } from "../types.js";
+import type { RPCRequest, RPCResponse } from "@lumeweb/relay";
+export default abstract class RpcQueryBase {
+ protected _network: RpcNetwork;
+ protected _query: RPCRequest;
+ protected _options: RpcQueryOptions;
+ protected _promise?: Promise;
+ protected _timeoutTimer?: any;
+ protected _timeout: boolean;
+ protected _completed: boolean;
+ protected _responses: {
+ [relay: string]: RPCResponse;
+ };
+ protected _errors: {
+ [relay: string]: any;
+ };
+ protected _promiseResolve?: (data: any) => void;
+ constructor(
+ network: RpcNetwork,
+ query: RPCRequest,
+ options?: RpcQueryOptions
+ );
+ get result(): Promise;
+ private handeTimeout;
+ protected resolve(data?: RPCResponse, timeout?: boolean): void;
+ run(): this;
+ protected queryRelay(relay: string | Buffer): Promise;
+ protected abstract checkResponses(): void;
+ protected abstract getRelays(): string[] | Buffer[];
+}
+//# sourceMappingURL=base.d.ts.map
diff --git a/dist/query/base.d.ts.map b/dist/query/base.d.ts.map
new file mode 100644
index 0000000..c5ed8c9
--- /dev/null
+++ b/dist/query/base.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/query/base.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,UAAU,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE9D,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,YAAY;IACxC,SAAS,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC/B,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC;IAC7B,SAAS,CAAC,QAAQ,EAAE,eAAe,CAAC;IAEpC,SAAS,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAClC,SAAS,CAAC,aAAa,CAAC,EAAE,GAAG,CAAC;IAC9B,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAS;IACpC,SAAS,CAAC,UAAU,EAAE,OAAO,CAAS;IACtC,SAAS,CAAC,UAAU,EAAE;QAAE,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAAA;KAAE,CAAM;IAC5D,SAAS,CAAC,OAAO,EAAE;QAAE,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAM;IACjD,SAAS,CAAC,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;gBAG9C,OAAO,EAAE,UAAU,EACnB,KAAK,EAAE,UAAU,EACjB,OAAO,GAAE,eAAoB;IAO/B,IAAI,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC,CAEjC;IAED,OAAO,CAAC,YAAY;IAIpB,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,OAAO,GAAE,OAAe,GAAG,IAAI;IAc9D,GAAG,IAAI,IAAI;cA2BF,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAmDhE,SAAS,CAAC,QAAQ,CAAC,cAAc,IAAI,IAAI;IAEzC,SAAS,CAAC,QAAQ,CAAC,SAAS,IAAI,MAAM,EAAE,GAAG,MAAM,EAAE;CACpD"}
\ No newline at end of file
diff --git a/dist/query/base.js b/dist/query/base.js
new file mode 100644
index 0000000..b755910
--- /dev/null
+++ b/dist/query/base.js
@@ -0,0 +1,104 @@
+import { clearTimeout, setTimeout } from "timers";
+import { pack, unpack } from "msgpackr";
+import { Buffer } from "buffer";
+import { isPromise } from "../util.js";
+export default class RpcQueryBase {
+ _network;
+ _query;
+ _options;
+ _promise;
+ _timeoutTimer;
+ _timeout = false;
+ _completed = false;
+ _responses = {};
+ _errors = {};
+ _promiseResolve;
+ constructor(network, query, options = {}) {
+ this._network = network;
+ this._query = query;
+ this._options = options;
+ }
+ get result() {
+ return this._promise;
+ }
+ handeTimeout() {
+ this.resolve(undefined, true);
+ }
+ resolve(data, timeout = false) {
+ clearTimeout(this._timeoutTimer);
+ this._timeout = timeout;
+ this._completed = true;
+ if (timeout) {
+ data = {
+ error: "timeout",
+ };
+ }
+ this._promiseResolve?.(data);
+ }
+ run() {
+ this._promise =
+ this._promise ??
+ new Promise((resolve) => {
+ this._promiseResolve = resolve;
+ });
+ this._timeoutTimer =
+ this._timeoutTimer ??
+ setTimeout(this.handeTimeout.bind(this), (this._options.queryTimeout || this._network.queryTimeout) * 1000);
+ this._network.ready.then(() => {
+ const promises = [];
+ for (const relay of this.getRelays()) {
+ promises.push(this.queryRelay(relay));
+ }
+ Promise.allSettled(promises).then(() => this.checkResponses());
+ });
+ return this;
+ }
+ async queryRelay(relay) {
+ let socket;
+ let relayKey = relay;
+ if (typeof relay === "string") {
+ relayKey = Buffer.from(relay, "hex");
+ }
+ if (relay instanceof Buffer) {
+ relayKey = relay;
+ relay = relay.toString("hex");
+ }
+ try {
+ socket = this._network.dht.connect(relayKey);
+ if (isPromise(socket)) {
+ socket = await socket;
+ }
+ }
+ catch (e) {
+ return;
+ }
+ return new Promise((resolve, reject) => {
+ let timer;
+ socket.on("data", (res) => {
+ relay = relay;
+ if (timer && timer.close) {
+ clearTimeout(timer);
+ }
+ socket.end();
+ const response = unpack(res);
+ if (response && response.error) {
+ this._errors[relay] = response.error;
+ return reject(null);
+ }
+ this._responses[relay] = response;
+ resolve(null);
+ });
+ socket.on("error", (error) => {
+ relay = relay;
+ this._errors[relay] = error;
+ reject({ error });
+ });
+ socket.write("rpc");
+ socket.write(pack(this._query));
+ timer = setTimeout(() => {
+ this._errors[relay] = "timeout";
+ reject(null);
+ }, (this._options.relayTimeout || this._network.relayTimeout) * 1000);
+ });
+ }
+}
diff --git a/dist/query/simple.d.ts b/dist/query/simple.d.ts
new file mode 100644
index 0000000..bbe01ac
--- /dev/null
+++ b/dist/query/simple.d.ts
@@ -0,0 +1,18 @@
+///
+import RpcQueryBase from "./base.js";
+import RpcNetwork from "../network.js";
+import type { RPCRequest } from "@lumeweb/relay";
+import { RpcQueryOptions } from "../types.js";
+import type { Buffer } from "buffer";
+export default class SimpleRpcQuery extends RpcQueryBase {
+ private _relay;
+ constructor(
+ network: RpcNetwork,
+ relay: string | Buffer,
+ query: RPCRequest,
+ options: RpcQueryOptions
+ );
+ protected checkResponses(): void;
+ protected getRelays(): string[] | Buffer[];
+}
+//# sourceMappingURL=simple.d.ts.map
diff --git a/dist/query/simple.d.ts.map b/dist/query/simple.d.ts.map
new file mode 100644
index 0000000..b589827
--- /dev/null
+++ b/dist/query/simple.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"simple.d.ts","sourceRoot":"","sources":["../../src/query/simple.ts"],"names":[],"mappings":";AAAA,OAAO,YAAY,MAAM,WAAW,CAAC;AACrC,OAAO,UAAU,MAAM,eAAe,CAAC;AACvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,YAAY;IACtD,OAAO,CAAC,MAAM,CAAkB;gBAE9B,OAAO,EAAE,UAAU,EACnB,KAAK,EAAE,MAAM,GAAG,MAAM,EACtB,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,eAAe;IAM1B,SAAS,CAAC,cAAc,IAAI,IAAI;IAYhC,SAAS,CAAC,SAAS,IAAI,MAAM,EAAE,GAAG,MAAM,EAAE;CAG3C"}
\ No newline at end of file
diff --git a/dist/query/simple.js b/dist/query/simple.js
new file mode 100644
index 0000000..5ce845b
--- /dev/null
+++ b/dist/query/simple.js
@@ -0,0 +1,21 @@
+import RpcQueryBase from "./base.js";
+export default class SimpleRpcQuery extends RpcQueryBase {
+ _relay;
+ constructor(network, relay, query, options) {
+ super(network, query, options);
+ this._relay = relay;
+ }
+ checkResponses() {
+ if (Object.keys(this._responses).length) {
+ this.resolve(Object.values(this._responses).pop());
+ return;
+ }
+ if (Object.keys(this._errors).length) {
+ this.resolve({ error: Object.values(this._errors).pop() });
+ return;
+ }
+ }
+ getRelays() {
+ return [this._relay];
+ }
+}
diff --git a/dist/query/streaming.d.ts b/dist/query/streaming.d.ts
new file mode 100644
index 0000000..a7a6aa5
--- /dev/null
+++ b/dist/query/streaming.d.ts
@@ -0,0 +1,17 @@
+///
+import SimpleRpcQuery from "./simple.js";
+import { Buffer } from "buffer";
+import type { RPCRequest } from "@lumeweb/relay";
+import RpcNetwork from "../network.js";
+import { StreamingRpcQueryOptions } from "../types.js";
+export default class StreamingRpcQuery extends SimpleRpcQuery {
+ protected _options: StreamingRpcQueryOptions;
+ constructor(
+ network: RpcNetwork,
+ relay: string | Buffer,
+ query: RPCRequest,
+ options: StreamingRpcQueryOptions
+ );
+ protected queryRelay(relay: string | Buffer): Promise;
+}
+//# sourceMappingURL=streaming.d.ts.map
diff --git a/dist/query/streaming.d.ts.map b/dist/query/streaming.d.ts.map
new file mode 100644
index 0000000..451c814
--- /dev/null
+++ b/dist/query/streaming.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"streaming.d.ts","sourceRoot":"","sources":["../../src/query/streaming.ts"],"names":[],"mappings":";AAAA,OAAO,cAAc,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAIhC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,UAAU,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAEvD,MAAM,CAAC,OAAO,OAAO,iBAAkB,SAAQ,cAAc;IAC3D,SAAS,CAAC,QAAQ,EAAE,wBAAwB,CAAC;gBAE3C,OAAO,EAAE,UAAU,EACnB,KAAK,EAAE,MAAM,GAAG,MAAM,EACtB,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,wBAAwB;cAKnB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;CAwDjE"}
\ No newline at end of file
diff --git a/dist/query/streaming.js b/dist/query/streaming.js
new file mode 100644
index 0000000..aa06668
--- /dev/null
+++ b/dist/query/streaming.js
@@ -0,0 +1,64 @@
+import SimpleRpcQuery from "./simple.js";
+import { Buffer } from "buffer";
+import { isPromise } from "../util.js";
+import { clearTimeout, setTimeout } from "timers";
+import { pack, unpack } from "msgpackr";
+export default class StreamingRpcQuery extends SimpleRpcQuery {
+ _options;
+ constructor(network, relay, query, options) {
+ super(network, relay, query, options);
+ this._options = options;
+ }
+ async queryRelay(relay) {
+ let socket;
+ let relayKey = relay;
+ if (relay === "string") {
+ relayKey = Buffer.from(relay, "hex");
+ }
+ if (relay instanceof Buffer) {
+ relayKey = relay;
+ relay = relay.toString("hex");
+ }
+ try {
+ socket = this._network.dht.connect(relayKey);
+ if (isPromise(socket)) {
+ socket = await socket;
+ }
+ }
+ catch (e) {
+ return;
+ }
+ return new Promise((resolve, reject) => {
+ let timer;
+ socket.on("data", (res) => {
+ relay = relay;
+ if (timer && timer.close) {
+ clearTimeout(timer);
+ }
+ socket.end();
+ const response = unpack(res);
+ if (response && response.error) {
+ this._errors[relay] = response.error;
+ return reject(null);
+ }
+ if (response?.data.done) {
+ this._responses[relay] = {};
+ resolve(null);
+ return;
+ }
+ this._options.streamHandler(response?.data.data);
+ });
+ socket.on("error", (error) => {
+ relay = relay;
+ this._errors[relay] = error;
+ reject({ error });
+ });
+ socket.write("rpc");
+ socket.write(pack(this._query));
+ timer = setTimeout(() => {
+ this._errors[relay] = "timeout";
+ reject(null);
+ }, (this._options.relayTimeout || this._network.relayTimeout) * 1000);
+ });
+ }
+}
diff --git a/dist/query/wisdom.d.ts b/dist/query/wisdom.d.ts
new file mode 100644
index 0000000..01440c6
--- /dev/null
+++ b/dist/query/wisdom.d.ts
@@ -0,0 +1,9 @@
+import RpcQueryBase from "./base.js";
+export default class WisdomRpcQuery extends RpcQueryBase {
+ private _maxTries;
+ private _tries;
+ protected checkResponses(): void;
+ private retry;
+ protected getRelays(): string[] | [];
+}
+//# sourceMappingURL=wisdom.d.ts.map
diff --git a/dist/query/wisdom.d.ts.map b/dist/query/wisdom.d.ts.map
new file mode 100644
index 0000000..87f5d4f
--- /dev/null
+++ b/dist/query/wisdom.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"wisdom.d.ts","sourceRoot":"","sources":["../../src/query/wisdom.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,WAAW,CAAC;AAOrC,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,YAAY;IACtD,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,MAAM,CAAK;IAEnB,SAAS,CAAC,cAAc,IAAI,IAAI;IAoDhC,OAAO,CAAC,KAAK;IAWb,SAAS,CAAC,SAAS,IAAI,MAAM,EAAE,GAAG,EAAE;CAGrC"}
\ No newline at end of file
diff --git a/dist/query/wisdom.js b/dist/query/wisdom.js
new file mode 100644
index 0000000..bb22d55
--- /dev/null
+++ b/dist/query/wisdom.js
@@ -0,0 +1,54 @@
+import RpcQueryBase from "./base.js";
+import { flatten } from "../util.js";
+import { Buffer } from "buffer";
+import { blake2b } from "libskynet";
+import { ERR_MAX_TRIES_HIT } from "../error.js";
+export default class WisdomRpcQuery extends RpcQueryBase {
+ _maxTries = 3;
+ _tries = 0;
+ checkResponses() {
+ const responseStore = this._responses;
+ const responseStoreData = Object.values(responseStore);
+ const responseObjects = responseStoreData.reduce((output, item) => {
+ const itemFlattened = flatten(item?.data).sort();
+ const hash = Buffer.from(blake2b(Buffer.from(JSON.stringify(itemFlattened)))).toString("hex");
+ output[hash] = item?.data;
+ return output;
+ }, {});
+ const responses = responseStoreData.reduce((output, item) => {
+ const itemFlattened = flatten(item?.data).sort();
+ const hash = Buffer.from(blake2b(Buffer.from(JSON.stringify(itemFlattened)))).toString("hex");
+ output[hash] = output[hash] ?? 0;
+ output[hash]++;
+ return output;
+ }, {});
+ for (const responseHash in responses) {
+ if (responses[responseHash] / responseStoreData.length >=
+ this._network.majorityThreshold) {
+ let response = responseObjects[responseHash];
+ // @ts-ignore
+ if (null === response) {
+ if (this._tries <= this._maxTries) {
+ this._tries++;
+ this.retry();
+ return;
+ }
+ response = { error: ERR_MAX_TRIES_HIT };
+ }
+ this.resolve(response);
+ break;
+ }
+ }
+ }
+ retry() {
+ this._responses = {};
+ this._errors = {};
+ if (this._completed) {
+ return;
+ }
+ this.run();
+ }
+ getRelays() {
+ return this._network.relays;
+ }
+}