forked from cosmos/cosmjs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
httpclient.ts
131 lines (115 loc) · 3.8 KB
/
httpclient.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import {
isJsonRpcErrorResponse,
JsonRpcRequest,
JsonRpcSuccessResponse,
parseJsonRpcResponse,
} from "@cosmjs/json-rpc";
import axios from "axios";
import { hasProtocol, RpcClient } from "./rpcclient";
// Global symbols in some environments
// https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
declare const fetch: any | undefined;
function filterBadStatus(res: any): any {
if (res.status >= 400) {
throw new Error(`Bad status on response: ${res.status}`);
}
return res;
}
/**
* Helper to work around missing CORS support in Tendermint (https://github.com/tendermint/tendermint/pull/2800)
*
* For some reason, fetch does not complain about missing server-side CORS support.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function http(
method: "POST",
url: string,
headers: Record<string, string> | undefined,
request?: any,
): Promise<any> {
if (typeof fetch !== "undefined") {
const settings = {
method: method,
body: request ? JSON.stringify(request) : undefined,
headers: {
// eslint-disable-next-line @typescript-eslint/naming-convention
"Content-Type": "application/json",
...headers,
},
};
return fetch(url, settings)
.then(filterBadStatus)
.then((res: any) => res.json());
} else {
return axios
.request({ url: url, method: method, data: request, headers: headers })
.then((res) => res.data);
}
}
export interface HttpEndpoint {
/**
* The URL of the HTTP endpoint.
*
* For POST APIs like Tendermint RPC in CosmJS,
* this is without the method specific paths (e.g. https://cosmoshub-4--rpc--full.datahub.figment.io/)
*/
readonly url: string;
/**
* HTTP headers that are sent with every request, such as authorization information.
*/
readonly headers: Record<string, string>;
}
export interface HttpClientOptions {
dispatchInterval: number;
}
export const defaultHttpClientOptions: HttpClientOptions = { dispatchInterval: 0 };
export class HttpClient implements RpcClient {
protected readonly url: string;
protected readonly headers: Record<string, string> | undefined;
protected readonly options: HttpClientOptions;
private stack: Array<{
request: JsonRpcRequest;
resolve: (a: JsonRpcSuccessResponse) => void;
reject: (a: Error) => void;
}> = [];
public constructor(endpoint: string | HttpEndpoint, options: HttpClientOptions = defaultHttpClientOptions) {
this.options = options;
if (typeof endpoint === "string") {
// accept host.name:port and assume http protocol
this.url = hasProtocol(endpoint) ? endpoint : "http://" + endpoint;
} else {
this.url = endpoint.url;
this.headers = endpoint.headers;
}
setInterval(() => this.tick(), options.dispatchInterval);
}
public disconnect(): void {
// nothing to be done
}
public async execute(request: JsonRpcRequest): Promise<JsonRpcSuccessResponse> {
return new Promise((resolve, reject) => {
this.stack.push({ request, resolve, reject });
});
}
private async tick(): Promise<void> {
// Avoid race conditions
const stack = this.stack;
this.stack = [];
if (!stack.length) return;
const request = stack.map((s) => s.request);
const raw = await http("POST", this.url, this.headers, request);
// Requests with a single entry return as an object
const arr = Array.isArray(raw) ? raw : [raw];
arr.forEach((el) => {
const req = stack.find((s) => s.request.id === el.id);
if (!req) return;
const { reject, resolve } = req;
const response = parseJsonRpcResponse(el);
if (isJsonRpcErrorResponse(response)) {
reject(new Error(JSON.stringify(response.error)));
} else {
resolve(response);
}
});
}
}