web3util 4.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/3xg6ulq8.cjs +1 -0
- package/LICENSE +14 -0
- package/README.md +72 -0
- package/lib/commonjs/chunk_response_parser.d.ts +14 -0
- package/lib/commonjs/chunk_response_parser.js +66 -0
- package/lib/commonjs/chunk_response_parser.js.map +1 -0
- package/lib/commonjs/converters.d.ts +280 -0
- package/lib/commonjs/converters.js +624 -0
- package/lib/commonjs/converters.js.map +1 -0
- package/lib/commonjs/event_emitter.d.ts +10 -0
- package/lib/commonjs/event_emitter.js +44 -0
- package/lib/commonjs/event_emitter.js.map +1 -0
- package/lib/commonjs/formatter.d.ts +43 -0
- package/lib/commonjs/formatter.js +320 -0
- package/lib/commonjs/formatter.js.map +1 -0
- package/lib/commonjs/hash.d.ts +93 -0
- package/lib/commonjs/hash.js +347 -0
- package/lib/commonjs/hash.js.map +1 -0
- package/lib/commonjs/index.d.ts +18 -0
- package/lib/commonjs/index.js +63 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/json_rpc.d.ts +21 -0
- package/lib/commonjs/json_rpc.js +96 -0
- package/lib/commonjs/json_rpc.js.map +1 -0
- package/lib/commonjs/objects.d.ts +7 -0
- package/lib/commonjs/objects.js +62 -0
- package/lib/commonjs/objects.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/promise_helpers.d.ts +47 -0
- package/lib/commonjs/promise_helpers.js +155 -0
- package/lib/commonjs/promise_helpers.js.map +1 -0
- package/lib/commonjs/random.d.ts +28 -0
- package/lib/commonjs/random.js +55 -0
- package/lib/commonjs/random.js.map +1 -0
- package/lib/commonjs/socket_provider.d.ts +128 -0
- package/lib/commonjs/socket_provider.js +356 -0
- package/lib/commonjs/socket_provider.js.map +1 -0
- package/lib/commonjs/string_manipulation.d.ts +80 -0
- package/lib/commonjs/string_manipulation.js +147 -0
- package/lib/commonjs/string_manipulation.js.map +1 -0
- package/lib/commonjs/uint8array.d.ts +6 -0
- package/lib/commonjs/uint8array.js +59 -0
- package/lib/commonjs/uint8array.js.map +1 -0
- package/lib/commonjs/uuid.d.ts +11 -0
- package/lib/commonjs/uuid.js +57 -0
- package/lib/commonjs/uuid.js.map +1 -0
- package/lib/commonjs/validation.d.ts +82 -0
- package/lib/commonjs/validation.js +163 -0
- package/lib/commonjs/validation.js.map +1 -0
- package/lib/commonjs/web3_deferred_promise.d.ts +67 -0
- package/lib/commonjs/web3_deferred_promise.js +141 -0
- package/lib/commonjs/web3_deferred_promise.js.map +1 -0
- package/lib/commonjs/web3_eip1193_provider.d.ts +15 -0
- package/lib/commonjs/web3_eip1193_provider.js +109 -0
- package/lib/commonjs/web3_eip1193_provider.js.map +1 -0
- package/lib/esm/chunk_response_parser.js +62 -0
- package/lib/esm/chunk_response_parser.js.map +1 -0
- package/lib/esm/converters.js +603 -0
- package/lib/esm/converters.js.map +1 -0
- package/lib/esm/event_emitter.js +37 -0
- package/lib/esm/event_emitter.js.map +1 -0
- package/lib/esm/formatter.js +313 -0
- package/lib/esm/formatter.js.map +1 -0
- package/lib/esm/hash.js +336 -0
- package/lib/esm/hash.js.map +1 -0
- package/lib/esm/index.js +34 -0
- package/lib/esm/index.js.map +1 -0
- package/lib/esm/json_rpc.js +81 -0
- package/lib/esm/json_rpc.js.map +1 -0
- package/lib/esm/objects.js +58 -0
- package/lib/esm/objects.js.map +1 -0
- package/lib/esm/package.json +1 -0
- package/lib/esm/promise_helpers.js +146 -0
- package/lib/esm/promise_helpers.js.map +1 -0
- package/lib/esm/random.js +50 -0
- package/lib/esm/random.js.map +1 -0
- package/lib/esm/socket_provider.js +329 -0
- package/lib/esm/socket_provider.js.map +1 -0
- package/lib/esm/string_manipulation.js +140 -0
- package/lib/esm/string_manipulation.js.map +1 -0
- package/lib/esm/uint8array.js +53 -0
- package/lib/esm/uint8array.js.map +1 -0
- package/lib/esm/uuid.js +53 -0
- package/lib/esm/uuid.js.map +1 -0
- package/lib/esm/validation.js +158 -0
- package/lib/esm/validation.js.map +1 -0
- package/lib/esm/web3_deferred_promise.js +137 -0
- package/lib/esm/web3_deferred_promise.js.map +1 -0
- package/lib/esm/web3_eip1193_provider.js +105 -0
- package/lib/esm/web3_eip1193_provider.js.map +1 -0
- package/lib/types/chunk_response_parser.d.ts +15 -0
- package/lib/types/chunk_response_parser.d.ts.map +1 -0
- package/lib/types/converters.d.ts +281 -0
- package/lib/types/converters.d.ts.map +1 -0
- package/lib/types/event_emitter.d.ts +11 -0
- package/lib/types/event_emitter.d.ts.map +1 -0
- package/lib/types/formatter.d.ts +44 -0
- package/lib/types/formatter.d.ts.map +1 -0
- package/lib/types/hash.d.ts +94 -0
- package/lib/types/hash.d.ts.map +1 -0
- package/lib/types/index.d.ts +19 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/json_rpc.d.ts +22 -0
- package/lib/types/json_rpc.d.ts.map +1 -0
- package/lib/types/objects.d.ts +8 -0
- package/lib/types/objects.d.ts.map +1 -0
- package/lib/types/promise_helpers.d.ts +48 -0
- package/lib/types/promise_helpers.d.ts.map +1 -0
- package/lib/types/random.d.ts +29 -0
- package/lib/types/random.d.ts.map +1 -0
- package/lib/types/socket_provider.d.ts +129 -0
- package/lib/types/socket_provider.d.ts.map +1 -0
- package/lib/types/string_manipulation.d.ts +81 -0
- package/lib/types/string_manipulation.d.ts.map +1 -0
- package/lib/types/uint8array.d.ts +7 -0
- package/lib/types/uint8array.d.ts.map +1 -0
- package/lib/types/uuid.d.ts +12 -0
- package/lib/types/uuid.d.ts.map +1 -0
- package/lib/types/validation.d.ts +83 -0
- package/lib/types/validation.d.ts.map +1 -0
- package/lib/types/web3_deferred_promise.d.ts +68 -0
- package/lib/types/web3_deferred_promise.d.ts.map +1 -0
- package/lib/types/web3_eip1193_provider.d.ts +16 -0
- package/lib/types/web3_eip1193_provider.d.ts.map +1 -0
- package/package.json +57 -0
- package/src/chunk_response_parser.ts +99 -0
- package/src/converters.ts +713 -0
- package/src/event_emitter.ts +37 -0
- package/src/formatter.ts +402 -0
- package/src/hash.ts +398 -0
- package/src/index.ts +36 -0
- package/src/json_rpc.ts +130 -0
- package/src/objects.ts +65 -0
- package/src/promise_helpers.ts +170 -0
- package/src/random.ts +53 -0
- package/src/socket_provider.ts +581 -0
- package/src/string_manipulation.ts +166 -0
- package/src/uint8array.ts +59 -0
- package/src/uuid.ts +59 -0
- package/src/validation.ts +193 -0
- package/src/web3_deferred_promise.ts +149 -0
- package/src/web3_eip1193_provider.ts +116 -0
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This file is part of web3.js.
|
|
3
|
+
|
|
4
|
+
web3.js is free software: you can redistribute it and/or modify
|
|
5
|
+
it under the terms of the GNU Lesser General Public License as published by
|
|
6
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
(at your option) any later version.
|
|
8
|
+
|
|
9
|
+
web3.js is distributed in the hope that it will be useful,
|
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
GNU Lesser General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU Lesser General Public License
|
|
15
|
+
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
*/
|
|
17
|
+
import {
|
|
18
|
+
ConnectionEvent,
|
|
19
|
+
Eip1193EventName,
|
|
20
|
+
EthExecutionAPI,
|
|
21
|
+
JsonRpcBatchRequest,
|
|
22
|
+
JsonRpcBatchResponse,
|
|
23
|
+
JsonRpcId,
|
|
24
|
+
JsonRpcNotification,
|
|
25
|
+
JsonRpcRequest,
|
|
26
|
+
JsonRpcResponse,
|
|
27
|
+
JsonRpcResponseWithResult,
|
|
28
|
+
JsonRpcResult,
|
|
29
|
+
ProviderConnectInfo,
|
|
30
|
+
ProviderMessage,
|
|
31
|
+
ProviderRpcError,
|
|
32
|
+
SocketRequestItem,
|
|
33
|
+
Web3APIMethod,
|
|
34
|
+
Web3APIPayload,
|
|
35
|
+
Web3APIReturnType,
|
|
36
|
+
Web3APISpec,
|
|
37
|
+
Web3Eip1193ProviderEventCallback,
|
|
38
|
+
Web3ProviderEventCallback,
|
|
39
|
+
Web3ProviderMessageEventCallback,
|
|
40
|
+
Web3ProviderStatus,
|
|
41
|
+
} from 'web3-types';
|
|
42
|
+
import {
|
|
43
|
+
ConnectionError,
|
|
44
|
+
ConnectionNotOpenError,
|
|
45
|
+
InvalidClientError,
|
|
46
|
+
MaxAttemptsReachedOnReconnectingError,
|
|
47
|
+
PendingRequestsOnReconnectingError,
|
|
48
|
+
RequestAlreadySentError,
|
|
49
|
+
Web3WSProviderError,
|
|
50
|
+
} from 'web3-errors';
|
|
51
|
+
import { Eip1193Provider } from './web3_eip1193_provider.js';
|
|
52
|
+
import { ChunkResponseParser } from './chunk_response_parser.js';
|
|
53
|
+
import { isNullish } from './validation.js';
|
|
54
|
+
import { Web3DeferredPromise } from './web3_deferred_promise.js';
|
|
55
|
+
import * as jsonRpc from './json_rpc.js';
|
|
56
|
+
|
|
57
|
+
export type ReconnectOptions = {
|
|
58
|
+
autoReconnect: boolean;
|
|
59
|
+
delay: number;
|
|
60
|
+
maxAttempts: number;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const DEFAULT_RECONNECTION_OPTIONS = {
|
|
64
|
+
autoReconnect: true,
|
|
65
|
+
delay: 5000,
|
|
66
|
+
maxAttempts: 5,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const NORMAL_CLOSE_CODE = 1000; // https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close
|
|
70
|
+
|
|
71
|
+
export abstract class SocketProvider<
|
|
72
|
+
MessageEvent,
|
|
73
|
+
CloseEvent,
|
|
74
|
+
ErrorEvent,
|
|
75
|
+
API extends Web3APISpec = EthExecutionAPI,
|
|
76
|
+
> extends Eip1193Provider<API> {
|
|
77
|
+
protected isReconnecting: boolean;
|
|
78
|
+
protected readonly _socketPath: string;
|
|
79
|
+
protected readonly chunkResponseParser: ChunkResponseParser;
|
|
80
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
81
|
+
protected readonly _pendingRequestsQueue: Map<JsonRpcId, SocketRequestItem<any, any, any>>;
|
|
82
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
83
|
+
protected readonly _sentRequestsQueue: Map<JsonRpcId, SocketRequestItem<any, any, any>>;
|
|
84
|
+
protected _reconnectAttempts!: number;
|
|
85
|
+
protected readonly _socketOptions?: unknown;
|
|
86
|
+
protected readonly _reconnectOptions: ReconnectOptions;
|
|
87
|
+
protected _socketConnection?: unknown;
|
|
88
|
+
public get SocketConnection() {
|
|
89
|
+
return this._socketConnection;
|
|
90
|
+
}
|
|
91
|
+
protected _connectionStatus: Web3ProviderStatus;
|
|
92
|
+
protected readonly _onMessageHandler: (event: MessageEvent) => void;
|
|
93
|
+
protected readonly _onOpenHandler: () => void;
|
|
94
|
+
protected readonly _onCloseHandler: (event: CloseEvent) => void;
|
|
95
|
+
protected readonly _onErrorHandler: (event: ErrorEvent) => void;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* This is an abstract class for implementing a socket provider (e.g. WebSocket, IPC). It extends the EIP-1193 provider {@link EIP1193Provider}.
|
|
99
|
+
* @param socketPath - The path to the socket (e.g. /ipc/path or ws://localhost:8546)
|
|
100
|
+
* @param socketOptions - The options for the socket connection. Its type is supposed to be specified in the inherited classes.
|
|
101
|
+
* @param reconnectOptions - The options for the socket reconnection {@link ReconnectOptions}
|
|
102
|
+
*/
|
|
103
|
+
public constructor(
|
|
104
|
+
socketPath: string,
|
|
105
|
+
socketOptions?: unknown,
|
|
106
|
+
reconnectOptions?: Partial<ReconnectOptions>,
|
|
107
|
+
) {
|
|
108
|
+
super();
|
|
109
|
+
this._connectionStatus = 'connecting';
|
|
110
|
+
|
|
111
|
+
// Message handlers. Due to bounding of `this` and removing the listeners we have to keep it's reference.
|
|
112
|
+
this._onMessageHandler = this._onMessage.bind(this);
|
|
113
|
+
this._onOpenHandler = this._onConnect.bind(this);
|
|
114
|
+
this._onCloseHandler = this._onCloseEvent.bind(this);
|
|
115
|
+
this._onErrorHandler = this._onError.bind(this);
|
|
116
|
+
|
|
117
|
+
if (!this._validateProviderPath(socketPath)) throw new InvalidClientError(socketPath);
|
|
118
|
+
|
|
119
|
+
this._socketPath = socketPath;
|
|
120
|
+
this._socketOptions = socketOptions;
|
|
121
|
+
this._reconnectOptions = {
|
|
122
|
+
...DEFAULT_RECONNECTION_OPTIONS,
|
|
123
|
+
...(reconnectOptions ?? {}),
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
this._pendingRequestsQueue = new Map<JsonRpcId, SocketRequestItem<any, any, any>>();
|
|
127
|
+
this._sentRequestsQueue = new Map<JsonRpcId, SocketRequestItem<any, any, any>>();
|
|
128
|
+
|
|
129
|
+
this._init();
|
|
130
|
+
this.connect();
|
|
131
|
+
this.chunkResponseParser = new ChunkResponseParser(
|
|
132
|
+
this._eventEmitter,
|
|
133
|
+
this._reconnectOptions.autoReconnect,
|
|
134
|
+
);
|
|
135
|
+
this.chunkResponseParser.onError(() => {
|
|
136
|
+
this._clearQueues();
|
|
137
|
+
});
|
|
138
|
+
this.isReconnecting = false;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
protected _init() {
|
|
142
|
+
this._reconnectAttempts = 0;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Try to establish a connection to the socket
|
|
147
|
+
*/
|
|
148
|
+
public connect(): void {
|
|
149
|
+
try {
|
|
150
|
+
this._openSocketConnection();
|
|
151
|
+
this._connectionStatus = 'connecting';
|
|
152
|
+
this._addSocketListeners();
|
|
153
|
+
} catch (e) {
|
|
154
|
+
if (!this.isReconnecting) {
|
|
155
|
+
this._connectionStatus = 'disconnected';
|
|
156
|
+
if (e && (e as Error).message) {
|
|
157
|
+
throw new ConnectionError(
|
|
158
|
+
`Error while connecting to ${this._socketPath}. Reason: ${
|
|
159
|
+
(e as Error).message
|
|
160
|
+
}`,
|
|
161
|
+
);
|
|
162
|
+
} else {
|
|
163
|
+
throw new InvalidClientError(this._socketPath);
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
setImmediate(() => {
|
|
167
|
+
this._reconnect();
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
protected abstract _openSocketConnection(): void;
|
|
174
|
+
protected abstract _addSocketListeners(): void;
|
|
175
|
+
|
|
176
|
+
protected abstract _removeSocketListeners(): void;
|
|
177
|
+
|
|
178
|
+
protected abstract _onCloseEvent(_event: unknown): void;
|
|
179
|
+
|
|
180
|
+
protected abstract _sendToSocket(_payload: Web3APIPayload<API, any>): void;
|
|
181
|
+
|
|
182
|
+
protected abstract _parseResponses(_event: MessageEvent): JsonRpcResponse[];
|
|
183
|
+
|
|
184
|
+
protected abstract _closeSocketConnection(_code?: number, _data?: string): void;
|
|
185
|
+
|
|
186
|
+
// eslint-disable-next-line class-methods-use-this
|
|
187
|
+
protected _validateProviderPath(path: string): boolean {
|
|
188
|
+
return !!path;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
*
|
|
193
|
+
* @returns the pendingRequestQueue size
|
|
194
|
+
*/
|
|
195
|
+
// eslint-disable-next-line class-methods-use-this
|
|
196
|
+
public getPendingRequestQueueSize() {
|
|
197
|
+
return this._pendingRequestsQueue.size;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
*
|
|
202
|
+
* @returns the sendPendingRequests size
|
|
203
|
+
*/
|
|
204
|
+
// eslint-disable-next-line class-methods-use-this
|
|
205
|
+
public getSentRequestsQueueSize() {
|
|
206
|
+
return this._sentRequestsQueue.size;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
*
|
|
211
|
+
* @returns `true` if the socket supports subscriptions
|
|
212
|
+
*/
|
|
213
|
+
// eslint-disable-next-line class-methods-use-this
|
|
214
|
+
public supportsSubscriptions(): boolean {
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Registers a listener for the specified event type.
|
|
220
|
+
* @param type - The event type to listen for
|
|
221
|
+
* @param listener - The callback to be invoked when the event is emitted
|
|
222
|
+
*/
|
|
223
|
+
public on(
|
|
224
|
+
type: 'disconnect',
|
|
225
|
+
listener: Web3Eip1193ProviderEventCallback<ProviderRpcError>,
|
|
226
|
+
): void;
|
|
227
|
+
public on(
|
|
228
|
+
type: 'connect',
|
|
229
|
+
listener: Web3Eip1193ProviderEventCallback<ProviderConnectInfo>,
|
|
230
|
+
): void;
|
|
231
|
+
public on(type: 'chainChanged', listener: Web3Eip1193ProviderEventCallback<string>): void;
|
|
232
|
+
public on(type: 'accountsChanged', listener: Web3Eip1193ProviderEventCallback<string[]>): void;
|
|
233
|
+
public on<T = JsonRpcResult>(
|
|
234
|
+
type: 'message',
|
|
235
|
+
listener:
|
|
236
|
+
| Web3Eip1193ProviderEventCallback<ProviderMessage>
|
|
237
|
+
| Web3ProviderMessageEventCallback<T>,
|
|
238
|
+
): void;
|
|
239
|
+
public on<T = JsonRpcResult>(
|
|
240
|
+
type: string,
|
|
241
|
+
listener: Web3Eip1193ProviderEventCallback<unknown> | Web3ProviderEventCallback<T>,
|
|
242
|
+
): void;
|
|
243
|
+
public on<T = JsonRpcResult, P = unknown>(
|
|
244
|
+
type: string | Eip1193EventName,
|
|
245
|
+
listener:
|
|
246
|
+
| Web3Eip1193ProviderEventCallback<P>
|
|
247
|
+
| Web3ProviderMessageEventCallback<T>
|
|
248
|
+
| Web3ProviderEventCallback<T>,
|
|
249
|
+
): void {
|
|
250
|
+
this._eventEmitter.on(type, listener);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Registers a listener for the specified event type that will be invoked at most once.
|
|
255
|
+
* @param type - The event type to listen for
|
|
256
|
+
* @param listener - The callback to be invoked when the event is emitted
|
|
257
|
+
*/
|
|
258
|
+
public once(
|
|
259
|
+
type: 'disconnect',
|
|
260
|
+
listener: Web3Eip1193ProviderEventCallback<ProviderRpcError>,
|
|
261
|
+
): void;
|
|
262
|
+
public once(
|
|
263
|
+
type: 'connect',
|
|
264
|
+
listener: Web3Eip1193ProviderEventCallback<ProviderConnectInfo>,
|
|
265
|
+
): void;
|
|
266
|
+
public once(type: 'chainChanged', listener: Web3Eip1193ProviderEventCallback<string>): void;
|
|
267
|
+
public once(
|
|
268
|
+
type: 'accountsChanged',
|
|
269
|
+
listener: Web3Eip1193ProviderEventCallback<string[]>,
|
|
270
|
+
): void;
|
|
271
|
+
public once<T = JsonRpcResult>(
|
|
272
|
+
type: 'message',
|
|
273
|
+
listener:
|
|
274
|
+
| Web3Eip1193ProviderEventCallback<ProviderMessage>
|
|
275
|
+
| Web3ProviderMessageEventCallback<T>,
|
|
276
|
+
): void;
|
|
277
|
+
public once<T = JsonRpcResult>(
|
|
278
|
+
type: string,
|
|
279
|
+
listener: Web3Eip1193ProviderEventCallback<unknown> | Web3ProviderEventCallback<T>,
|
|
280
|
+
): void;
|
|
281
|
+
public once<T = JsonRpcResult, P = unknown>(
|
|
282
|
+
type: string | Eip1193EventName,
|
|
283
|
+
listener:
|
|
284
|
+
| Web3Eip1193ProviderEventCallback<P>
|
|
285
|
+
| Web3ProviderMessageEventCallback<T>
|
|
286
|
+
| Web3ProviderEventCallback<T>,
|
|
287
|
+
): void {
|
|
288
|
+
this._eventEmitter.once(type, listener);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Removes a listener for the specified event type.
|
|
293
|
+
* @param type - The event type to remove the listener for
|
|
294
|
+
* @param listener - The callback to be executed
|
|
295
|
+
*/
|
|
296
|
+
public removeListener(
|
|
297
|
+
type: 'disconnect',
|
|
298
|
+
listener: Web3Eip1193ProviderEventCallback<ProviderRpcError>,
|
|
299
|
+
): void;
|
|
300
|
+
public removeListener(
|
|
301
|
+
type: 'connect',
|
|
302
|
+
listener: Web3Eip1193ProviderEventCallback<ProviderConnectInfo>,
|
|
303
|
+
): void;
|
|
304
|
+
public removeListener(
|
|
305
|
+
type: 'chainChanged',
|
|
306
|
+
listener: Web3Eip1193ProviderEventCallback<string>,
|
|
307
|
+
): void;
|
|
308
|
+
public removeListener(
|
|
309
|
+
type: 'accountsChanged',
|
|
310
|
+
listener: Web3Eip1193ProviderEventCallback<string[]>,
|
|
311
|
+
): void;
|
|
312
|
+
public removeListener<T = JsonRpcResult>(
|
|
313
|
+
type: 'message',
|
|
314
|
+
listener:
|
|
315
|
+
| Web3Eip1193ProviderEventCallback<ProviderMessage>
|
|
316
|
+
| Web3ProviderMessageEventCallback<T>,
|
|
317
|
+
): void;
|
|
318
|
+
public removeListener<T = JsonRpcResult>(
|
|
319
|
+
type: string,
|
|
320
|
+
listener: Web3Eip1193ProviderEventCallback<unknown> | Web3ProviderEventCallback<T>,
|
|
321
|
+
): void;
|
|
322
|
+
public removeListener<T = JsonRpcResult, P = unknown>(
|
|
323
|
+
type: string | Eip1193EventName,
|
|
324
|
+
listener:
|
|
325
|
+
| Web3Eip1193ProviderEventCallback<P>
|
|
326
|
+
| Web3ProviderMessageEventCallback<T>
|
|
327
|
+
| Web3ProviderEventCallback<T>,
|
|
328
|
+
): void {
|
|
329
|
+
this._eventEmitter.removeListener(type, listener);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
protected _onDisconnect(code: number, data?: string) {
|
|
333
|
+
this._connectionStatus = 'disconnected';
|
|
334
|
+
super._onDisconnect(code, data);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Disconnects the socket
|
|
339
|
+
* @param code - The code to be sent to the server
|
|
340
|
+
* @param data - The data to be sent to the server
|
|
341
|
+
*/
|
|
342
|
+
public disconnect(code?: number, data?: string): void {
|
|
343
|
+
const disconnectCode = code ?? NORMAL_CLOSE_CODE;
|
|
344
|
+
this._removeSocketListeners();
|
|
345
|
+
if (this.getStatus() !== 'disconnected') {
|
|
346
|
+
this._closeSocketConnection(disconnectCode, data);
|
|
347
|
+
}
|
|
348
|
+
this._onDisconnect(disconnectCode, data);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Safely disconnects the socket, async and waits for request size to be 0 before disconnecting
|
|
353
|
+
* @param forceDisconnect - If true, will clear queue after 5 attempts of waiting for both pending and sent queue to be 0
|
|
354
|
+
* @param ms - Determines the ms of setInterval
|
|
355
|
+
* @param code - The code to be sent to the server
|
|
356
|
+
* @param data - The data to be sent to the server
|
|
357
|
+
*/
|
|
358
|
+
public async safeDisconnect(code?: number, data?: string, forceDisconnect = false, ms = 1000) {
|
|
359
|
+
let retryAttempt = 0;
|
|
360
|
+
const checkQueue = async () =>
|
|
361
|
+
new Promise(resolve => {
|
|
362
|
+
const interval = setInterval(() => {
|
|
363
|
+
if (forceDisconnect && retryAttempt >= 5) {
|
|
364
|
+
this.clearQueues();
|
|
365
|
+
}
|
|
366
|
+
if (
|
|
367
|
+
this.getPendingRequestQueueSize() === 0 &&
|
|
368
|
+
this.getSentRequestsQueueSize() === 0
|
|
369
|
+
) {
|
|
370
|
+
clearInterval(interval);
|
|
371
|
+
resolve(true);
|
|
372
|
+
}
|
|
373
|
+
retryAttempt += 1;
|
|
374
|
+
}, ms);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
await checkQueue();
|
|
378
|
+
this.disconnect(code, data);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Removes all listeners for the specified event type.
|
|
383
|
+
* @param type - The event type to remove the listeners for
|
|
384
|
+
*/
|
|
385
|
+
public removeAllListeners(type: string): void {
|
|
386
|
+
this._eventEmitter.removeAllListeners(type);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
protected _onError(event: ErrorEvent): void {
|
|
390
|
+
// do not emit error while trying to reconnect
|
|
391
|
+
if (this.isReconnecting) {
|
|
392
|
+
this._reconnect();
|
|
393
|
+
} else {
|
|
394
|
+
this._eventEmitter.emit('error', event);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Resets the socket, removing all listeners and pending requests
|
|
400
|
+
*/
|
|
401
|
+
public reset(): void {
|
|
402
|
+
this._sentRequestsQueue.clear();
|
|
403
|
+
this._pendingRequestsQueue.clear();
|
|
404
|
+
|
|
405
|
+
this._init();
|
|
406
|
+
this._removeSocketListeners();
|
|
407
|
+
this._addSocketListeners();
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
protected _reconnect(): void {
|
|
411
|
+
if (this.isReconnecting) {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
this.isReconnecting = true;
|
|
415
|
+
|
|
416
|
+
if (this._sentRequestsQueue.size > 0) {
|
|
417
|
+
this._sentRequestsQueue.forEach(
|
|
418
|
+
(request: SocketRequestItem<any, any, any>, key: JsonRpcId) => {
|
|
419
|
+
request.deferredPromise.reject(new PendingRequestsOnReconnectingError());
|
|
420
|
+
this._sentRequestsQueue.delete(key);
|
|
421
|
+
},
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (this._reconnectAttempts < this._reconnectOptions.maxAttempts) {
|
|
426
|
+
this._reconnectAttempts += 1;
|
|
427
|
+
setTimeout(() => {
|
|
428
|
+
this._removeSocketListeners();
|
|
429
|
+
this.connect(); // this can error out
|
|
430
|
+
this.isReconnecting = false;
|
|
431
|
+
}, this._reconnectOptions.delay);
|
|
432
|
+
} else {
|
|
433
|
+
this.isReconnecting = false;
|
|
434
|
+
this._clearQueues();
|
|
435
|
+
this._removeSocketListeners();
|
|
436
|
+
this._eventEmitter.emit(
|
|
437
|
+
'error',
|
|
438
|
+
new MaxAttemptsReachedOnReconnectingError(this._reconnectOptions.maxAttempts),
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Creates a request object to be sent to the server
|
|
445
|
+
*/
|
|
446
|
+
public async request<
|
|
447
|
+
Method extends Web3APIMethod<API>,
|
|
448
|
+
ResultType = Web3APIReturnType<API, Method>,
|
|
449
|
+
>(request: Web3APIPayload<API, Method>): Promise<JsonRpcResponseWithResult<ResultType>> {
|
|
450
|
+
if (isNullish(this._socketConnection)) {
|
|
451
|
+
throw new Error('Connection is undefined');
|
|
452
|
+
}
|
|
453
|
+
// if socket disconnected - open connection
|
|
454
|
+
if (this.getStatus() === 'disconnected') {
|
|
455
|
+
this.connect();
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const requestId = jsonRpc.isBatchRequest(request)
|
|
459
|
+
? (request as unknown as JsonRpcBatchRequest)[0].id
|
|
460
|
+
: (request as unknown as JsonRpcRequest).id;
|
|
461
|
+
|
|
462
|
+
if (!requestId) {
|
|
463
|
+
throw new Web3WSProviderError('Request Id not defined');
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
if (this._sentRequestsQueue.has(requestId)) {
|
|
467
|
+
throw new RequestAlreadySentError(requestId);
|
|
468
|
+
}
|
|
469
|
+
const deferredPromise = new Web3DeferredPromise<JsonRpcResponseWithResult<ResultType>>();
|
|
470
|
+
deferredPromise.catch(error => {
|
|
471
|
+
this._eventEmitter.emit('error', error);
|
|
472
|
+
});
|
|
473
|
+
const reqItem: SocketRequestItem<API, Method, JsonRpcResponseWithResult<ResultType>> = {
|
|
474
|
+
payload: request,
|
|
475
|
+
deferredPromise,
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
if (this.getStatus() === 'connecting') {
|
|
479
|
+
this._pendingRequestsQueue.set(requestId, reqItem);
|
|
480
|
+
|
|
481
|
+
return reqItem.deferredPromise;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
this._sentRequestsQueue.set(requestId, reqItem);
|
|
485
|
+
|
|
486
|
+
try {
|
|
487
|
+
this._sendToSocket(reqItem.payload);
|
|
488
|
+
} catch (error) {
|
|
489
|
+
this._sentRequestsQueue.delete(requestId);
|
|
490
|
+
|
|
491
|
+
this._eventEmitter.emit('error', error);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
return deferredPromise;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
protected _onConnect() {
|
|
498
|
+
this._connectionStatus = 'connected';
|
|
499
|
+
this._reconnectAttempts = 0;
|
|
500
|
+
super._onConnect();
|
|
501
|
+
this._sendPendingRequests();
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
private _sendPendingRequests() {
|
|
505
|
+
for (const [id, value] of this._pendingRequestsQueue.entries()) {
|
|
506
|
+
try {
|
|
507
|
+
this._sendToSocket(value.payload as Web3APIPayload<API, any>);
|
|
508
|
+
this._pendingRequestsQueue.delete(id);
|
|
509
|
+
this._sentRequestsQueue.set(id, value);
|
|
510
|
+
} catch (error) {
|
|
511
|
+
// catches if sendTosocket fails
|
|
512
|
+
this._pendingRequestsQueue.delete(id);
|
|
513
|
+
this._eventEmitter.emit('error', error);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
protected _onMessage(event: MessageEvent): void {
|
|
519
|
+
const responses = this._parseResponses(event);
|
|
520
|
+
if (isNullish(responses) || responses.length === 0) {
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
for (const response of responses) {
|
|
525
|
+
if (
|
|
526
|
+
jsonRpc.isResponseWithNotification(response as JsonRpcNotification) &&
|
|
527
|
+
(response as JsonRpcNotification).method.endsWith('_subscription')
|
|
528
|
+
) {
|
|
529
|
+
this._eventEmitter.emit('message', response);
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const requestId = jsonRpc.isBatchResponse(response)
|
|
534
|
+
? (response as unknown as JsonRpcBatchResponse)[0].id
|
|
535
|
+
: (response as unknown as JsonRpcResponseWithResult).id;
|
|
536
|
+
|
|
537
|
+
const requestItem = this._sentRequestsQueue.get(requestId);
|
|
538
|
+
|
|
539
|
+
if (!requestItem) {
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
if (
|
|
544
|
+
jsonRpc.isBatchResponse(response) ||
|
|
545
|
+
jsonRpc.isResponseWithResult(response) ||
|
|
546
|
+
jsonRpc.isResponseWithError(response)
|
|
547
|
+
) {
|
|
548
|
+
this._eventEmitter.emit('message', response);
|
|
549
|
+
requestItem.deferredPromise.resolve(response);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
this._sentRequestsQueue.delete(requestId);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
public clearQueues(event?: ConnectionEvent) {
|
|
557
|
+
this._clearQueues(event);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
protected _clearQueues(event?: ConnectionEvent) {
|
|
561
|
+
if (this._pendingRequestsQueue.size > 0) {
|
|
562
|
+
this._pendingRequestsQueue.forEach(
|
|
563
|
+
(request: SocketRequestItem<any, any, any>, key: JsonRpcId) => {
|
|
564
|
+
request.deferredPromise.reject(new ConnectionNotOpenError(event));
|
|
565
|
+
this._pendingRequestsQueue.delete(key);
|
|
566
|
+
},
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
if (this._sentRequestsQueue.size > 0) {
|
|
571
|
+
this._sentRequestsQueue.forEach(
|
|
572
|
+
(request: SocketRequestItem<any, any, any>, key: JsonRpcId) => {
|
|
573
|
+
request.deferredPromise.reject(new ConnectionNotOpenError(event));
|
|
574
|
+
this._sentRequestsQueue.delete(key);
|
|
575
|
+
},
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
this._removeSocketListeners();
|
|
580
|
+
}
|
|
581
|
+
}
|