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

Commit 097c960

Browse files
committed
fix: deterministic id and cleanup
1 parent 7423e52 commit 097c960

2 files changed

Lines changed: 55 additions & 71 deletions

File tree

‎src/RequestManager.test.ts‎

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,13 @@ describe("client-js", () => {
4747
});
4848
});
4949

50-
it("can return errors on batchng requests", async () => {
50+
it("can return errors on batch requests", async () => {
5151
const transport = new EventEmitterTransport("foo://unique-uri");
5252
transport.sendData = (data) => {
5353
const result = JSON.stringify([
5454
{
5555
jsonrpc: "2.0",
56-
id: 3,
56+
id: "0",
5757
error: {
5858
code: 509,
5959
message: "too much 509",
@@ -64,30 +64,30 @@ describe("client-js", () => {
6464
},
6565
{
6666
jsonrpc: "2.0",
67-
id: 4,
67+
id: "1",
6868
result: "bar",
6969
},
7070
]);
7171
transport.connection.emit("message", result);
7272
};
7373

7474
const c = new RequestManager([transport]);
75-
return c.connect().then(() => {
76-
c.startBatch();
77-
const requests = [
78-
c.request("foo", []),
79-
c.request("foo", []),
80-
];
81-
c.endBatch();
82-
expect(Promise.all(requests)).rejects.toEqual({
83-
code: 509,
84-
message: "too much 509",
85-
data: {
86-
test: "data",
87-
},
88-
});
89-
c.close();
75+
await c.connect();
76+
c.startBatch();
77+
const requests = [
78+
c.request("foo", []),
79+
c.request("foo", []),
80+
];
81+
expect(requests[0]).rejects.toEqual({
82+
code: 509,
83+
message: "too much 509",
84+
data: {
85+
test: "data",
86+
},
9087
});
88+
expect(requests[1]).resolves.toEqual("bar");
89+
c.endBatch();
90+
c.close();
9191
});
9292

9393
it("can batch a request", async () => {
@@ -96,33 +96,30 @@ describe("client-js", () => {
9696
const result = JSON.stringify([
9797
{
9898
jsonrpc: "2.0",
99-
id: 5,
99+
id: "0",
100100
result: "foo",
101101
},
102102
{
103103
jsonrpc: "2.0",
104-
id: 6,
104+
id: "1",
105105
result: "bar",
106106
},
107107
]);
108108
transport.connection.emit("message", result);
109109
};
110110

111111
const c = new RequestManager([transport]);
112-
return c.connect().then(() => {
113-
c.startBatch();
114-
const requests = [
115-
c.request("foo", []),
116-
c.request("foo", []),
117-
];
118-
c.endBatch();
119-
return Promise.all(requests).then((results) => {
120-
expect(results[0]).toEqual("foo");
121-
expect(results[1]).toEqual("bar");
122-
c.close();
123-
});
124-
125-
});
112+
await c.connect();
113+
c.startBatch();
114+
const requests = [
115+
c.request("foo", []),
116+
c.request("foo", []),
117+
];
118+
c.endBatch();
119+
const [a, b] = await Promise.all(requests);
120+
expect(a).toEqual("foo");
121+
expect(b).toEqual("bar");
122+
c.close();
126123
});
127124

128125
it("can send a request and error", async () => {

‎src/RequestManager.ts‎

Lines changed: 24 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import ITransport from "./transports/Transport";
22

3-
let id = 1;
4-
53
interface IJSONRPCRequest {
64
jsonrpc: "2.0";
7-
id: number;
5+
id: string;
86
method: string;
97
params: any[] | object;
108
}
@@ -16,7 +14,7 @@ interface IJSONRPCError {
1614

1715
interface IJSONRPCResponse {
1816
jsonrpc: "2.0";
19-
id: number;
17+
id: string; // can also be null
2018
result?: any;
2119
error?: IJSONRPCError;
2220
}
@@ -38,6 +36,7 @@ class RequestManager {
3836
private requests: any;
3937
private batchStarted: boolean = false;
4038
private batch: IJSONRPCRequest[] = [];
39+
private lastId: number = -1;
4140

4241
constructor(transports: ITransport[]) {
4342
this.transports = transports;
@@ -59,14 +58,15 @@ class RequestManager {
5958
}
6059

6160
public async request(method: string, params: any): Promise<any> {
61+
const i = (++this.lastId).toString();
6262
return new Promise((resolve, reject) => {
63-
const i = id++;
6463
// naively grab first transport and use it
6564
const transport = this.transports[0];
6665
this.requests[i] = {
6766
resolve,
6867
reject,
6968
};
69+
7070
const payload: IJSONRPCRequest = {
7171
jsonrpc: "2.0",
7272
id: i,
@@ -78,7 +78,7 @@ class RequestManager {
7878
} else {
7979
transport.sendData(JSON.stringify(payload));
8080
}
81-
});
81+
}).finally(() => this.requests[i] = undefined);
8282
}
8383

8484
public close(): void {
@@ -98,9 +98,6 @@ class RequestManager {
9898
this.batchStarted = true;
9999
}
100100

101-
/**
102-
*
103-
*/
104101
public endBatch(): void {
105102
if (this.batchStarted === false) {
106103
throw new Error("cannot end that which has never started");
@@ -117,34 +114,24 @@ class RequestManager {
117114

118115
private onData(data: string): void {
119116
const parsedData: IJSONRPCResponse[] | IJSONRPCResponse = JSON.parse(data);
120-
// handle batch requests
121-
if (Array.isArray(parsedData)) {
122-
parsedData.forEach((response) => {
123-
if (!this.requests[response.id]) {
124-
return;
125-
}
126-
if (response.error) {
127-
this.requests[response.id].reject(response.error);
128-
} else {
129-
this.requests[response.id].resolve(response.result);
130-
}
131-
});
132-
return;
133-
}
134-
if (typeof parsedData.result === "undefined" && typeof parsedData.error === "undefined") {
135-
return;
136-
}
137-
const req = this.requests[parsedData.id];
138-
if (req === undefined) {
139-
return;
140-
}
141-
// resolve promise for id
142-
if (parsedData.error) {
143-
req.reject(parsedData.error);
144-
} else {
145-
req.resolve(parsedData.result);
146-
}
147-
delete this.requests[parsedData.id];
117+
const results = parsedData instanceof Array ? parsedData : [parsedData];
118+
119+
results.forEach((response) => {
120+
const promiseForResult = this.requests[response.id];
121+
if (promiseForResult === undefined) {
122+
throw new Error(
123+
`Received an unrecognized response id: ${response.id}. Valid ids are: ${Object.keys(this.requests)}`,
124+
);
125+
}
126+
127+
if (response.error) {
128+
promiseForResult.reject(response.error);
129+
} else if (response.result) {
130+
promiseForResult.resolve(response.result);
131+
} else {
132+
throw new Error(`Malformed JSON-RPC response object: ${response}`);
133+
}
134+
});
148135
}
149136
}
150137

0 commit comments

Comments
 (0)