diff --git a/packages/api-provider/src/http/index.ts b/packages/api-provider/src/http/index.ts index 85fbeb6efd5b..fb85376baf85 100644 --- a/packages/api-provider/src/http/index.ts +++ b/packages/api-provider/src/http/index.ts @@ -53,11 +53,11 @@ export default class HttpProvider implements ProviderInterface { return this.coder.decodeResponse(result); } - async subscribe (method: string, params: Array, cb: ProviderInterface$Callback): Promise { + async subscribe (types: string, method: string, params: Array, cb: ProviderInterface$Callback): Promise { throw new Error('Subscriptions has not been implemented'); } - async unsubscribe (method: string, id: number): Promise { + async unsubscribe (type: string, method: string, id: number): Promise { throw new Error('Subscriptions has not been implemented'); } } diff --git a/packages/api-provider/src/mock/index.ts b/packages/api-provider/src/mock/index.ts index 1c1041e5f66d..fa7feab61729 100644 --- a/packages/api-provider/src/mock/index.ts +++ b/packages/api-provider/src/mock/index.ts @@ -23,9 +23,9 @@ export default function mockProvider (): ProviderInterface { on(self, type, sub), send: (method: string, params: Array): Promise => send(self, method, params), - subscribe: (method: string, ...params: Array): Promise => - subscribe(self, method, params), - unsubscribe: (method: string, id: number): Promise => - unsubscribe(self, method, id) + subscribe: (type: string, method: string, ...params: Array): Promise => + subscribe(self, type, method, params), + unsubscribe: (type: string, method: string, id: number): Promise => + unsubscribe(self, type, method, id) }; } diff --git a/packages/api-provider/src/mock/subscribe.spec.js b/packages/api-provider/src/mock/subscribe.spec.js index 9adc1a4f8a39..2112e37d7f19 100644 --- a/packages/api-provider/src/mock/subscribe.spec.js +++ b/packages/api-provider/src/mock/subscribe.spec.js @@ -13,13 +13,13 @@ describe('subscribe', () => { }); it('fails on unknown methods', () => { - return subscribe(state, 'test_notFound').catch((error) => { + return subscribe(state, 'test', 'test_notFound').catch((error) => { expect(error.message).toMatch(/Invalid method 'test_notFound'/); }); }); it('returns a subscription id', () => { - return subscribe(state, 'chain_newHead', [() => void 0]).then((id) => { + return subscribe(state, 'chain_newHead', 'chain_newHead', [() => void 0]).then((id) => { expect(id).toEqual(state.subscriptionId); }); }); @@ -27,7 +27,7 @@ describe('subscribe', () => { it('stores the mapping values', () => { const cb = () => void 0; - return subscribe(state, 'chain_newHead', [cb]).then((id) => { + return subscribe(state, 'chain_newHead', 'chain_newHead', [cb]).then((id) => { expect(state.subscriptionMap[id]).toEqual('chain_newHead'); expect(state.subscriptions['chain_newHead'].callbacks[id]).toEqual(cb); }); @@ -36,7 +36,7 @@ describe('subscribe', () => { it('calls back with the last known value', (done) => { state.subscriptions['chain_newHead'].lastValue = 'testValue'; - subscribe(state, 'chain_newHead', [(_, value) => { + subscribe(state, 'chain_newHead', 'chain_newHead', [(_, value) => { expect(value).toEqual('testValue'); done(); }]); diff --git a/packages/api-provider/src/mock/subscribe.ts b/packages/api-provider/src/mock/subscribe.ts index 0c2572bc6392..759ef43c7f2d 100644 --- a/packages/api-provider/src/mock/subscribe.ts +++ b/packages/api-provider/src/mock/subscribe.ts @@ -4,7 +4,7 @@ import { MockState, MockState$Subscription$Callback } from './types'; -export default async function subscribe (self: MockState, method: string, params: Array): Promise { +export default async function subscribe (self: MockState, type: string, method: string, params: Array): Promise { self.l.debug(() => ['subscribe', method, params]); if (self.subscriptions[method]) { diff --git a/packages/api-provider/src/mock/unsubscribe.spec.js b/packages/api-provider/src/mock/unsubscribe.spec.js index 8d951d7f818d..e9200666c161 100644 --- a/packages/api-provider/src/mock/unsubscribe.spec.js +++ b/packages/api-provider/src/mock/unsubscribe.spec.js @@ -13,23 +13,23 @@ describe('unsubscribe', () => { beforeEach(() => { state = createState(); - return subscribe(state, 'chain_newHead', [() => void 0]).then((_id) => { + return subscribe(state, 'chain_newHead', 'chain_newHead', [() => void 0]).then((_id) => { id = _id; }); }); it('fails on unknown ids', () => { - return unsubscribe(state, 'chain_newHead', 5).catch((error) => { + return unsubscribe(state, 'chain_newHead', 'chain_newHead', 5).catch((error) => { expect(error.message).toMatch(/Unable to find/); }); }); it('unsubscribes successfully', () => { - return unsubscribe(state, 'chain_newHead', id); + return unsubscribe(state, 'chain_newHead', 'chain_newHead', id); }); it('fails on double unsubscribe', () => { - return unsubscribe(state, 'chain_newHead', id) + return unsubscribe(state, 'chain_newHead', 'chain_newHead', id) .then(() => unsubscribe(state, id)) .catch((error) => { expect(error.message).toMatch(/Unable to find/); @@ -37,7 +37,7 @@ describe('unsubscribe', () => { }); it('clears the subscriptions', () => { - return unsubscribe(state, 'chain_newHead', id).then(() => { + return unsubscribe(state, 'chain_newHead', 'chain_newHead', id).then(() => { expect(state.subscriptionMap[id]).not.toBeDefined(); expect(state.subscriptions['chain_newHead'].callbacks[id]).not.toBeDefined(); }); diff --git a/packages/api-provider/src/mock/unsubscribe.ts b/packages/api-provider/src/mock/unsubscribe.ts index 88d76994d721..f83ca3a4c0c0 100644 --- a/packages/api-provider/src/mock/unsubscribe.ts +++ b/packages/api-provider/src/mock/unsubscribe.ts @@ -4,7 +4,7 @@ import { MockState } from './types'; -export default async function unsubscribe (self: MockState, _: string, id: number): Promise { +export default async function unsubscribe (self: MockState, type: string, name: string, id: number): Promise { const method = self.subscriptionMap[id]; self.l.debug(() => ['unsubscribe', id, method]); diff --git a/packages/api-provider/src/types.d.ts b/packages/api-provider/src/types.d.ts index 1d137ef66e4b..5e2b69d04efc 100644 --- a/packages/api-provider/src/types.d.ts +++ b/packages/api-provider/src/types.d.ts @@ -45,6 +45,6 @@ export interface ProviderInterface { isConnected (): boolean, on (type: ProviderInterface$Emitted, sub: ProviderInterface$EmitCb): void, send (method: string, params: Array): Promise, - subscribe (method: string, params: Array, cb: ProviderInterface$Callback): Promise, - unsubscribe (method: string, id: number): Promise + subscribe (type: string, method: string, params: Array, cb: ProviderInterface$Callback): Promise, + unsubscribe (type: string, method: string, id: number): Promise } diff --git a/packages/api-provider/src/ws/index.ts b/packages/api-provider/src/ws/index.ts index 0909510562f5..15cb28381a46 100644 --- a/packages/api-provider/src/ws/index.ts +++ b/packages/api-provider/src/ws/index.ts @@ -16,15 +16,19 @@ import logger from '@polkadot/util/logger'; import coder from '../coder/json'; +type SubscriptionHandler = { + callback: ProviderInterface$Callback, + type: string +}; + type WsState$Awaiting = { callback: ProviderInterface$Callback, method: string, params: Array, - subscription?: ProviderInterface$Callback + subscription?: SubscriptionHandler }; -type WsState$Subscription = { - callback: ProviderInterface$Callback, +type WsState$Subscription = SubscriptionHandler & { method: string, params: Array }; @@ -91,7 +95,7 @@ export default class WsProvider extends E3.EventEmitter implements WSProviderInt return super.on(type, sub); } - async send (method: string, params: Array, subscription?: ProviderInterface$Callback): Promise { + async send (method: string, params: Array, subscription?: SubscriptionHandler): Promise { return new Promise((resolve, reject): void => { try { const json = this.coder.encodeJson(method, params); @@ -124,16 +128,18 @@ export default class WsProvider extends E3.EventEmitter implements WSProviderInt }); } - async subscribe (method: string, params: Array, subscription: ProviderInterface$Callback): Promise { - const id = await this.send(method, params, subscription); + async subscribe (type: string, method: string, params: Array, callback: ProviderInterface$Callback): Promise { + const id = await this.send(method, params, { callback, type }); return id as number; } - async unsubscribe (method: string, id: number): Promise { - assert(!isUndefined(this.subscriptions[`${method}::${id}`]), `Unable to find active subscription=${id}`); + async unsubscribe (type: string, method: string, id: number): Promise { + const subscription = `${type}::${id}`; + + assert(!isUndefined(this.subscriptions[subscription]), `Unable to find active subscription=${subscription}`); - delete this.subscriptions[id]; + delete this.subscriptions[subscription]; const result = await this.send(method, [id]); @@ -178,12 +184,12 @@ export default class WsProvider extends E3.EventEmitter implements WSProviderInt } try { - const { method, params, subscription } = this.handlers[response.id]; + const { method, params, subscription } = handler; const result = this.coder.decodeResponse(response); if (subscription) { - this.subscriptions[`${method}::${result}`] = { - callback: subscription, + this.subscriptions[`${subscription.type}::${result}`] = { + ...subscription, method, params }; diff --git a/packages/api-provider/src/ws/onMessageSubscribe.spec.js b/packages/api-provider/src/ws/onMessageSubscribe.spec.js index 856130505e8b..4ced0407f431 100644 --- a/packages/api-provider/src/ws/onMessageSubscribe.spec.js +++ b/packages/api-provider/src/ws/onMessageSubscribe.spec.js @@ -29,9 +29,12 @@ describe('onMessageSubscribe', () => { ws.handlers[11] = { callback: (_, id) => {}, method: 'test', - subscription: (_, result) => { - expect(result).toEqual('test'); - done(); + subscription: { + callback: (_, result) => { + expect(result).toEqual('test'); + done(); + }, + type: 'test' } }; @@ -43,9 +46,12 @@ describe('onMessageSubscribe', () => { ws.handlers[11] = { callback: (_, id) => {}, method: 'test', - subscription: (error) => { - expect(error.message).toMatch(/test/); - done(); + subscription: { + callback: (error) => { + expect(error.message).toMatch(/test/); + done(); + }, + type: 'test' } }; diff --git a/packages/api-provider/src/ws/unsubscribe.spec.js b/packages/api-provider/src/ws/unsubscribe.spec.js index 6082cf3df0e8..1df76b027e8a 100644 --- a/packages/api-provider/src/ws/unsubscribe.spec.js +++ b/packages/api-provider/src/ws/unsubscribe.spec.js @@ -56,9 +56,9 @@ describe('subscribe', () => { const ws = createWs(); return ws - .subscribe('subscribe_test', [], () => {}) + .subscribe('test', 'subscribe_test', [], () => {}) .then((id) => { - return ws.unsubscribe('subscribe_test', id); + return ws.unsubscribe('test', 'subscribe_test', id); }); }); @@ -74,9 +74,9 @@ describe('subscribe', () => { const ws = createWs(); return ws - .subscribe('subscribe_test', [], () => {}) + .subscribe('test', 'subscribe_test', [], () => {}) .then((id) => { - return ws.unsubscribe('subscribe_test', 111); + return ws.unsubscribe('test', 'subscribe_test', 111); }) .catch((error) => { expect(error.message).toMatch(/find active subscription/); diff --git a/packages/api/src/create/formatResult.spec.js b/packages/api/src/create/formatResult.spec.js index f3903582b9b0..b5f352502604 100644 --- a/packages/api/src/create/formatResult.spec.js +++ b/packages/api/src/create/formatResult.spec.js @@ -21,7 +21,7 @@ describe('formatResult', () => { send: jest.fn((method, params) => Promise.resolve('0x0102') ), - subscribe: jest.fn((method, params, subscription) => + subscribe: jest.fn((type, method, params, subscription) => subscription(null, { block: '0x1234', changes: [ @@ -61,6 +61,7 @@ describe('formatResult', () => { expect( provider.subscribe ).toHaveBeenCalledWith( + 'state_storage', 'state_subscribeStorage', [[ENC_ONE, ENC_TWO]], expect.anything() diff --git a/packages/api/src/create/methodSubscribe.ts b/packages/api/src/create/methodSubscribe.ts index 70069c190556..ce352fefdfdb 100644 --- a/packages/api/src/create/methodSubscribe.ts +++ b/packages/api/src/create/methodSubscribe.ts @@ -17,7 +17,7 @@ import formatResult from './formatResult'; export default function methodSubscribe (provider: ProviderInterface, rpcName: string, method: SectionItem): ApiInterface$Section$Method { const unsubscribe = (subscriptionId: any): Promise => - provider.send(method.subscribe[1], [subscriptionId]); + provider.unsubscribe(rpcName, method.subscribe[1], subscriptionId); const _call = async (...values: Array): Promise => { try { const cb: ProviderInterface$Callback = values.pop(); @@ -29,7 +29,7 @@ export default function methodSubscribe (provider: ProviderInterface, rpcName: s cb(error, formatResult(method, params, values, result)); }; - return provider.subscribe(method.subscribe[0], params, update); + return provider.subscribe(rpcName, method.subscribe[0], params, update); } catch (error) { throw new ExtError(`${signature(method)}:: ${error.message}`, (error as ExtError).code, undefined); }