Add autoconnect to ScProvider (#5217)

* Add autoconnect to ScProvider

* Add autoconnect flag

* remove autoconnect solution and create resubscribe

* Satisfy lint

* Update packages/rpc-provider/src/substrate-connect/ScProvider.ts

Co-authored-by: Jaco <jacogr@gmail.com>

Co-authored-by: Jaco <jacogr@gmail.com>
This commit is contained in:
Nikos Kontakis
2022-09-23 12:47:44 +03:00
committed by GitHub
co-authored by Jaco
parent cfc7e2490c
commit 421f767b0d
@@ -7,13 +7,15 @@ import type { JsonRpcResponse, ProviderInterface, ProviderInterfaceCallback, Pro
import { Chain, createScClient, ScClient, WellKnownChain } from '@substrate/connect';
import EventEmitter from 'eventemitter3';
import { isError, objectSpread } from '@polkadot/util';
import { isError, logger, objectSpread } from '@polkadot/util';
import { RpcCoder } from '../coder';
import { healthChecker } from './Health';
type ResponseCallback = (response: string | Error) => void
const l = logger('api-substrate-connect');
// These methods have been taken from:
// https://github.com/paritytech/smoldot/blob/17425040ddda47d539556eeaf62b88c4240d1d42/src/json_rpc/methods.rs#L338-L462
// It's important to take into account that smoldot is adding support to the new
@@ -37,11 +39,19 @@ const scClients = new WeakMap<ScProvider, ScClient>();
export { WellKnownChain };
interface ActiveSubs {
type: string,
method: string,
params: any[],
callback: ProviderInterfaceCallback
}
export class ScProvider implements ProviderInterface {
readonly #coder: RpcCoder = new RpcCoder();
readonly #spec: string | WellKnownChain;
readonly #sharedSandbox?: ScProvider;
readonly #subscriptions: Map<string, [ResponseCallback, { unsubscribeMethod: string; id: string | number }]> = new Map();
readonly #resubscribeMethods: Map<string, ActiveSubs> = new Map();
readonly #requests: Map<number, ResponseCallback> = new Map();
readonly #eventemitter: EventEmitter = new EventEmitter();
#chain: Promise<Chain> | null = null;
@@ -207,11 +217,17 @@ export class ScProvider implements ProviderInterface {
staleSubscriptions.push(s[1]);
});
cleanup();
this.#eventemitter.emit('disconnected');
} else {
killStaleSubscriptions();
}
this.#eventemitter.emit(isReady ? 'connected' : 'disconnected');
this.#eventemitter.emit('connected');
if (this.#resubscribeMethods.size) {
this.#resubscribe();
}
}
});
return objectSpread({}, chain, {
@@ -233,6 +249,32 @@ export class ScProvider implements ProviderInterface {
}
}
#resubscribe = (): void => {
const promises: any[] = [];
this.#resubscribeMethods.forEach((subDetails: ActiveSubs): void => {
// only re-create subscriptions which are not in author (only area where
// transactions are created, i.e. submissions such as 'author_submitAndWatchExtrinsic'
// are not included (and will not be re-broadcast)
if (subDetails.type.startsWith('author_')) {
return;
}
try {
const promise: Promise<void> = new Promise((resolve) => {
this.subscribe(subDetails.type, subDetails.method, subDetails.params, subDetails.callback).catch((error) => console.log(error));
resolve();
});
promises.push(promise);
} catch (error) {
l.error(error);
}
});
Promise.all(promises).catch((err) => l.log(err));
};
async disconnect (): Promise<void> {
if (!this.#chain) {
return;
@@ -322,6 +364,8 @@ export class ScProvider implements ProviderInterface {
throw new Error('Invalid unsubscribe method found');
}
this.#resubscribeMethods.set(subscriptionId, { callback, method, params, type });
this.#subscriptions.set(subscriptionId, [cb, { id, unsubscribeMethod }]);
return id;