Sitelet https://github.com/open-rpc/client-js/commit/e5cb09f
Skip to content

Commit e5cb09f

Browse files
committed
fix: initial transport implementation
1 parent 991ef68 commit e5cb09f

12 files changed

Lines changed: 353 additions & 15 deletions

‎package-lock.json‎

Lines changed: 82 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,17 @@
1919
},
2020
"homepage": "https://github.com/open-rpc/client-js#readme",
2121
"devDependencies": {
22+
"@types/isomorphic-fetch": "0.0.35",
2223
"@types/jest": "^24.0.12",
24+
"@types/websocket": "0.0.40",
2325
"jest": "^24.8.0",
2426
"ts-jest": "^24.0.2",
2527
"tslint": "^5.16.0",
2628
"typescript": "^3.4.5"
29+
},
30+
"dependencies": {
31+
"isomorphic-fetch": "^2.2.1",
32+
"isomorphic-ws": "^4.0.1",
33+
"ws": "^7.0.0"
2734
}
2835
}

‎src/RequestManager.test.ts‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import RequestManager from "./RequestManager";
2+
import EventEmitterTransport from "./transports/EventEmitterTransport";
3+
4+
describe("client-js", () => {
5+
it("can be constructed", () => {
6+
const transport = new EventEmitterTransport("foo://unique-uri");
7+
const c = new RequestManager([transport]);
8+
expect(!!c).toEqual(true);
9+
});
10+
11+
it("has a request method that returns a promise", () => {
12+
const transport = new EventEmitterTransport("foo://unique-uri");
13+
const c = new RequestManager([transport]);
14+
expect(typeof c.request).toEqual("function");
15+
expect(typeof c.request("my_method", null).then).toEqual("function");
16+
});
17+
18+
it("can connect", () => {
19+
const transport = new EventEmitterTransport("foo://unique-uri");
20+
const c = new RequestManager([transport]);
21+
return c.connect();
22+
});
23+
24+
it("can send a request", (done) => {
25+
const transport = new EventEmitterTransport("foo://unique-uri");
26+
const c = new RequestManager([transport]);
27+
c.connect();
28+
transport.onData((data: any) => {
29+
const d = JSON.parse(data);
30+
expect(d.method).toEqual("foo");
31+
done();
32+
});
33+
c.request("foo", []);
34+
});
35+
36+
});

‎src/RequestManager.ts‎

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import ITransport from "./transports/Transport";
2+
let id = 1;
3+
4+
/*
5+
** Naive Request Manager, only use 1st transport.
6+
* A more complex request manager could try each transport.
7+
* If a transport fails, or times out, move on to the next.
8+
*/
9+
class RequestManager {
10+
public transports: ITransport[];
11+
private requests: any;
12+
private connectPromise: Promise<any>;
13+
constructor(transports: ITransport[]) {
14+
this.transports = transports;
15+
this.requests = {};
16+
this.connectPromise = this.connect();
17+
}
18+
public connect() {
19+
const promises = this.transports.map((transport) => {
20+
return new Promise(async (resolve, reject) => {
21+
await transport.connect();
22+
transport.onData((data: any) => {
23+
this.onData(data);
24+
});
25+
resolve();
26+
});
27+
});
28+
return Promise.all(promises);
29+
}
30+
public onData(data: string) {
31+
const parsedData = JSON.parse(data);
32+
if (typeof parsedData.result === "undefined") {
33+
return;
34+
}
35+
// call request callback for id
36+
this.requests[parsedData.id](parsedData);
37+
delete this.requests[parsedData.id];
38+
}
39+
public async request(method: string, params: any): Promise<any> {
40+
await this.connectPromise;
41+
return new Promise((resolve, reject) => {
42+
const i = id++;
43+
// naively grab first transport and use it
44+
const transport = this.transports[0];
45+
this.requests[i] = resolve;
46+
transport.sendData(JSON.stringify({
47+
jsonrpc: "2.0",
48+
id: i,
49+
method,
50+
params,
51+
}));
52+
});
53+
}
54+
public close() {
55+
this.transports.forEach((transport) => {
56+
transport.close();
57+
});
58+
}
59+
}
60+
61+
export default RequestManager;

‎src/example.ts‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import Client from ".";
2+
import RequestManager from "./RequestManager";
3+
import Transport from "./transports/HTTPTransport";
4+
5+
const t = new Transport("http://localhost:8545");
6+
7+
const c = new Client(new RequestManager([t]));
8+
9+
// make request for eth_blockNumber
10+
c.request("eth_blockNumber", []).then((b: any) => {
11+
console.log('in then', b); //tslint:disable-line
12+
});

‎src/index.test.ts‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import Client from ".";
2+
import RequestManager from "./RequestManager";
3+
import EventEmitterTransport from "./transports/EventEmitterTransport";
24

35
describe("client-js", () => {
46
it("can be constructed", () => {
5-
const c = new Client();
7+
const c = new Client(new RequestManager([new EventEmitterTransport("foo://unique")]));
68
expect(!!c).toEqual(true);
79
});
810

911
it("has a request method that returns a promise", () => {
10-
const c = new Client();
12+
const c = new Client(new RequestManager([new EventEmitterTransport("foo://unique")]));
13+
console.log("test city before"); // tslint:disable-line
1114
expect(typeof c.request).toEqual("function");
1215
expect(typeof c.request("my_method", null).then).toEqual("function");
1316
});
17+
1418
});

‎src/index.ts‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1+
import RequestManager from "./RequestManager";
12

23
interface IClient {
34
request(method: string, params: any): Promise<any>;
45
}
56

67
class Client implements IClient {
8+
public requestManager: RequestManager;
9+
constructor(requestManager: RequestManager) {
10+
this.requestManager = requestManager;
11+
}
712
public request(method: string, params: any) {
8-
return new Promise(() => {/* */});
13+
return this.requestManager.request(method, params);
914
}
1015
}
1116

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import EventEmitterTransport from "./EventEmitterTransport";
2+
3+
describe("EventEmitterTransport", () => {
4+
it("can connect", () => {
5+
const eventEmitterTransport = new EventEmitterTransport("foo://bar");
6+
eventEmitterTransport.connect();
7+
});
8+
it("can close", () => {
9+
const eventEmitterTransport = new EventEmitterTransport("foo://bar");
10+
eventEmitterTransport.close();
11+
});
12+
it("can send and receive data", (done) => {
13+
const eventEmitterTransport = new EventEmitterTransport("foo://bar");
14+
eventEmitterTransport.onData((data: any) => {
15+
const d = JSON.parse(data);
16+
expect(d.foo).toEqual("bar");
17+
done();
18+
});
19+
eventEmitterTransport.sendData(JSON.stringify({foo: "bar"}));
20+
});
21+
});

0 commit comments

Comments
 (0)