2022-07-19 18:43:28 +00:00
|
|
|
// @ts-ignore
|
2023-03-18 16:11:23 +00:00
|
|
|
import Hyperswarm from "hyperswarm";
|
2022-12-04 11:35:57 +00:00
|
|
|
import RpcNetworkQueryFactory from "./query/index.js";
|
2023-03-18 16:11:23 +00:00
|
|
|
import b4a from "b4a";
|
2023-03-25 14:51:07 +00:00
|
|
|
import { createHash, maybeGetAsyncProperty } from "./util.js";
|
2022-06-27 19:36:29 +00:00
|
|
|
|
|
|
|
export default class RpcNetwork {
|
2023-03-18 16:11:23 +00:00
|
|
|
private _relaysAvailablePromise?: Promise<void>;
|
|
|
|
private _relaysAvailableResolve?: Function;
|
|
|
|
constructor(swarm = new Hyperswarm()) {
|
|
|
|
this._swarm = swarm;
|
|
|
|
this.init();
|
|
|
|
}
|
|
|
|
|
|
|
|
private _methods: Map<string, Set<string>> = new Map<string, Set<string>>();
|
|
|
|
|
|
|
|
get methods(): Map<string, Set<string>> {
|
|
|
|
return this._methods;
|
2022-06-27 19:36:29 +00:00
|
|
|
}
|
|
|
|
|
2022-12-04 11:35:57 +00:00
|
|
|
private _factory = new RpcNetworkQueryFactory(this);
|
|
|
|
|
|
|
|
get factory(): RpcNetworkQueryFactory {
|
|
|
|
return this._factory;
|
|
|
|
}
|
|
|
|
|
2023-03-18 16:11:23 +00:00
|
|
|
private _swarm: typeof Hyperswarm;
|
2022-07-23 15:39:17 +00:00
|
|
|
|
2023-03-18 16:11:23 +00:00
|
|
|
get swarm() {
|
|
|
|
return this._swarm;
|
2022-06-27 19:36:29 +00:00
|
|
|
}
|
|
|
|
|
2022-07-23 15:39:17 +00:00
|
|
|
private _majorityThreshold = 0.75;
|
|
|
|
|
|
|
|
get majorityThreshold(): number {
|
|
|
|
return this._majorityThreshold;
|
2022-06-27 19:36:29 +00:00
|
|
|
}
|
|
|
|
|
2022-07-23 15:39:17 +00:00
|
|
|
set majorityThreshold(value: number) {
|
|
|
|
this._majorityThreshold = value;
|
2022-06-27 19:36:29 +00:00
|
|
|
}
|
|
|
|
|
2022-07-23 15:39:17 +00:00
|
|
|
private _queryTimeout = 30;
|
|
|
|
|
2022-06-27 19:36:29 +00:00
|
|
|
get queryTimeout(): number {
|
|
|
|
return this._queryTimeout;
|
|
|
|
}
|
|
|
|
|
|
|
|
set queryTimeout(value: number) {
|
|
|
|
this._queryTimeout = value;
|
|
|
|
}
|
|
|
|
|
2022-07-23 15:39:17 +00:00
|
|
|
private _relayTimeout = 2;
|
|
|
|
|
|
|
|
get relayTimeout(): number {
|
|
|
|
return this._relayTimeout;
|
2022-06-27 19:36:29 +00:00
|
|
|
}
|
|
|
|
|
2022-07-23 15:39:17 +00:00
|
|
|
set relayTimeout(value: number) {
|
|
|
|
this._relayTimeout = value;
|
2022-06-27 19:36:29 +00:00
|
|
|
}
|
|
|
|
|
2023-03-18 16:11:23 +00:00
|
|
|
private _relays: Map<string, any> = new Map<string, string[]>();
|
2022-07-23 15:39:17 +00:00
|
|
|
|
2023-03-18 16:11:23 +00:00
|
|
|
get relays(): Map<string, string[]> {
|
2022-07-23 15:39:17 +00:00
|
|
|
return this._relays;
|
|
|
|
}
|
|
|
|
|
2022-07-27 01:25:38 +00:00
|
|
|
private _ready?: Promise<void>;
|
2022-07-23 15:39:17 +00:00
|
|
|
|
|
|
|
get ready(): Promise<void> {
|
2022-07-27 00:58:41 +00:00
|
|
|
if (!this._ready) {
|
2023-03-25 14:51:07 +00:00
|
|
|
this._ready = maybeGetAsyncProperty(this._swarm.dht).then((dht: any) =>
|
|
|
|
dht.ready()
|
|
|
|
) as Promise<void>;
|
2022-07-27 00:58:41 +00:00
|
|
|
}
|
2022-12-04 07:40:36 +00:00
|
|
|
|
2023-03-25 13:42:42 +00:00
|
|
|
return this._ready as Promise<void>;
|
2022-07-23 15:39:17 +00:00
|
|
|
}
|
|
|
|
|
2023-03-18 16:11:23 +00:00
|
|
|
get readyWithRelays(): Promise<void> {
|
|
|
|
return this.ready.then(() => this._relaysAvailablePromise);
|
|
|
|
}
|
|
|
|
|
2022-08-18 23:10:07 +00:00
|
|
|
private _bypassCache: boolean = false;
|
2022-07-23 15:39:17 +00:00
|
|
|
|
2022-08-18 23:10:07 +00:00
|
|
|
get bypassCache(): boolean {
|
|
|
|
return this._bypassCache;
|
2022-06-27 19:36:29 +00:00
|
|
|
}
|
|
|
|
|
2022-08-18 23:10:07 +00:00
|
|
|
set bypassCache(value: boolean) {
|
|
|
|
this._bypassCache = value;
|
2022-06-27 19:36:29 +00:00
|
|
|
}
|
|
|
|
|
2023-03-18 16:11:23 +00:00
|
|
|
public getAvailableRelay(module: string, method: string) {
|
|
|
|
method = `${module}.${method}`;
|
2022-09-22 13:34:07 +00:00
|
|
|
|
2023-03-18 16:11:23 +00:00
|
|
|
let relays = this._methods.get(method) ?? new Set();
|
2022-09-22 13:34:07 +00:00
|
|
|
|
2023-03-18 16:11:23 +00:00
|
|
|
if (!relays.size) {
|
|
|
|
throw Error("no available relay");
|
|
|
|
}
|
2022-09-22 13:34:07 +00:00
|
|
|
|
2023-03-19 19:11:13 +00:00
|
|
|
return this._relays.get(
|
|
|
|
Array.from(relays)[Math.floor(Math.random() * relays.size)]
|
|
|
|
);
|
2022-06-27 19:36:29 +00:00
|
|
|
}
|
|
|
|
|
2023-03-18 16:11:23 +00:00
|
|
|
public getRelay(pubkey: string) {
|
|
|
|
if (this._relays.has(pubkey)) {
|
|
|
|
return this._relays.get(pubkey);
|
2022-06-27 20:25:53 +00:00
|
|
|
}
|
|
|
|
|
2023-03-18 16:11:23 +00:00
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
private init() {
|
|
|
|
this._swarm.join(createHash("lumeweb"));
|
|
|
|
this.setupRelayPromise();
|
|
|
|
|
|
|
|
this._swarm.on("connection", async (relay: any) => {
|
2023-03-25 14:51:29 +00:00
|
|
|
const pubkey = b4a
|
|
|
|
.from(await maybeGetAsyncProperty(relay.remotePublicKey))
|
|
|
|
.toString("hex");
|
2023-03-18 18:49:05 +00:00
|
|
|
relay.once("close", () => {
|
2023-03-18 18:48:43 +00:00
|
|
|
this._methods.forEach((item) => {
|
|
|
|
if (item.has(pubkey)) {
|
|
|
|
item.delete(pubkey);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
this.relays.delete(pubkey);
|
|
|
|
|
|
|
|
if (!this._relays.size) {
|
|
|
|
this.setupRelayPromise();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-03-18 16:11:23 +00:00
|
|
|
const query = this._factory.simple({
|
|
|
|
relay,
|
|
|
|
query: { module: "core", method: "get_methods", data: null },
|
|
|
|
});
|
|
|
|
const resp = await query.result;
|
|
|
|
|
2023-03-29 21:25:26 +00:00
|
|
|
if (resp.error) {
|
|
|
|
relay.end();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-03-18 16:11:23 +00:00
|
|
|
if (resp.data) {
|
|
|
|
this._relays.set(pubkey, relay);
|
|
|
|
|
|
|
|
(resp.data as string[]).forEach((item) => {
|
|
|
|
const methods: Set<string> =
|
|
|
|
this._methods.get(item) ?? new Set<string>();
|
|
|
|
|
|
|
|
methods.add(pubkey);
|
|
|
|
this._methods.set(item, methods);
|
|
|
|
});
|
|
|
|
this._relaysAvailableResolve?.();
|
|
|
|
}
|
|
|
|
});
|
2022-06-27 20:25:53 +00:00
|
|
|
}
|
|
|
|
|
2023-03-18 16:11:23 +00:00
|
|
|
private setupRelayPromise() {
|
|
|
|
this._relaysAvailablePromise = new Promise<void>((resolve) => {
|
|
|
|
this._relaysAvailableResolve = resolve;
|
|
|
|
});
|
2022-06-27 20:25:53 +00:00
|
|
|
}
|
2022-06-27 19:36:29 +00:00
|
|
|
}
|