Adjust class privates via #, where applicable (#1921)

* Adjust class priates via #, where applicable

* Remove stray log

* Cleanup rpc-provider

* Small adjustments

* No private access in tests

* Submittable privates

* Use derive for nonce derivation

* Tweak observers

* Alphabetical privates
This commit is contained in:
Jaco Greeff
2020-02-22 11:29:50 +01:00
committed by GitHub
parent ccf32a6289
commit 3bf4c3fac5
32 changed files with 406 additions and 514 deletions
+3 -3
View File
@@ -8,7 +8,7 @@ import { assert, isUndefined, isNumber, isString } from '@polkadot/util';
/** @internal */
export default class RpcCoder {
private id = 0;
#id = 0;
public decodeResponse (response: JsonRpcResponse): any {
assert(response, 'Empty response object received');
@@ -39,7 +39,7 @@ export default class RpcCoder {
public encodeObject (method: string, params: any | any[]): JsonRpcRequest {
return {
id: ++this.id,
id: ++this.#id,
jsonrpc: '2.0',
method,
params
@@ -47,7 +47,7 @@ export default class RpcCoder {
}
public getId (): number {
return this.id;
return this.#id;
}
private checkError (error?: JsonRpcResponseBaseError): void {
+7 -7
View File
@@ -36,9 +36,9 @@ const l = logger('api-http');
* @see [[WsProvider]]
*/
export default class HttpProvider implements ProviderInterface {
private coder: Coder;
readonly #coder: Coder;
private endpoint: string;
readonly #endpoint: string;
/**
* @param {string} endpoint The endpoint url starting with http://
@@ -46,8 +46,8 @@ export default class HttpProvider implements ProviderInterface {
constructor (endpoint: string = defaults.HTTP_URL) {
assert(/^(https|http):\/\//.test(endpoint), `Endpoint should start with 'http://', received '${endpoint}'`);
this.coder = new Coder();
this.endpoint = endpoint;
this.#coder = new Coder();
this.#endpoint = endpoint;
}
/**
@@ -95,8 +95,8 @@ export default class HttpProvider implements ProviderInterface {
* @summary Send HTTP POST Request with Body to configured HTTP Endpoint.
*/
public async send (method: string, params: any[]): Promise<any> {
const body = this.coder.encodeJson(method, params);
const response = await fetch(this.endpoint, {
const body = this.#coder.encodeJson(method, params);
const response = await fetch(this.#endpoint, {
body,
headers: {
Accept: 'application/json',
@@ -110,7 +110,7 @@ export default class HttpProvider implements ProviderInterface {
const result = await response.json();
return this.coder.decodeResponse(result);
return this.#coder.decodeResponse(result);
}
/**
+77 -81
View File
@@ -65,25 +65,25 @@ const l = logger('api-ws');
* @see [[HttpProvider]]
*/
export default class WsProvider implements WSProviderInterface {
private _eventemitter: EventEmitter;
readonly #coder: Coder;
private _isConnected = false;
readonly #endpoint: string;
private autoConnect: boolean;
readonly #eventemitter: EventEmitter;
private coder: Coder;
readonly #handlers: Record<string, WsStateAwaiting> = {};
private endpoint: string;
readonly #queued: Record<string, string> = {};
private handlers: Record<string, WsStateAwaiting>;
readonly #waitingForId: Record<string, JsonRpcResponse> = {};
private queued: Record<string, string>;
#autoConnect: boolean;
private subscriptions: Record<string, WsStateSubscription>;
#isConnected = false;
private waitingForId: Record<string, JsonRpcResponse>;
#subscriptions: Record<string, WsStateSubscription> = {};
private websocket: WebSocket | null;
#websocket: WebSocket | null;
/**
* @param {string} endpoint The endpoint url. Usually `ws://ip:9944` or `wss://ip:9944`
@@ -92,15 +92,11 @@ export default class WsProvider implements WSProviderInterface {
constructor (endpoint: string = defaults.WS_URL, autoConnect = true) {
assert(/^(wss|ws):\/\//.test(endpoint), `Endpoint should start with 'ws://', received '${endpoint}'`);
this._eventemitter = new EventEmitter();
this.autoConnect = autoConnect;
this.coder = new Coder();
this.endpoint = endpoint;
this.handlers = {};
this.queued = {};
this.subscriptions = {};
this.waitingForId = {};
this.websocket = null;
this.#eventemitter = new EventEmitter();
this.#autoConnect = autoConnect;
this.#coder = new Coder();
this.#endpoint = endpoint;
this.#websocket = null;
if (autoConnect) {
this.connect();
@@ -118,7 +114,7 @@ export default class WsProvider implements WSProviderInterface {
* @description Returns a clone of the object
*/
public clone (): WsProvider {
return new WsProvider(this.endpoint);
return new WsProvider(this.#endpoint);
}
/**
@@ -128,12 +124,11 @@ export default class WsProvider implements WSProviderInterface {
*/
public connect (): void {
try {
this.websocket = new WebSocket(this.endpoint);
this.websocket.onclose = this.onSocketClose;
this.websocket.onerror = this.onSocketError;
this.websocket.onmessage = this.onSocketMessage;
this.websocket.onopen = this.onSocketOpen;
this.#websocket = new WebSocket(this.#endpoint);
this.#websocket.onclose = this.#onSocketClose;
this.#websocket.onerror = this.#onSocketError;
this.#websocket.onmessage = this.#onSocketMessage;
this.#websocket.onopen = this.#onSocketOpen;
} catch (error) {
l.error(error);
}
@@ -143,16 +138,16 @@ export default class WsProvider implements WSProviderInterface {
* @description Manually disconnect from the connection, clearing autoconnect logic
*/
public disconnect (): void {
if (isNull(this.websocket)) {
if (isNull(this.#websocket)) {
throw new Error('Cannot disconnect on a non-open websocket');
}
// switch off autoConnect, we are in manual mode now
this.autoConnect = false;
this.#autoConnect = false;
// 1000 - Normal closure; the connection successfully completed
this.websocket.close(1000);
this.websocket = null;
this.#websocket.close(1000);
this.#websocket = null;
}
/**
@@ -160,7 +155,7 @@ export default class WsProvider implements WSProviderInterface {
* @return {boolean} true if connected
*/
public isConnected (): boolean {
return this._isConnected;
return this.#isConnected;
}
/**
@@ -170,9 +165,10 @@ export default class WsProvider implements WSProviderInterface {
* @return unsubscribe function
*/
public on (type: ProviderInterfaceEmitted, sub: ProviderInterfaceEmitCb): () => void {
this._eventemitter.on(type, sub);
this.#eventemitter.on(type, sub);
return (): void => {
this._eventemitter.removeListener(type, sub);
this.#eventemitter.removeListener(type, sub);
};
}
@@ -185,8 +181,8 @@ export default class WsProvider implements WSProviderInterface {
public send (method: string, params: any[], subscription?: SubscriptionHandler): Promise<any> {
return new Promise((resolve, reject): void => {
try {
const json = this.coder.encodeJson(method, params);
const id = this.coder.getId();
const json = this.#coder.encodeJson(method, params);
const id = this.#coder.getId();
const callback = (error?: Error | null, result?: any): void => {
error
? reject(error)
@@ -195,17 +191,17 @@ export default class WsProvider implements WSProviderInterface {
l.debug((): string[] => ['calling', method, json]);
this.handlers[id] = {
this.#handlers[id] = {
callback,
method,
params,
subscription
};
if (this.isConnected() && !isNull(this.websocket)) {
this.websocket.send(json);
if (this.isConnected() && !isNull(this.#websocket)) {
this.#websocket.send(json);
} else {
this.queued[id] = json;
this.#queued[id] = json;
}
} catch (error) {
reject(error);
@@ -252,55 +248,55 @@ export default class WsProvider implements WSProviderInterface {
// the assigned id now does not match what the API user originally received. It has
// a slight complication in solving - since we cannot rely on the send id, but rather
// need to find the actual subscription id to map it
if (isUndefined(this.subscriptions[subscription])) {
if (isUndefined(this.#subscriptions[subscription])) {
l.debug((): string => `Unable to find active subscription=${subscription}`);
return false;
}
delete this.subscriptions[subscription];
delete this.#subscriptions[subscription];
const result = await this.send(method, [id]);
return result as boolean;
}
private emit (type: ProviderInterfaceEmitted, ...args: any[]): void {
this._eventemitter.emit(type, ...args);
#emit = (type: ProviderInterfaceEmitted, ...args: any[]): void => {
this.#eventemitter.emit(type, ...args);
}
private onSocketClose = (event: CloseEvent): void => {
if (this.autoConnect) {
l.error(`disconnected from ${this.endpoint} code: '${event.code}' reason: '${event.reason}'`);
#onSocketClose = (event: CloseEvent): void => {
if (this.#autoConnect) {
l.error(`disconnected from ${this.#endpoint} code: '${event.code}' reason: '${event.reason}'`);
}
this._isConnected = false;
this.emit('disconnected');
this.#isConnected = false;
this.#emit('disconnected');
if (this.autoConnect) {
if (this.#autoConnect) {
setTimeout((): void => {
this.connect();
}, 1000);
}
}
private onSocketError = (error: Event): void => {
#onSocketError = (error: Event): void => {
l.debug((): any => ['socket error', error]);
this.emit('error', error);
this.#emit('error', error);
}
private onSocketMessage = (message: MessageEvent): void => {
#onSocketMessage = (message: MessageEvent): void => {
l.debug((): any => ['received', message.data]);
const response: JsonRpcResponse = JSON.parse(message.data as string);
return isUndefined(response.method)
? this.onSocketMessageResult(response)
: this.onSocketMessageSubscribe(response);
? this.#onSocketMessageResult(response)
: this.#onSocketMessageSubscribe(response);
}
private onSocketMessageResult = (response: JsonRpcResponse): void => {
const handler = this.handlers[response.id];
#onSocketMessageResult = (response: JsonRpcResponse): void => {
const handler = this.#handlers[response.id];
if (!handler) {
l.debug((): string => `Unable to find handler for id=${response.id}`);
@@ -309,7 +305,7 @@ export default class WsProvider implements WSProviderInterface {
try {
const { method, params, subscription } = handler;
const result = this.coder.decodeResponse(response);
const result = this.#coder.decodeResponse(response);
// first send the result - in case of subs, we may have an update
// immediately if we have some queued results already
@@ -318,42 +314,42 @@ export default class WsProvider implements WSProviderInterface {
if (subscription) {
const subId = `${subscription.type}::${result}`;
this.subscriptions[subId] = {
this.#subscriptions[subId] = {
...subscription,
method,
params
};
// if we have a result waiting for this subscription already
if (this.waitingForId[subId]) {
this.onSocketMessageSubscribe(this.waitingForId[subId]);
if (this.#waitingForId[subId]) {
this.#onSocketMessageSubscribe(this.#waitingForId[subId]);
}
}
} catch (error) {
handler.callback(error, undefined);
}
delete this.handlers[response.id];
delete this.#handlers[response.id];
}
private onSocketMessageSubscribe = (response: JsonRpcResponse): void => {
#onSocketMessageSubscribe = (response: JsonRpcResponse): void => {
const method = ALIASSES[response.method as string] || response.method;
const subId = `${method}::${response.params.subscription}`;
const handler = this.subscriptions[subId];
const handler = this.#subscriptions[subId];
if (!handler) {
// store the JSON, we could have out-of-order subid coming in
this.waitingForId[subId] = response;
this.#waitingForId[subId] = response;
l.debug((): string => `Unable to find handler for subscription=${subId}`);
return;
}
// housekeeping
delete this.waitingForId[subId];
delete this.#waitingForId[subId];
try {
const result = this.coder.decodeResponse(response);
const result = this.#coder.decodeResponse(response);
handler.callback(null, result);
} catch (error) {
@@ -361,24 +357,24 @@ export default class WsProvider implements WSProviderInterface {
}
}
private onSocketOpen = (): boolean => {
assert(!isNull(this.websocket), 'WebSocket cannot be null in onOpen');
#onSocketOpen = (): boolean => {
assert(!isNull(this.#websocket), 'WebSocket cannot be null in onOpen');
l.debug((): any[] => ['connected to', this.endpoint]);
l.debug((): any[] => ['connected to', this.#endpoint]);
this._isConnected = true;
this.emit('connected');
this.#isConnected = true;
this.sendQueue();
this.resubscribe();
this.#emit('connected');
this.#sendQueue();
this.#resubscribe();
return true;
}
private resubscribe (): void {
const subscriptions = this.subscriptions;
#resubscribe = (): void => {
const subscriptions = this.#subscriptions;
this.subscriptions = {};
this.#subscriptions = {};
// eslint-disable-next-line @typescript-eslint/no-misused-promises
Object.keys(subscriptions).forEach(async (id): Promise<void> => {
@@ -399,15 +395,15 @@ export default class WsProvider implements WSProviderInterface {
});
}
private sendQueue (): void {
Object.keys(this.queued).forEach((id): void => {
#sendQueue = (): void => {
Object.keys(this.#queued).forEach((id): void => {
try {
// we have done the websocket check in onSocketOpen, if an issue, will catch it
(this.websocket as WebSocket).send(
this.queued[id]
(this.#websocket as WebSocket).send(
this.#queued[id]
);
delete this.queued[id];
delete this.#queued[id];
} catch (error) {
l.error(error);
}
+5 -20
View File
@@ -21,38 +21,23 @@ describe('onConnect', (): void => {
it('Does not connect when autoConnect is false', (): void => {
const provider: WsProvider = new WsProvider(TEST_WS_URL, false);
// We need to access the private WsProvider property 'websocket' here which would otherwise trigger a tslint error.
expect((provider as any).websocket).toBeNull();
expect(provider.isConnected()).toBe(false);
});
it('Does connect when autoConnect is true', (): void => {
const provider: WsProvider = new WsProvider(TEST_WS_URL, true);
expect((provider as any).websocket).not.toBeNull();
expect(provider.isConnected()).not.toBe(true);
});
it('Creates a new WebSocket instance by calling the connect() method', (): void => {
const provider: WsProvider = new WsProvider(TEST_WS_URL, false);
expect((provider as any).websocket).toBeNull();
expect(provider.isConnected()).toBe(false);
provider.connect();
expect((provider as any).websocket).not.toBeNull();
expect((provider as any).websocket instanceof WebSocket).toBe(true);
});
it('Creates the on handlers', (): void => {
const provider: WsProvider = new WsProvider(TEST_WS_URL);
expect((provider as any).websocket).not.toBeNull();
expect((provider as any).websocket).toEqual(expect.objectContaining({
listeners: expect.objectContaining({
close: [expect.any(Function)],
error: [expect.any(Function)],
message: [expect.any(Function)],
open: [expect.any(Function)]
})
}));
expect(provider.isConnected()).not.toBe(true);
});
});
@@ -1,30 +0,0 @@
// Copyright 2017-2020 @polkadot/rpc-provider authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import WsProvider from './';
describe('WsProvider', (): void => {
let provider: WsProvider;
beforeEach((): void => {
provider = new WsProvider('ws://127.0.0.1:1234', false);
});
it('calls the handler when found', (done): void => {
// We need to access the private WsProvider property 'handlers' here which otherwise trigger a tslint error..
(provider as any).handlers[5] = {
callback: (_: any, result: any): void => {
expect(result).toEqual('test');
done();
},
method: '',
params: []
};
// We need to access the private WsProvider property 'onSocketMessage' here which would otherwise trigger a tslint error.
(provider as any).onSocketMessage(
new MessageEvent('test', { data: '{"jsonrpc":"2.0","id":5,"result":"test"}' })
);
});
});
@@ -1,57 +0,0 @@
// Copyright 2017-2020 @polkadot/rpc-provider authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import WsProvider from './';
describe('onMessageSubscribe', (): void => {
let provider: WsProvider;
beforeEach((): void => {
provider = new WsProvider('ws://127.0.0.1:1234', false);
});
it('calls the subscriber with data', (done): void => {
// We need to access the private WsProvider property 'handlers' here which otherwise triggers a tslint error..
(provider as any).handlers[11] = {
callback: (_: any, id: number): void => {
expect(typeof id).toBe('number');
},
method: 'test',
params: [],
subscription: {
callback: (_: any, result: any): void => {
expect(result).toEqual('test');
done();
},
type: 'test'
}
};
// We need to access the private WsProvider property 'onSocketMessage' here which would otherwise trigger a tslint error.
(provider as any).onSocketMessage(new MessageEvent('test', { data: '{"jsonrpc":"2.0","id":11,"result":22}' }));
(provider as any).onSocketMessage(new MessageEvent('test', { data: '{"jsonrpc":"2.0","method":"test","params":{"subscription":22,"result":"test"}}' }));
});
it('calls the subscriber with error', (done): void => {
// We need to access the private WsProvider property 'handlers' here which otherwise trigger a tslint error..
(provider as any).handlers[11] = {
callback: (_: any, id: number): void => {
expect(typeof id).toBe('number');
},
method: 'test',
params: [],
subscription: {
callback: (error: any): void => {
expect(error.message).toMatch(/test/);
done();
},
type: 'test'
}
};
// We need to access the private WsProvider property 'onSocketMessage' here which would otherwise trigger a tslint error.
(provider as any).onSocketMessage(new MessageEvent('test', { data: '{"jsonrpc":"2.0","id":11,"result":22}' }));
(provider as any).onSocketMessage(new MessageEvent('test', { data: '{"jsonrpc":"2.0","method":"test","params":{"subscription":22,"error":{"message":"test"}}}' }));
});
});
+8 -13
View File
@@ -39,21 +39,16 @@ describe('send', (): void => {
});
it('handles internal errors', (): Promise<any> => {
createMock([]);
(global as any).WebSocket = class {
public send (): void {
throw new Error('send error');
createMock([{
id: 1,
method: 'test_body',
reply: {
result: 'ok'
}
};
}]);
provider = createWs(true);
// HACK this is a private method...
(provider as any).websocket.onopen();
return provider
.send('test_encoding', ['param'])
return createWs(true)
.send('test_encoding', [{ error: 'send error' }])
.catch((error): void => {
expect(error.message).toEqual('send error');
});