Skip to content

Commit

Permalink
fix: initial transport implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
shanejonas committed May 14, 2019
1 parent 991ef68 commit e5cb09f
Show file tree
Hide file tree
Showing 12 changed files with 353 additions and 15 deletions.
94 changes: 82 additions & 12 deletions package-lock.json

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

7 changes: 7 additions & 0 deletions package.json
Expand Up @@ -19,10 +19,17 @@
},
"homepage": "https://github.com/open-rpc/client-js#readme",
"devDependencies": {
"@types/isomorphic-fetch": "0.0.35",
"@types/jest": "^24.0.12",
"@types/websocket": "0.0.40",
"jest": "^24.8.0",
"ts-jest": "^24.0.2",
"tslint": "^5.16.0",
"typescript": "^3.4.5"
},
"dependencies": {
"isomorphic-fetch": "^2.2.1",
"isomorphic-ws": "^4.0.1",
"ws": "^7.0.0"
}
}
36 changes: 36 additions & 0 deletions src/RequestManager.test.ts
@@ -0,0 +1,36 @@
import RequestManager from "./RequestManager";
import EventEmitterTransport from "./transports/EventEmitterTransport";

describe("client-js", () => {
it("can be constructed", () => {
const transport = new EventEmitterTransport("foo://unique-uri");
const c = new RequestManager([transport]);
expect(!!c).toEqual(true);
});

it("has a request method that returns a promise", () => {
const transport = new EventEmitterTransport("foo://unique-uri");
const c = new RequestManager([transport]);
expect(typeof c.request).toEqual("function");
expect(typeof c.request("my_method", null).then).toEqual("function");
});

it("can connect", () => {
const transport = new EventEmitterTransport("foo://unique-uri");
const c = new RequestManager([transport]);
return c.connect();
});

it("can send a request", (done) => {
const transport = new EventEmitterTransport("foo://unique-uri");
const c = new RequestManager([transport]);
c.connect();
transport.onData((data: any) => {
const d = JSON.parse(data);
expect(d.method).toEqual("foo");
done();
});
c.request("foo", []);
});

});
61 changes: 61 additions & 0 deletions src/RequestManager.ts
@@ -0,0 +1,61 @@
import ITransport from "./transports/Transport";
let id = 1;

/*
** Naive Request Manager, only use 1st transport.
* A more complex request manager could try each transport.
* If a transport fails, or times out, move on to the next.
*/
class RequestManager {
public transports: ITransport[];
private requests: any;
private connectPromise: Promise<any>;
constructor(transports: ITransport[]) {
this.transports = transports;
this.requests = {};
this.connectPromise = this.connect();
}
public connect() {
const promises = this.transports.map((transport) => {
return new Promise(async (resolve, reject) => {
await transport.connect();
transport.onData((data: any) => {
this.onData(data);
});
resolve();
});
});
return Promise.all(promises);
}
public onData(data: string) {
const parsedData = JSON.parse(data);
if (typeof parsedData.result === "undefined") {
return;
}
// call request callback for id
this.requests[parsedData.id](parsedData);
delete this.requests[parsedData.id];
}
public async request(method: string, params: any): Promise<any> {
await this.connectPromise;
return new Promise((resolve, reject) => {
const i = id++;
// naively grab first transport and use it
const transport = this.transports[0];
this.requests[i] = resolve;
transport.sendData(JSON.stringify({
jsonrpc: "2.0",
id: i,
method,
params,
}));
});
}
public close() {
this.transports.forEach((transport) => {
transport.close();
});
}
}

export default RequestManager;
12 changes: 12 additions & 0 deletions src/example.ts
@@ -0,0 +1,12 @@
import Client from ".";
import RequestManager from "./RequestManager";
import Transport from "./transports/HTTPTransport";

const t = new Transport("http://localhost:8545");

const c = new Client(new RequestManager([t]));

// make request for eth_blockNumber
c.request("eth_blockNumber", []).then((b: any) => {
console.log('in then', b); //tslint:disable-line
});
8 changes: 6 additions & 2 deletions src/index.test.ts
@@ -1,14 +1,18 @@
import Client from ".";
import RequestManager from "./RequestManager";
import EventEmitterTransport from "./transports/EventEmitterTransport";

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

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

});
7 changes: 6 additions & 1 deletion src/index.ts
@@ -1,11 +1,16 @@
import RequestManager from "./RequestManager";

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

class Client implements IClient {
public requestManager: RequestManager;
constructor(requestManager: RequestManager) {
this.requestManager = requestManager;
}
public request(method: string, params: any) {
return new Promise(() => {/* */});
return this.requestManager.request(method, params);
}
}

Expand Down
21 changes: 21 additions & 0 deletions src/transports/EventEmitterTransport.test.ts
@@ -0,0 +1,21 @@
import EventEmitterTransport from "./EventEmitterTransport";

describe("EventEmitterTransport", () => {
it("can connect", () => {
const eventEmitterTransport = new EventEmitterTransport("foo://bar");
eventEmitterTransport.connect();
});
it("can close", () => {
const eventEmitterTransport = new EventEmitterTransport("foo://bar");
eventEmitterTransport.close();
});
it("can send and receive data", (done) => {
const eventEmitterTransport = new EventEmitterTransport("foo://bar");
eventEmitterTransport.onData((data: any) => {
const d = JSON.parse(data);
expect(d.foo).toEqual("bar");
done();
});
eventEmitterTransport.sendData(JSON.stringify({foo: "bar"}));
});
});

0 comments on commit e5cb09f

Please sign in to comment.