Allow limited (non-sub operation) with Http provider (#1465)
* Allow limited (non-sub operation) with Http provider * Throw-away typo
This commit is contained in:
@@ -129,6 +129,13 @@ export default abstract class Decorate<ApiType> extends Events {
|
||||
this._isConnected = new BehaviorSubject(this._rpcCore.provider.isConnected());
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns `true` if the API operates with subscriptions
|
||||
*/
|
||||
get hasSubscriptions (): boolean {
|
||||
return this._rpcCore.provider.hasSubscriptions;
|
||||
}
|
||||
|
||||
private decorateFunctionMeta (input: MetaDecoration, output: MetaDecoration): MetaDecoration {
|
||||
output.meta = input.meta;
|
||||
output.method = input.method;
|
||||
@@ -185,10 +192,13 @@ export default abstract class Decorate<ApiType> extends Events {
|
||||
|
||||
// out and section here are horrors to get right from a typing perspective :()
|
||||
(out as any)[sectionName] = Object.entries(rpc[sectionName]).reduce((section, [methodName, method]): DecoratedRpcSection<ApiType, RpcInterface[typeof sectionName]> => {
|
||||
(section as any)[methodName] = decorateMethod(method, { methodName });
|
||||
// skip subscriptions where we have a non-subscribable interface
|
||||
if (this.hasSubscriptions || !(methodName.startsWith('subscribe') || methodName.startsWith('unsubscribe'))) {
|
||||
(section as any)[methodName] = decorateMethod(method, { methodName });
|
||||
|
||||
// add this endpoint mapping to our internal map - we use this for filters
|
||||
this._rpcMap.set(`${sectionName}_${methodName}`, jsonrpc[sectionName].methods[methodName]);
|
||||
// add this endpoint mapping to our internal map - we use this for filters
|
||||
this._rpcMap.set(`${sectionName}_${methodName}`, jsonrpc[sectionName].methods[methodName]);
|
||||
}
|
||||
|
||||
return section;
|
||||
}, {} as unknown as DecoratedRpcSection<ApiType, RpcInterface[typeof sectionName]>);
|
||||
@@ -246,15 +256,19 @@ export default abstract class Decorate<ApiType> extends Events {
|
||||
? [creator, args]
|
||||
: [creator, ...args];
|
||||
|
||||
const decorated = creator.headKey
|
||||
// FIXME We probably want to be able to query the full list with non-subs as well
|
||||
const decorated = this.hasSubscriptions && creator.headKey
|
||||
? this.decorateStorageEntryLinked(creator, decorateMethod)
|
||||
: decorateMethod((...args: any[]): Observable<Codec> =>
|
||||
this._rpcCore.state
|
||||
// Unfortunately for one-shot calls we also use .subscribeStorage here
|
||||
.subscribeStorage<[Codec]>([getArgs(...args)])
|
||||
// state_storage returns an array of values, since we have just subscribed to
|
||||
// a single entry, we pull that from the array and return it as-is
|
||||
.pipe(map(([data]): Codec => data)), { methodName: creator.method });
|
||||
: decorateMethod((...args: any[]): Observable<Codec> => (
|
||||
this.hasSubscriptions
|
||||
? this._rpcCore.state
|
||||
// Unfortunately for one-shot calls we also use .subscribeStorage here
|
||||
.subscribeStorage<[Codec]>([getArgs(...args)])
|
||||
// state_storage returns an array of values, since we have just subscribed to
|
||||
// a single entry, we pull that from the array and return it as-is
|
||||
.pipe(map(([data]): Codec => data))
|
||||
: this._rpcCore.state.getStorage(getArgs(...args))
|
||||
), { methodName: creator.method });
|
||||
|
||||
decorated.creator = creator;
|
||||
|
||||
@@ -267,10 +281,12 @@ export default abstract class Decorate<ApiType> extends Events {
|
||||
decorated.key = (arg1?: Arg, arg2?: Arg): string =>
|
||||
u8aToHex(compactStripLength(creator(creator.meta.type.isDoubleMap ? [arg1, arg2] : arg1))[1]);
|
||||
|
||||
// When using double map storage function, user need to pass double map key as an array
|
||||
decorated.multi = decorateMethod((args: (Arg | Arg[])[]): Observable<Codec[]> =>
|
||||
this._rpcCore.state.subscribeStorage(
|
||||
args.map((arg: Arg[] | Arg): [StorageEntry, Arg | Arg[]] => [creator, arg])));
|
||||
if (this.hasSubscriptions) {
|
||||
// When using double map storage function, user need to pass double map key as an array
|
||||
decorated.multi = decorateMethod((args: (Arg | Arg[])[]): Observable<Codec[]> =>
|
||||
this._rpcCore.state.subscribeStorage(
|
||||
args.map((arg: Arg[] | Arg): [StorageEntry, Arg | Arg[]] => [creator, arg])));
|
||||
}
|
||||
|
||||
decorated.size = decorateMethod((arg1?: Arg, arg2?: Arg): Observable<u64> =>
|
||||
this._rpcCore.state.getStorageSize(getArgs(arg1, arg2)));
|
||||
|
||||
@@ -11,7 +11,7 @@ import extrinsicsFromMeta from '@polkadot/api-metadata/extrinsics/fromMetadata';
|
||||
import storageFromMeta from '@polkadot/api-metadata/storage/fromMetadata';
|
||||
import { GenericCall, GenericEvent, Metadata, u32 as U32 } from '@polkadot/types';
|
||||
import { LATEST_VERSION as EXTRINSIC_LATEST_VERSION } from '@polkadot/types/primitive/Extrinsic/constants';
|
||||
import { assert, logger } from '@polkadot/util';
|
||||
import { logger } from '@polkadot/util';
|
||||
import { cryptoWaitReady, setSS58Format } from '@polkadot/util-crypto';
|
||||
import addressDefaults from '@polkadot/util-crypto/address/defaults';
|
||||
|
||||
@@ -59,7 +59,9 @@ export default abstract class Init<ApiType> extends Decorate<ApiType> {
|
||||
public constructor (options: ApiOptions, type: ApiTypes, decorateMethod: DecorateMethod<ApiType>) {
|
||||
super(options, type, decorateMethod);
|
||||
|
||||
assert(this._rpcCore.provider.hasSubscriptions, 'Api can only be used with a provider supporting subscriptions');
|
||||
if (!this.hasSubscriptions) {
|
||||
console.warn('Api will be available in a limited mode since the provider does not support subscriptions');
|
||||
}
|
||||
|
||||
// We only register the types (global) if this is not a cloned instance.
|
||||
// Do right up-front, so we get in the user types before we are actually
|
||||
|
||||
@@ -28,7 +28,7 @@ try {
|
||||
}
|
||||
|
||||
function assertResult<T> (value: T | undefined): T {
|
||||
assert(!isUndefined(value), 'Api needs to be initialised before using, listen on \'ready\'');
|
||||
assert(!isUndefined(value), 'Api needs to be initialized before using, listen on \'ready\'');
|
||||
|
||||
return value as T;
|
||||
}
|
||||
@@ -163,7 +163,7 @@ export default abstract class ApiBase<ApiType> extends Init<ApiType> {
|
||||
/**
|
||||
* @description Contains all the raw rpc sections and their subsequent methods in the API as defined by the jsonrpc interface definitions. Unlike the dynamic `api.query` and `api.tx` sections, these methods are fixed (although extensible with node upgrades) and not determined by the runtime.
|
||||
*
|
||||
* RPC endpoints available here allow for the query of chain, node and system information, in addition to providing interfaces for the raw queries of state (usine known keys) and the submission of transactions.
|
||||
* RPC endpoints available here allow for the query of chain, node and system information, in addition to providing interfaces for the raw queries of state (using known keys) and the submission of transactions.
|
||||
*
|
||||
* @example
|
||||
* <BR>
|
||||
@@ -225,7 +225,7 @@ export default abstract class ApiBase<ApiType> extends Init<ApiType> {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Disconnect from the underlying provider, halting all comms
|
||||
* @description Disconnect from the underlying provider, halting all network traffic
|
||||
*/
|
||||
public disconnect (): void {
|
||||
this._rpcCore.disconnect();
|
||||
|
||||
@@ -72,7 +72,7 @@ export default class Submittable<ApiType> extends _Extrinsic implements Submitta
|
||||
// signAndSend implementation for all 3 cases above
|
||||
public signAndSend (account: IKeyringPair | string | AccountId | Address, optionsOrStatus?: Partial<SignerOptions> | Callback<SubmittableResultImpl>, optionalStatusCb?: Callback<SubmittableResultImpl>): SubmitableResultResult<ApiType> | SubmitableResultSubscription<ApiType> {
|
||||
const [options, statusCb] = this._makeSignAndSendOptions(optionsOrStatus, optionalStatusCb);
|
||||
const isSubscription = this._ignoreStatusCb || !!statusCb;
|
||||
const isSubscription = this._api.hasSubscriptions && (this._ignoreStatusCb || !!statusCb);
|
||||
const address = isKeyringPair(account) ? account.address : account.toString();
|
||||
let updateId: number | undefined;
|
||||
|
||||
@@ -106,7 +106,7 @@ export default class Submittable<ApiType> extends _Extrinsic implements Submitta
|
||||
|
||||
// send implementation for both immediate Hash and statusCb variants
|
||||
public send (statusCb?: Callback<SubmittableResultImpl>): SubmitableResultResult<ApiType> | SubmitableResultSubscription<ApiType> {
|
||||
const isSubscription = this._ignoreStatusCb || !!statusCb;
|
||||
const isSubscription = this._api.hasSubscriptions && (this._ignoreStatusCb || !!statusCb);
|
||||
|
||||
return this._decorateMethod(
|
||||
isSubscription
|
||||
|
||||
@@ -48,7 +48,7 @@ export default class UInt extends AbstractInt {
|
||||
*/
|
||||
public toRawType (): string {
|
||||
// NOTE In the case of balances, which have a special meaning on the UI
|
||||
// and can be interpreted differently, return a specifc value for it so
|
||||
// and can be interpreted differently, return a specific value for it so
|
||||
// underlying it always matches (no matter which length it actually is)
|
||||
return this instanceof ClassOf('Balance')
|
||||
? 'Balance'
|
||||
|
||||
Reference in New Issue
Block a user