From 421f767b0da0003f7885c7ee81dde91fc3fa4ce9 Mon Sep 17 00:00:00 2001 From: Nikos Kontakis Date: Fri, 23 Sep 2022 12:47:44 +0300 Subject: [PATCH] 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 Co-authored-by: Jaco --- .../src/substrate-connect/ScProvider.ts | 50 +++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/packages/rpc-provider/src/substrate-connect/ScProvider.ts b/packages/rpc-provider/src/substrate-connect/ScProvider.ts index 76e0dd801e..06befb58f6 100644 --- a/packages/rpc-provider/src/substrate-connect/ScProvider.ts +++ b/packages/rpc-provider/src/substrate-connect/ScProvider.ts @@ -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(); 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 = new Map(); + readonly #resubscribeMethods: Map = new Map(); readonly #requests: Map = new Map(); readonly #eventemitter: EventEmitter = new EventEmitter(); #chain: Promise | 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 = 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 { 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;