Compare commits
No commits in common. "develop" and "master" have entirely different histories.
|
@ -1,13 +0,0 @@
|
||||||
name: Build/Publish
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
- develop
|
|
||||||
- develop-*
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
main:
|
|
||||||
uses: lumeweb/github-node-deploy-workflow/.github/workflows/main.yml@master
|
|
||||||
secrets: inherit
|
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"preset": [
|
|
||||||
"@lumeweb/node-library-preset"
|
|
||||||
]
|
|
||||||
}
|
|
32
CHANGELOG.md
32
CHANGELOG.md
|
@ -1,32 +0,0 @@
|
||||||
## [0.0.2-develop.6](https://git.lumeweb.com/LumeWeb/rpc-client/compare/v0.0.2-develop.5...v0.0.2-develop.6) (2023-07-23)
|
|
||||||
|
|
||||||
## [0.0.2-develop.5](https://git.lumeweb.com/LumeWeb/rpc-client/compare/v0.0.2-develop.4...v0.0.2-develop.5) (2023-07-22)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* add _endPeerOnError optional function to conditionally end a peer if there is an error ([5971d0a](https://git.lumeweb.com/LumeWeb/rpc-client/commit/5971d0ace858eebd30afbf4b644457d42acc04dd))
|
|
||||||
|
|
||||||
## [0.0.2-develop.4](https://git.lumeweb.com/LumeWeb/rpc-client/compare/v0.0.2-develop.3...v0.0.2-develop.4) (2023-07-04)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* remove unneeded import ([a3669fb](https://git.lumeweb.com/LumeWeb/rpc-client/commit/a3669fb403e89185a19cd599b3e9464d240e8455))
|
|
||||||
|
|
||||||
## [0.0.2-develop.3](https://git.lumeweb.com/LumeWeb/rpc-client/compare/v0.0.2-develop.2...v0.0.2-develop.3) (2023-07-04)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* remove unneeded import ([3a84b0e](https://git.lumeweb.com/LumeWeb/rpc-client/commit/3a84b0e1cb52f3732ddf06a089f9864735e1be34))
|
|
||||||
|
|
||||||
## [0.0.2-develop.2](https://git.lumeweb.com/LumeWeb/rpc-client/compare/v0.0.2-develop.1...v0.0.2-develop.2) (2023-07-04)
|
|
||||||
|
|
||||||
## [0.0.2-develop.1](https://git.lumeweb.com/LumeWeb/rpc-client/compare/v0.0.1...v0.0.2-develop.1) (2023-07-04)
|
|
||||||
|
|
||||||
|
|
||||||
### Reverts
|
|
||||||
|
|
||||||
* Revert "*add a _timeoutCanceled property and abort handeTimeout if true" ([1d73d23](https://git.lumeweb.com/LumeWeb/rpc-client/commit/1d73d2370057c6efca45a00f1676722ccd3ac3ab))
|
|
||||||
* Revert "*Switch from clearing the timeout to setting the _timeoutCanceled flag" ([f9036e1](https://git.lumeweb.com/LumeWeb/rpc-client/commit/f9036e1c73572e38e27fdf748cc164c4f2ca32e1))
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
export declare const ERR_INVALID_SIGNATURE = "INVALID_SIGNATURE";
|
||||||
|
//# sourceMappingURL=error.d.ts.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,sBAAsB,CAAC"}
|
|
@ -0,0 +1 @@
|
||||||
|
export const ERR_INVALID_SIGNATURE = "INVALID_SIGNATURE";
|
|
@ -0,0 +1,5 @@
|
||||||
|
export * from "./types.js";
|
||||||
|
export * from "./query/index.js";
|
||||||
|
export * from "./network.js";
|
||||||
|
export * from "./util.js";
|
||||||
|
//# sourceMappingURL=index.d.ts.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC"}
|
|
@ -0,0 +1,4 @@
|
||||||
|
export * from "./types.js";
|
||||||
|
export * from "./query/index.js";
|
||||||
|
export * from "./network.js";
|
||||||
|
export * from "./util.js";
|
|
@ -0,0 +1,34 @@
|
||||||
|
import RpcNetworkQueryFactory from "./query/index.js";
|
||||||
|
export default class RpcNetwork {
|
||||||
|
private _relaysAvailablePromise?;
|
||||||
|
private _relaysAvailableResolve?;
|
||||||
|
constructor(swarm?: any);
|
||||||
|
private _methods;
|
||||||
|
get methods(): Map<string, Set<string>>;
|
||||||
|
private _factory;
|
||||||
|
get factory(): RpcNetworkQueryFactory;
|
||||||
|
private _swarm;
|
||||||
|
get swarm(): 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(): Map<string, string[]>;
|
||||||
|
private _ready?;
|
||||||
|
get ready(): Promise<void>;
|
||||||
|
get readyWithRelays(): Promise<void>;
|
||||||
|
private _bypassCache;
|
||||||
|
get bypassCache(): boolean;
|
||||||
|
set bypassCache(value: boolean);
|
||||||
|
getAvailableRelay(module: string, method: string): any;
|
||||||
|
getRelay(pubkey: string): any;
|
||||||
|
private init;
|
||||||
|
private setupRelayPromise;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=network.d.ts.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../src/network.ts"],"names":[],"mappings":"AAEA,OAAO,sBAAsB,MAAM,kBAAkB,CAAC;AAItD,MAAM,CAAC,OAAO,OAAO,UAAU;IAC7B,OAAO,CAAC,uBAAuB,CAAC,CAAgB;IAChD,OAAO,CAAC,uBAAuB,CAAC,CAAW;gBAC/B,KAAK,MAAmB;IAKpC,OAAO,CAAC,QAAQ,CAA4D;IAE5E,IAAI,OAAO,IAAI,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAEtC;IAED,OAAO,CAAC,QAAQ,CAAoC;IAEpD,IAAI,OAAO,IAAI,sBAAsB,CAEpC;IAED,OAAO,CAAC,MAAM,CAAoB;IAElC,IAAI,KAAK,QAER;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,CAAiD;IAEhE,IAAI,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAElC;IAED,OAAO,CAAC,MAAM,CAAC,CAAgB;IAE/B,IAAI,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAQzB;IAED,IAAI,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAEnC;IAED,OAAO,CAAC,YAAY,CAAkB;IAEtC,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,IAAI,WAAW,CAAC,KAAK,EAAE,OAAO,EAE7B;IAEM,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAchD,QAAQ,CAAC,MAAM,EAAE,MAAM;IAQ9B,OAAO,CAAC,IAAI;IA+CZ,OAAO,CAAC,iBAAiB;CAK1B"}
|
|
@ -0,0 +1,124 @@
|
||||||
|
// @ts-ignore
|
||||||
|
import Hyperswarm from "hyperswarm";
|
||||||
|
import RpcNetworkQueryFactory from "./query/index.js";
|
||||||
|
import b4a from "b4a";
|
||||||
|
import { createHash, maybeGetAsyncProperty } from "./util.js";
|
||||||
|
export default class RpcNetwork {
|
||||||
|
_relaysAvailablePromise;
|
||||||
|
_relaysAvailableResolve;
|
||||||
|
constructor(swarm = new Hyperswarm()) {
|
||||||
|
this._swarm = swarm;
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
_methods = new Map();
|
||||||
|
get methods() {
|
||||||
|
return this._methods;
|
||||||
|
}
|
||||||
|
_factory = new RpcNetworkQueryFactory(this);
|
||||||
|
get factory() {
|
||||||
|
return this._factory;
|
||||||
|
}
|
||||||
|
_swarm;
|
||||||
|
get swarm() {
|
||||||
|
return this._swarm;
|
||||||
|
}
|
||||||
|
_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 = new Map();
|
||||||
|
get relays() {
|
||||||
|
return this._relays;
|
||||||
|
}
|
||||||
|
_ready;
|
||||||
|
get ready() {
|
||||||
|
if (!this._ready) {
|
||||||
|
this._ready = maybeGetAsyncProperty(this._swarm.dht).then((dht) => dht.ready());
|
||||||
|
}
|
||||||
|
return this._ready;
|
||||||
|
}
|
||||||
|
get readyWithRelays() {
|
||||||
|
return this.ready.then(() => this._relaysAvailablePromise);
|
||||||
|
}
|
||||||
|
_bypassCache = false;
|
||||||
|
get bypassCache() {
|
||||||
|
return this._bypassCache;
|
||||||
|
}
|
||||||
|
set bypassCache(value) {
|
||||||
|
this._bypassCache = value;
|
||||||
|
}
|
||||||
|
getAvailableRelay(module, method) {
|
||||||
|
method = `${module}.${method}`;
|
||||||
|
let relays = this._methods.get(method) ?? new Set();
|
||||||
|
if (!relays.size) {
|
||||||
|
throw Error("no available relay");
|
||||||
|
}
|
||||||
|
return this._relays.get(Array.from(relays)[Math.floor(Math.random() * relays.size)]);
|
||||||
|
}
|
||||||
|
getRelay(pubkey) {
|
||||||
|
if (this._relays.has(pubkey)) {
|
||||||
|
return this._relays.get(pubkey);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
init() {
|
||||||
|
this._swarm.join(createHash("lumeweb"));
|
||||||
|
this.setupRelayPromise();
|
||||||
|
this._swarm.on("connection", async (relay) => {
|
||||||
|
const pubkey = b4a
|
||||||
|
.from(await maybeGetAsyncProperty(relay.remotePublicKey))
|
||||||
|
.toString("hex");
|
||||||
|
relay.once("close", () => {
|
||||||
|
this._methods.forEach((item) => {
|
||||||
|
if (item.has(pubkey)) {
|
||||||
|
item.delete(pubkey);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.relays.delete(pubkey);
|
||||||
|
if (!this._relays.size) {
|
||||||
|
this.setupRelayPromise();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const query = this._factory.simple({
|
||||||
|
relay,
|
||||||
|
query: { module: "core", method: "get_methods", data: null },
|
||||||
|
});
|
||||||
|
const resp = await query.result;
|
||||||
|
if (resp.error) {
|
||||||
|
relay.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (resp.data) {
|
||||||
|
this._relays.set(pubkey, relay);
|
||||||
|
resp.data.forEach((item) => {
|
||||||
|
const methods = this._methods.get(item) ?? new Set();
|
||||||
|
methods.add(pubkey);
|
||||||
|
this._methods.set(item, methods);
|
||||||
|
});
|
||||||
|
this._relaysAvailableResolve?.();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setupRelayPromise() {
|
||||||
|
this._relaysAvailablePromise = new Promise((resolve) => {
|
||||||
|
this._relaysAvailableResolve = resolve;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/// <reference types="node" />
|
||||||
|
import RpcNetwork from "../network.js";
|
||||||
|
import { RpcQueryOptions } from "../types.js";
|
||||||
|
import type {
|
||||||
|
ClientRPCRequest,
|
||||||
|
RPCRequest,
|
||||||
|
RPCResponse,
|
||||||
|
} from "@lumeweb/interface-relay";
|
||||||
|
export default abstract class RpcQueryBase {
|
||||||
|
protected _network: RpcNetwork;
|
||||||
|
protected _query: RPCRequest;
|
||||||
|
protected _options: RpcQueryOptions;
|
||||||
|
protected _promise?: Promise<any>;
|
||||||
|
protected _timeoutTimer?: any;
|
||||||
|
protected _timeout: boolean;
|
||||||
|
protected _completed: boolean;
|
||||||
|
protected _response?: RPCResponse;
|
||||||
|
protected _error?: string;
|
||||||
|
protected _promiseResolve?: (data: any) => void;
|
||||||
|
constructor({
|
||||||
|
network,
|
||||||
|
query,
|
||||||
|
options,
|
||||||
|
}: {
|
||||||
|
network: RpcNetwork;
|
||||||
|
query: ClientRPCRequest | RPCRequest;
|
||||||
|
options: RpcQueryOptions;
|
||||||
|
});
|
||||||
|
get result(): Promise<RPCResponse>;
|
||||||
|
protected handeTimeout(): void;
|
||||||
|
protected resolve(data?: RPCResponse, timeout?: boolean): void;
|
||||||
|
run(): this;
|
||||||
|
private _doRun;
|
||||||
|
protected setupRelayTimeout(reject: Function): NodeJS.Timeout;
|
||||||
|
protected abstract _run(): void;
|
||||||
|
protected queryRpc(rpc: any, request: RPCRequest): Promise<unknown>;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=base.d.ts.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/query/base.ts"],"names":[],"mappings":";AACA,OAAO,UAAU,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EACV,gBAAgB,EAChB,UAAU,EACV,WAAW,EACZ,MAAM,0BAA0B,CAAC;AAElC,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,SAAS,CAAC,EAAE,WAAW,CAAC;IAClC,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;gBAEpC,EACV,OAAO,EACP,KAAK,EACL,OAAY,GACb,EAAE;QACD,OAAO,EAAE,UAAU,CAAC;QACpB,KAAK,EAAE,gBAAgB,GAAG,UAAU,CAAC;QACrC,OAAO,EAAE,eAAe,CAAC;KAC1B;IAMD,IAAI,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC,CAEjC;IAED,SAAS,CAAC,YAAY;IAItB,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,OAAO,GAAE,OAAe,GAAG,IAAI;IAc9D,GAAG,IAAI,IAAI;YAmBJ,MAAM;IASpB,SAAS,CAAC,iBAAiB,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC,OAAO;IAO7D,SAAS,CAAC,QAAQ,CAAC,IAAI,IAAI,IAAI;cAEf,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU;CAyBvD"}
|
|
@ -0,0 +1,84 @@
|
||||||
|
import { clearTimeout, setTimeout } from "timers";
|
||||||
|
export default class RpcQueryBase {
|
||||||
|
_network;
|
||||||
|
_query;
|
||||||
|
_options;
|
||||||
|
_promise;
|
||||||
|
_timeoutTimer;
|
||||||
|
_timeout = false;
|
||||||
|
_completed = false;
|
||||||
|
_response;
|
||||||
|
_error;
|
||||||
|
_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._doRun();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
async _doRun() {
|
||||||
|
try {
|
||||||
|
await this._network.ready;
|
||||||
|
await this._run();
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
this._promiseResolve?.({ error: e?.message || e?.error });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setupRelayTimeout(reject) {
|
||||||
|
return setTimeout(() => {
|
||||||
|
this._error = "timeout";
|
||||||
|
reject("timeout");
|
||||||
|
}, (this._options.relayTimeout || this._network.relayTimeout) * 1000);
|
||||||
|
}
|
||||||
|
async queryRpc(rpc, request) {
|
||||||
|
let timer;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
rpc
|
||||||
|
// @ts-ignore
|
||||||
|
.request(`${request.module}.${request.method}`, request.data)
|
||||||
|
.then((resp) => {
|
||||||
|
if (resp.error) {
|
||||||
|
throw new Error(resp.error);
|
||||||
|
}
|
||||||
|
clearTimeout(timer);
|
||||||
|
this._response = resp;
|
||||||
|
resolve(null);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
this._error = e.message;
|
||||||
|
reject({ error: e.message });
|
||||||
|
clearTimeout(timer);
|
||||||
|
});
|
||||||
|
timer = this.setupRelayTimeout(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
import RpcNetwork from "../network.js";
|
||||||
|
import { RPCRequest } from "@lumeweb/interface-relay";
|
||||||
|
import { RpcQueryOptions } from "../types.js";
|
||||||
|
import SimpleRpcQuery from "./simple.js";
|
||||||
|
export default class ClearCacheRpcQuery extends SimpleRpcQuery {
|
||||||
|
protected _relays: string[];
|
||||||
|
constructor({
|
||||||
|
network,
|
||||||
|
relays,
|
||||||
|
query,
|
||||||
|
options,
|
||||||
|
}: {
|
||||||
|
network: RpcNetwork;
|
||||||
|
relays: string[];
|
||||||
|
query: RPCRequest;
|
||||||
|
options: RpcQueryOptions;
|
||||||
|
});
|
||||||
|
protected _run(): Promise<void>;
|
||||||
|
protected queryRelay(): Promise<any>;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=clearCache.d.ts.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"clearCache.d.ts","sourceRoot":"","sources":["../../src/query/clearCache.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,eAAe,CAAC;AACvC,OAAO,EAAuB,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,cAAc,MAAM,aAAa,CAAC;AAEzC,MAAM,CAAC,OAAO,OAAO,kBAAmB,SAAQ,cAAc;IAC5D,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;gBAEhB,EACV,OAAO,EACP,MAAM,EACN,KAAK,EACL,OAAO,GACR,EAAE;QACD,OAAO,EAAE,UAAU,CAAC;QACpB,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,KAAK,EAAE,UAAU,CAAC;QAClB,OAAO,EAAE,eAAe,CAAC;KAC1B;cAKe,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;cAOrB,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC;CAiB3C"}
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { hashQuery } from "../util.js";
|
||||||
|
import SimpleRpcQuery from "./simple.js";
|
||||||
|
export default class ClearCacheRpcQuery extends SimpleRpcQuery {
|
||||||
|
_relays;
|
||||||
|
constructor({ network, relays, query, options, }) {
|
||||||
|
super({ network, relay: "", query, options });
|
||||||
|
this._relays = relays;
|
||||||
|
}
|
||||||
|
async _run() {
|
||||||
|
// @ts-ignore
|
||||||
|
this._relay = getActiveRelay().stream.remotePublicKey;
|
||||||
|
await this.queryRelay();
|
||||||
|
await this.checkResponses();
|
||||||
|
}
|
||||||
|
async queryRelay() {
|
||||||
|
return this.queryRpc(this._network.getAvailableRelay("rpc", "broadcast_request"), {
|
||||||
|
module: "rpc",
|
||||||
|
method: "broadcast_request",
|
||||||
|
data: {
|
||||||
|
request: {
|
||||||
|
module: "rpc",
|
||||||
|
method: "clear_cached_item",
|
||||||
|
data: hashQuery(this._query),
|
||||||
|
},
|
||||||
|
relays: this._relays,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/// <reference types="node" />
|
||||||
|
import { ClientRPCRequest, RPCRequest } from "@lumeweb/interface-relay";
|
||||||
|
import { RpcQueryOptions } from "../types.js";
|
||||||
|
import SimpleRpcQuery from "./simple.js";
|
||||||
|
import ClearCacheRpcQuery from "./clearCache.js";
|
||||||
|
import RpcNetwork from "../network.js";
|
||||||
|
import RpcQueryBase from "./base.js";
|
||||||
|
export default class RpcNetworkQueryFactory {
|
||||||
|
private _network;
|
||||||
|
constructor(network: RpcNetwork);
|
||||||
|
simple({
|
||||||
|
relay,
|
||||||
|
query,
|
||||||
|
options,
|
||||||
|
}: {
|
||||||
|
relay?: string | Buffer;
|
||||||
|
query: ClientRPCRequest;
|
||||||
|
options?: RpcQueryOptions;
|
||||||
|
}): SimpleRpcQuery;
|
||||||
|
clearCache({
|
||||||
|
relays,
|
||||||
|
query,
|
||||||
|
options,
|
||||||
|
}: {
|
||||||
|
relays: string[];
|
||||||
|
query: RPCRequest;
|
||||||
|
options?: RpcQueryOptions;
|
||||||
|
}): ClearCacheRpcQuery;
|
||||||
|
}
|
||||||
|
export { RpcNetwork, RpcQueryBase, SimpleRpcQuery };
|
||||||
|
//# sourceMappingURL=index.d.ts.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,cAAc,MAAM,aAAa,CAAC;AACzC,OAAO,kBAAkB,MAAM,iBAAiB,CAAC;AACjD,OAAO,UAAU,MAAM,eAAe,CAAC;AACvC,OAAO,YAAY,MAAM,WAAW,CAAC;AAErC,MAAM,CAAC,OAAO,OAAO,sBAAsB;IACzC,OAAO,CAAC,QAAQ,CAAa;gBAEjB,OAAO,EAAE,UAAU;IAI/B,MAAM,CAAC,EACL,KAAK,EACL,KAAK,EACL,OAAY,GACb,EAAE;QACD,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QACxB,KAAK,EAAE,gBAAgB,CAAC;QACxB,OAAO,CAAC,EAAE,eAAe,CAAC;KAC3B,GAAG,cAAc;IAYlB,UAAU,CAAC,EACT,MAAM,EACN,KAAK,EACL,OAAY,GACb,EAAE;QACD,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,KAAK,EAAE,UAAU,CAAC;QAClB,OAAO,CAAC,EAAE,eAAe,CAAC;KAC3B,GAAG,kBAAkB;CAQvB;AAED,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,CAAC"}
|
|
@ -0,0 +1,30 @@
|
||||||
|
import SimpleRpcQuery from "./simple.js";
|
||||||
|
import ClearCacheRpcQuery from "./clearCache.js";
|
||||||
|
import RpcNetwork from "../network.js";
|
||||||
|
import RpcQueryBase from "./base.js";
|
||||||
|
export default class RpcNetworkQueryFactory {
|
||||||
|
_network;
|
||||||
|
constructor(network) {
|
||||||
|
this._network = network;
|
||||||
|
}
|
||||||
|
simple({ relay, query, options = {}, }) {
|
||||||
|
return new SimpleRpcQuery({
|
||||||
|
network: this._network,
|
||||||
|
relay,
|
||||||
|
query: {
|
||||||
|
...query,
|
||||||
|
bypassCache: query?.bypassCache || this._network.bypassCache,
|
||||||
|
},
|
||||||
|
options,
|
||||||
|
}).run();
|
||||||
|
}
|
||||||
|
clearCache({ relays, query, options = {}, }) {
|
||||||
|
return new ClearCacheRpcQuery({
|
||||||
|
network: this._network,
|
||||||
|
query,
|
||||||
|
relays,
|
||||||
|
options,
|
||||||
|
}).run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export { RpcNetwork, RpcQueryBase, SimpleRpcQuery };
|
|
@ -0,0 +1,24 @@
|
||||||
|
/// <reference types="node" />
|
||||||
|
import RpcNetwork from "../network.js";
|
||||||
|
import { ClientRPCRequest } from "@lumeweb/interface-relay";
|
||||||
|
import { RpcQueryOptions } from "../types.js";
|
||||||
|
import RpcQueryBase from "./base.js";
|
||||||
|
export default class SimpleRpcQuery extends RpcQueryBase {
|
||||||
|
protected _relay?: string | any;
|
||||||
|
protected _query: ClientRPCRequest;
|
||||||
|
constructor({
|
||||||
|
network,
|
||||||
|
relay,
|
||||||
|
query,
|
||||||
|
options,
|
||||||
|
}: {
|
||||||
|
network: RpcNetwork;
|
||||||
|
relay?: string | Buffer | any;
|
||||||
|
query: ClientRPCRequest;
|
||||||
|
options: RpcQueryOptions;
|
||||||
|
});
|
||||||
|
protected _run(): Promise<void>;
|
||||||
|
protected queryRelay(): Promise<any>;
|
||||||
|
protected checkResponses(): Promise<void>;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=simple.d.ts.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"simple.d.ts","sourceRoot":"","sources":["../../src/query/simple.ts"],"names":[],"mappings":";AAAA,OAAO,UAAU,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAe,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAW9C,OAAO,YAAY,MAAM,WAAW,CAAC;AAErC,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,YAAY;IACtD,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;IAChC,UAAkB,MAAM,EAAE,gBAAgB,CAAC;gBAE/B,EACV,OAAO,EACP,KAAK,EACL,KAAK,EACL,OAAO,GACR,EAAE;QACD,OAAO,EAAE,UAAU,CAAC;QACpB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,GAAG,CAAC;QAC9B,KAAK,EAAE,gBAAgB,CAAC;QACxB,OAAO,EAAE,eAAe,CAAC;KAC1B;cASe,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;cAKrB,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC;cAwD1B,cAAc;CAsB/B"}
|
|
@ -0,0 +1,75 @@
|
||||||
|
import b4a from "b4a";
|
||||||
|
import { hashQuery, isPromise, maybeGetAsyncProperty, setupStream, validateTimestampedResponse, } from "../util.js";
|
||||||
|
import { ERR_INVALID_SIGNATURE } from "../error.js";
|
||||||
|
import RpcQueryBase from "./base.js";
|
||||||
|
export default class SimpleRpcQuery extends RpcQueryBase {
|
||||||
|
_relay;
|
||||||
|
constructor({ network, relay, query, options, }) {
|
||||||
|
super({ network, query, options });
|
||||||
|
if (b4a.isBuffer(relay)) {
|
||||||
|
relay = b4a.from(relay).toString("hex");
|
||||||
|
}
|
||||||
|
this._relay = relay;
|
||||||
|
}
|
||||||
|
async _run() {
|
||||||
|
await this.queryRelay();
|
||||||
|
await this.checkResponses();
|
||||||
|
}
|
||||||
|
async queryRelay() {
|
||||||
|
let socket = this._relay;
|
||||||
|
if (socket) {
|
||||||
|
if (typeof socket === "string") {
|
||||||
|
try {
|
||||||
|
const relay = this._network.getRelay(socket);
|
||||||
|
if (this._network.getRelay(socket)) {
|
||||||
|
socket = relay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
if (typeof socket === "string") {
|
||||||
|
try {
|
||||||
|
socket = this._network.swarm.connect(b4a.from(this._relay, "hex"));
|
||||||
|
if (isPromise(socket)) {
|
||||||
|
socket = await socket;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!socket) {
|
||||||
|
socket = this._network.getAvailableRelay(this._query.module, this._query.method);
|
||||||
|
}
|
||||||
|
this._relay = socket;
|
||||||
|
await socket.opened;
|
||||||
|
const rpc = await setupStream(socket);
|
||||||
|
if (this._query.bypassCache) {
|
||||||
|
delete this._query.bypassCache;
|
||||||
|
await this.queryRpc(rpc, {
|
||||||
|
module: "rpc",
|
||||||
|
method: "clear_cached_item",
|
||||||
|
data: hashQuery(this._query),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if ("bypassCache" in this._query) {
|
||||||
|
delete this._query.bypassCache;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await this.queryRpc(rpc, this._query);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async checkResponses() {
|
||||||
|
let response = this._response;
|
||||||
|
if (this._error) {
|
||||||
|
response = { error: this._error };
|
||||||
|
}
|
||||||
|
if (!response.error &&
|
||||||
|
!validateTimestampedResponse(b4a.from(await maybeGetAsyncProperty(this._relay.remotePublicKey), "hex"), response)) {
|
||||||
|
response = { error: ERR_INVALID_SIGNATURE };
|
||||||
|
}
|
||||||
|
this.resolve(response);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
export interface RpcQueryOptions {
|
||||||
|
queryTimeout?: number;
|
||||||
|
relayTimeout?: number;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=types.d.ts.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB"}
|
|
@ -0,0 +1 @@
|
||||||
|
export {};
|
|
@ -0,0 +1,19 @@
|
||||||
|
/// <reference types="node" />
|
||||||
|
import type { RPCRequest, RPCResponse } from "@lumeweb/interface-relay";
|
||||||
|
export declare const RPC_PROTOCOL_SYMBOL: unique symbol;
|
||||||
|
export declare function isPromise(obj: Promise<any>): boolean;
|
||||||
|
export declare function flatten(target: any, opts?: any): any[];
|
||||||
|
export declare function validateResponse(
|
||||||
|
relay: Buffer,
|
||||||
|
response: RPCResponse,
|
||||||
|
timestamped?: boolean
|
||||||
|
): boolean;
|
||||||
|
export declare function validateTimestampedResponse(
|
||||||
|
relay: Buffer,
|
||||||
|
response: RPCResponse
|
||||||
|
): boolean;
|
||||||
|
export declare function hashQuery(query: RPCRequest): string;
|
||||||
|
export declare function createHash(data: string): Buffer;
|
||||||
|
export declare function setupStream(stream: any): Promise<any>;
|
||||||
|
export declare function maybeGetAsyncProperty(object: any): Promise<any>;
|
||||||
|
//# sourceMappingURL=util.d.ts.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAOxE,eAAO,MAAM,mBAAmB,eAAwB,CAAC;AAEzD,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,WAM1C;AAKD,wBAAgB,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,GAAE,GAAQ,GAAG,GAAG,EAAE,CA0C1D;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,WAAW,EACrB,WAAW,UAAQ,GAClB,OAAO,CAkBT;AAED,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,WAAW,GACpB,OAAO,CAET;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAUnD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM/C;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE,GAAG,gBAa5C;AAED,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,GAAG,gBAUtD"}
|
|
@ -0,0 +1,102 @@
|
||||||
|
// @ts-ignore
|
||||||
|
import stringify from "json-stringify-deterministic";
|
||||||
|
// @ts-ignore
|
||||||
|
import crypto from "hypercore-crypto";
|
||||||
|
// @ts-ignore
|
||||||
|
import sodium from "sodium-universal";
|
||||||
|
import b4a from "b4a";
|
||||||
|
import RPC from "@lumeweb/rpc";
|
||||||
|
export const RPC_PROTOCOL_SYMBOL = Symbol.for("lumeweb");
|
||||||
|
export function isPromise(obj) {
|
||||||
|
return (!!obj &&
|
||||||
|
(typeof obj === "object" || typeof obj === "function") &&
|
||||||
|
typeof obj.then === "function");
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Forked from https://github.com/hughsk/flat
|
||||||
|
*/
|
||||||
|
export function flatten(target, opts = {}) {
|
||||||
|
opts = opts || {};
|
||||||
|
const delimiter = opts.delimiter || ".";
|
||||||
|
const maxDepth = opts.maxDepth;
|
||||||
|
const transformKey = opts.transformKey || ((key) => (isNaN(parseInt(key)) ? key : ""));
|
||||||
|
const output = [];
|
||||||
|
function step(object, prev, currentDepth) {
|
||||||
|
currentDepth = currentDepth || 1;
|
||||||
|
if (!Array.isArray(object)) {
|
||||||
|
object = Object.keys(object ?? {});
|
||||||
|
}
|
||||||
|
object.forEach(function (key) {
|
||||||
|
const value = object[key];
|
||||||
|
const isarray = opts.safe && Array.isArray(value);
|
||||||
|
const type = Object.prototype.toString.call(value);
|
||||||
|
const isbuffer = b4a.isBuffer(value);
|
||||||
|
const isobject = type === "[object Object]" || type === "[object Array]";
|
||||||
|
const newKey = prev
|
||||||
|
? prev + delimiter + transformKey(key)
|
||||||
|
: transformKey(key);
|
||||||
|
if (!isarray &&
|
||||||
|
!isbuffer &&
|
||||||
|
isobject &&
|
||||||
|
Object.keys(value).length &&
|
||||||
|
(!opts.maxDepth || currentDepth < maxDepth)) {
|
||||||
|
return step(value, newKey, currentDepth + 1);
|
||||||
|
}
|
||||||
|
output.push(`${newKey}=${value}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
step(target);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
export function validateResponse(relay, response, timestamped = false) {
|
||||||
|
const field = response.signedField || "data";
|
||||||
|
// @ts-ignore
|
||||||
|
let json = response[field];
|
||||||
|
if (typeof json !== "string") {
|
||||||
|
json = stringify(json);
|
||||||
|
}
|
||||||
|
const updated = response.updated;
|
||||||
|
if (timestamped && updated) {
|
||||||
|
json = updated.toString() + json;
|
||||||
|
}
|
||||||
|
return !!crypto.verify(b4a.from(json), b4a.from(response.signature, "hex"), relay);
|
||||||
|
}
|
||||||
|
export function validateTimestampedResponse(relay, response) {
|
||||||
|
return validateResponse(relay, response, true);
|
||||||
|
}
|
||||||
|
export function hashQuery(query) {
|
||||||
|
const clonedQuery = {
|
||||||
|
module: query.module,
|
||||||
|
method: query.method,
|
||||||
|
data: query.data,
|
||||||
|
};
|
||||||
|
const queryHash = Buffer.allocUnsafe(32);
|
||||||
|
sodium.crypto_generichash(queryHash, Buffer.from(stringify(clonedQuery)));
|
||||||
|
return queryHash.toString("hex");
|
||||||
|
}
|
||||||
|
export function createHash(data) {
|
||||||
|
const buffer = b4a.from(data);
|
||||||
|
let hash = b4a.allocUnsafe(32);
|
||||||
|
sodium.crypto_generichash(hash, buffer);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
export async function setupStream(stream) {
|
||||||
|
const existing = stream[RPC_PROTOCOL_SYMBOL];
|
||||||
|
if (existing) {
|
||||||
|
await existing.ready;
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
const rpc = new RPC(stream);
|
||||||
|
stream[RPC_PROTOCOL_SYMBOL] = rpc;
|
||||||
|
await rpc.ready;
|
||||||
|
return rpc;
|
||||||
|
}
|
||||||
|
export async function maybeGetAsyncProperty(object) {
|
||||||
|
if (typeof object === "function") {
|
||||||
|
object = object();
|
||||||
|
}
|
||||||
|
if (isPromise(object)) {
|
||||||
|
object = await object;
|
||||||
|
}
|
||||||
|
return object;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
41
package.json
41
package.json
|
@ -1,31 +1,30 @@
|
||||||
{
|
{
|
||||||
"name": "@lumeweb/rpc-client",
|
"name": "@lumeweb/rpc-client",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "0.0.2-develop.6",
|
"version": "0.1.0",
|
||||||
"main": "lib/index.js",
|
"description": "",
|
||||||
"repository": {
|
"main": "dist/index.js",
|
||||||
"type": "git",
|
"scripts": {
|
||||||
"url": "gitea@git.lumeweb.com:LumeWeb/rpc-client.git"
|
"build": "rimraf dist && tsc"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@lumeweb/node-library-preset": "^0.2.7",
|
"@lumeweb/interface-relay": "git+https://git.lumeweb.com/LumeWeb/interface-relay.git",
|
||||||
"presetter": "*"
|
"@types/b4a": "^1.6.0",
|
||||||
},
|
"@types/express": "^4.17.14",
|
||||||
"readme": "ERROR: No README data found!",
|
"@types/node": "^18.0.0",
|
||||||
"scripts": {
|
"node-cache": "^5.1.2",
|
||||||
"prepare": "presetter bootstrap",
|
"prettier": "^2.7.1",
|
||||||
"build": "run build",
|
"typescript": "^4.7.4"
|
||||||
"semantic-release": "semantic-release"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lumeweb/interface-relay": "0.0.2-develop.1",
|
"@hyperswarm/dht": "^6.0.1",
|
||||||
"@lumeweb/rpc": "0.0.2-develop.5",
|
"@lumeweb/rpc": "git+https://git.lumeweb.com/LumeWeb/rpc.git",
|
||||||
"b4a": "^1.6.4",
|
"b4a": "^1.6.1",
|
||||||
"binconv": "^0.2.0",
|
|
||||||
"hypercore-crypto": "^3.3.1",
|
"hypercore-crypto": "^3.3.1",
|
||||||
"json-stringify-deterministic": "^1.0.8"
|
"hyperswarm": "^4.3.7",
|
||||||
},
|
"json-stringify-deterministic": "^1.0.7",
|
||||||
"publishConfig": {
|
"libskynet": "^0.0.61",
|
||||||
"access": "public"
|
"msgpackr": "^1.6.1",
|
||||||
|
"sodium-universal": "^4.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,17 @@
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import Hyperswarm from "hyperswarm";
|
import Hyperswarm from "hyperswarm";
|
||||||
import RpcNetworkQueryFactory from "./query/index.js";
|
import RpcNetworkQueryFactory from "./query/index.js";
|
||||||
|
import b4a from "b4a";
|
||||||
import { createHash, maybeGetAsyncProperty } from "./util.js";
|
import { createHash, maybeGetAsyncProperty } from "./util.js";
|
||||||
import { uint8ArrayToHexString } from "binconv";
|
|
||||||
|
|
||||||
export default class RpcNetwork {
|
export default class RpcNetwork {
|
||||||
private _relaysAvailablePromise?: Promise<void>;
|
private _relaysAvailablePromise?: Promise<void>;
|
||||||
private _relaysAvailableResolve?: Function;
|
private _relaysAvailableResolve?: Function;
|
||||||
|
|
||||||
constructor(swarm = new Hyperswarm()) {
|
constructor(swarm = new Hyperswarm()) {
|
||||||
this._swarm = swarm;
|
this._swarm = swarm;
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _endPeerOnError?: (peer: any) => Promise<boolean>;
|
|
||||||
|
|
||||||
set endPeerOnError(value: (peer: any) => Promise<boolean>) {
|
|
||||||
this._endPeerOnError = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _methods: Map<string, Set<string>> = new Map<string, Set<string>>();
|
private _methods: Map<string, Set<string>> = new Map<string, Set<string>>();
|
||||||
|
|
||||||
get methods(): Map<string, Set<string>> {
|
get methods(): Map<string, Set<string>> {
|
||||||
|
@ -78,7 +71,7 @@ export default class RpcNetwork {
|
||||||
get ready(): Promise<void> {
|
get ready(): Promise<void> {
|
||||||
if (!this._ready) {
|
if (!this._ready) {
|
||||||
this._ready = maybeGetAsyncProperty(this._swarm.dht).then((dht: any) =>
|
this._ready = maybeGetAsyncProperty(this._swarm.dht).then((dht: any) =>
|
||||||
dht.ready(),
|
dht.ready()
|
||||||
) as Promise<void>;
|
) as Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +102,7 @@ export default class RpcNetwork {
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._relays.get(
|
return this._relays.get(
|
||||||
Array.from(relays)[Math.floor(Math.random() * relays.size)],
|
Array.from(relays)[Math.floor(Math.random() * relays.size)]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,9 +119,9 @@ export default class RpcNetwork {
|
||||||
this.setupRelayPromise();
|
this.setupRelayPromise();
|
||||||
|
|
||||||
this._swarm.on("connection", async (relay: any) => {
|
this._swarm.on("connection", async (relay: any) => {
|
||||||
const pubkey = uint8ArrayToHexString(
|
const pubkey = b4a
|
||||||
await maybeGetAsyncProperty(relay.remotePublicKey),
|
.from(await maybeGetAsyncProperty(relay.remotePublicKey))
|
||||||
);
|
.toString("hex");
|
||||||
relay.once("close", () => {
|
relay.once("close", () => {
|
||||||
this._methods.forEach((item) => {
|
this._methods.forEach((item) => {
|
||||||
if (item.has(pubkey)) {
|
if (item.has(pubkey)) {
|
||||||
|
@ -149,9 +142,7 @@ export default class RpcNetwork {
|
||||||
const resp = await query.result;
|
const resp = await query.result;
|
||||||
|
|
||||||
if (resp.error) {
|
if (resp.error) {
|
||||||
if (await this._endPeerOnError?.(relay)) {
|
|
||||||
relay.end();
|
relay.end();
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {
|
||||||
setupStream,
|
setupStream,
|
||||||
validateTimestampedResponse,
|
validateTimestampedResponse,
|
||||||
} from "../util.js";
|
} from "../util.js";
|
||||||
|
import RPC from "@lumeweb/rpc";
|
||||||
import { ERR_INVALID_SIGNATURE } from "../error.js";
|
import { ERR_INVALID_SIGNATURE } from "../error.js";
|
||||||
import RpcQueryBase from "./base.js";
|
import RpcQueryBase from "./base.js";
|
||||||
|
|
||||||
|
@ -66,7 +67,7 @@ export default class SimpleRpcQuery extends RpcQueryBase {
|
||||||
if (!socket) {
|
if (!socket) {
|
||||||
socket = this._network.getAvailableRelay(
|
socket = this._network.getAvailableRelay(
|
||||||
this._query.module,
|
this._query.module,
|
||||||
this._query.method,
|
this._query.method
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,9 +109,9 @@ export default class SimpleRpcQuery extends RpcQueryBase {
|
||||||
!validateTimestampedResponse(
|
!validateTimestampedResponse(
|
||||||
b4a.from(
|
b4a.from(
|
||||||
await maybeGetAsyncProperty(this._relay.remotePublicKey),
|
await maybeGetAsyncProperty(this._relay.remotePublicKey),
|
||||||
"hex",
|
"hex"
|
||||||
) as Buffer,
|
) as Buffer,
|
||||||
response,
|
response
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
response = { error: ERR_INVALID_SIGNATURE };
|
response = { error: ERR_INVALID_SIGNATURE };
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"declaration": true,
|
||||||
|
"strict": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"target": "esnext",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"sourceMap": false,
|
||||||
|
"rootDir": "src",
|
||||||
|
"outDir": "dist",
|
||||||
|
"typeRoots": [
|
||||||
|
"node_modules/@types",
|
||||||
|
],
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"declarationMap": true,
|
||||||
|
"declarationDir": "dist",
|
||||||
|
"emitDeclarationOnly": false,
|
||||||
|
"allowJs": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue