Skip to content

Commit

Permalink
feat: refactor clientjs to support err handling
Browse files Browse the repository at this point in the history
and notifications

Clientjs needed a refactor, because error states from
failed transports and notifications would silently
fail or would require exceptional handling. Additionally
the refactor adds support for timeout, and eventual
implementation of request strategies for choosing
which transport to use in a request.

This refactor exposes notifications handler, and error handler
as well as a timeout handler for timing out request. The refactor
also moves request resolution to be handle by the transport,
and transport selection and batching start and stopping to be
handled by the request manager freeing multiple transports
to potentially be used at the same time.
  • Loading branch information
zcstarr committed Sep 13, 2019
1 parent 42260ee commit c3686c9
Show file tree
Hide file tree
Showing 23 changed files with 1,041 additions and 341 deletions.
3 changes: 2 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ module.exports = {
"restoreMocks": true,
"rootDir": "./src",
"testEnvironment": "jsdom",
"preset": "ts-jest"
"preset": "ts-jest",
"coveragePathIgnorePatterns": ["Error.ts"],
}
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"dependencies": {
"isomorphic-fetch": "^2.2.1",
"isomorphic-ws": "^4.0.1",
"strict-event-emitter-types": "^2.0.0",
"ws": "^7.0.0"
}
}
19 changes: 19 additions & 0 deletions src/Error.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { convertJSONToRPCError, JSONRPCError } from "./Error";
import { generateMockErrorResponse } from "./__mocks__/requestData";

describe("Error test", () => {

it("should convert payload to JSONRPC error ", () => {

let err = convertJSONToRPCError("message");
expect(err instanceof Error).toBe(true);
err = convertJSONToRPCError(generateMockErrorResponse(1, "somedata"));
expect(err instanceof Error).toBe(true);
});

it("should construct JSONRPCError", () => {
const err = new JSONRPCError("test", 9999);
const err2 = new JSONRPCError("test", 9999, "testdata");
});

});
23 changes: 23 additions & 0 deletions src/Error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export const ERR_TIMEOUT = 7777;
export const ERR_MISSIING_ID = 7878;
export const ERR_UNKNOWN = 7979;

export class JSONRPCError extends Error {
public message: string;
public code: number;
public data: any;
constructor(message: string, code: number, data?: any) {
super(message);
this.message = message;
this.code = code;
this.data = data;
}
}

export const convertJSONToRPCError = (payload: any): JSONRPCError => {
if (payload.error) {
const { message, code, data } = payload.error;
return new JSONRPCError(message, code, data);
}
return new JSONRPCError("Unknown error", ERR_UNKNOWN, payload);
};
89 changes: 89 additions & 0 deletions src/Request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@

export type JSONRPCRequestData = IJSONRPCData | IBatchRequest[] ;

export interface IJSONRPCData {
internalID: string | number;
request: IJSONRPCRequest | IJSONRPCNotification;
}

export interface IBatchRequest {
resolve: (data: any) => void;
reject: (data: any) => void;
request: IJSONRPCData; // IJSONRPCNotification | IJSONRPCRequest;
}

export interface IJSONRPCRequest {
jsonrpc: "2.0";
id: string | number;
method: string;
params: any[] | object;
}

export interface IJSONRPCError {
code: number;
message: string;
data: any;
}

export interface IJSONRPCResponse {
jsonrpc: "2.0";
id: string | number; // can also be null
result?: any;
error?: IJSONRPCError;
}

export interface IJSONRPCNotificationResponse {
jsonrpc: "2.0";
id?: null | undefined;
result?: any;
error?: IJSONRPCError;
}

export interface IJSONRPCNotification {
jsonrpc: "2.0";
id?: null | undefined;
method: string;
params: any[] | object;
}

interface IRPCRequest {
method: string;
params: any[];
type: "single";
}

interface IBatchRPCRequest {
type: "batch";
batch: IJSONRPCRequest[];
}

export type Request = IRPCRequest | IBatchRPCRequest;

export const isNotification = (data: IJSONRPCData): boolean => {
return (data.request.id === undefined || data.request.id === null);
};

export const getBatchRequests = (data: JSONRPCRequestData): IJSONRPCData[] => {
if (data instanceof Array) {
return data.filter((datum) => {
const id = datum.request.request.id;
return id !== null && id !== undefined;
}).map((batchRequest: IBatchRequest) => {
return batchRequest.request;
});
}
return [];
};
export const getNotifications = (data: JSONRPCRequestData): IJSONRPCData[] => {
if (data instanceof Array) {
return data.filter((datum) => {
return isNotification(datum.request);
}).map((batchRequest: IBatchRequest) => {
return batchRequest.request;
});
}
if (isNotification(data)) {
return [data];
}
return [];
};
Loading

0 comments on commit c3686c9

Please sign in to comment.