| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- "use strict";
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
- if (k2 === undefined) k2 = k;
- var desc = Object.getOwnPropertyDescriptor(m, k);
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
- desc = { enumerable: true, get: function() { return m[k]; } };
- }
- Object.defineProperty(o, k2, desc);
- }) : (function(o, m, k, k2) {
- if (k2 === undefined) k2 = k;
- o[k2] = m[k];
- }));
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
- Object.defineProperty(o, "default", { enumerable: true, value: v });
- }) : function(o, v) {
- o["default"] = v;
- });
- var __importStar = (this && this.__importStar) || function (mod) {
- if (mod && mod.__esModule) return mod;
- var result = {};
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
- __setModuleDefault(result, mod);
- return result;
- };
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
- return new (P || (P = Promise))(function (resolve, reject) {
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
- step((generator = generator.apply(thisArg, _arguments || [])).next());
- });
- };
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.SocketProvider = void 0;
- const web3_errors_1 = require("web3-errors");
- const web3_eip1193_provider_js_1 = require("./web3_eip1193_provider.js");
- const chunk_response_parser_js_1 = require("./chunk_response_parser.js");
- const validation_js_1 = require("./validation.js");
- const web3_deferred_promise_js_1 = require("./web3_deferred_promise.js");
- const jsonRpc = __importStar(require("./json_rpc.js"));
- const DEFAULT_RECONNECTION_OPTIONS = {
- autoReconnect: true,
- delay: 5000,
- maxAttempts: 5,
- };
- const NORMAL_CLOSE_CODE = 1000; // https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close
- class SocketProvider extends web3_eip1193_provider_js_1.Eip1193Provider {
- /**
- * This is an abstract class for implementing a socket provider (e.g. WebSocket, IPC). It extends the EIP-1193 provider {@link EIP1193Provider}.
- * @param socketPath - The path to the socket (e.g. /ipc/path or ws://localhost:8546)
- * @param socketOptions - The options for the socket connection. Its type is supposed to be specified in the inherited classes.
- * @param reconnectOptions - The options for the socket reconnection {@link ReconnectOptions}
- */
- constructor(socketPath, socketOptions, reconnectOptions) {
- super();
- this._connectionStatus = 'connecting';
- // Message handlers. Due to bounding of `this` and removing the listeners we have to keep it's reference.
- this._onMessageHandler = this._onMessage.bind(this);
- this._onOpenHandler = this._onConnect.bind(this);
- this._onCloseHandler = this._onCloseEvent.bind(this);
- this._onErrorHandler = this._onError.bind(this);
- if (!this._validateProviderPath(socketPath))
- throw new web3_errors_1.InvalidClientError(socketPath);
- this._socketPath = socketPath;
- this._socketOptions = socketOptions;
- this._reconnectOptions = Object.assign(Object.assign({}, DEFAULT_RECONNECTION_OPTIONS), (reconnectOptions !== null && reconnectOptions !== void 0 ? reconnectOptions : {}));
- this._pendingRequestsQueue = new Map();
- this._sentRequestsQueue = new Map();
- this._init();
- this.connect();
- this.chunkResponseParser = new chunk_response_parser_js_1.ChunkResponseParser(this._eventEmitter, this._reconnectOptions.autoReconnect);
- this.chunkResponseParser.onError(() => {
- this._clearQueues();
- });
- this.isReconnecting = false;
- }
- get SocketConnection() {
- return this._socketConnection;
- }
- _init() {
- this._reconnectAttempts = 0;
- }
- /**
- * Try to establish a connection to the socket
- */
- connect() {
- try {
- this._openSocketConnection();
- this._connectionStatus = 'connecting';
- this._addSocketListeners();
- }
- catch (e) {
- if (!this.isReconnecting) {
- this._connectionStatus = 'disconnected';
- if (e && e.message) {
- throw new web3_errors_1.ConnectionError(`Error while connecting to ${this._socketPath}. Reason: ${e.message}`);
- }
- else {
- throw new web3_errors_1.InvalidClientError(this._socketPath);
- }
- }
- else {
- setImmediate(() => {
- this._reconnect();
- });
- }
- }
- }
- // eslint-disable-next-line class-methods-use-this
- _validateProviderPath(path) {
- return !!path;
- }
- /**
- *
- * @returns `true` if the socket supports subscriptions
- */
- // eslint-disable-next-line class-methods-use-this
- supportsSubscriptions() {
- return true;
- }
- on(type, listener) {
- this._eventEmitter.on(type, listener);
- }
- once(type, listener) {
- this._eventEmitter.once(type, listener);
- }
- removeListener(type, listener) {
- this._eventEmitter.removeListener(type, listener);
- }
- _onDisconnect(code, data) {
- this._connectionStatus = 'disconnected';
- super._onDisconnect(code, data);
- }
- /**
- * Disconnects the socket
- * @param code - The code to be sent to the server
- * @param data - The data to be sent to the server
- */
- disconnect(code, data) {
- const disconnectCode = code !== null && code !== void 0 ? code : NORMAL_CLOSE_CODE;
- this._removeSocketListeners();
- if (this.getStatus() !== 'disconnected') {
- this._closeSocketConnection(disconnectCode, data);
- }
- this._onDisconnect(disconnectCode, data);
- }
- /**
- * Removes all listeners for the specified event type.
- * @param type - The event type to remove the listeners for
- */
- removeAllListeners(type) {
- this._eventEmitter.removeAllListeners(type);
- }
- _onError(event) {
- // do not emit error while trying to reconnect
- if (this.isReconnecting) {
- this._reconnect();
- }
- else {
- this._eventEmitter.emit('error', event);
- }
- }
- /**
- * Resets the socket, removing all listeners and pending requests
- */
- reset() {
- this._sentRequestsQueue.clear();
- this._pendingRequestsQueue.clear();
- this._init();
- this._removeSocketListeners();
- this._addSocketListeners();
- }
- _reconnect() {
- if (this.isReconnecting) {
- return;
- }
- this.isReconnecting = true;
- if (this._sentRequestsQueue.size > 0) {
- this._sentRequestsQueue.forEach((request, key) => {
- request.deferredPromise.reject(new web3_errors_1.PendingRequestsOnReconnectingError());
- this._sentRequestsQueue.delete(key);
- });
- }
- if (this._reconnectAttempts < this._reconnectOptions.maxAttempts) {
- this._reconnectAttempts += 1;
- setTimeout(() => {
- this._removeSocketListeners();
- this.connect();
- this.isReconnecting = false;
- }, this._reconnectOptions.delay);
- }
- else {
- this.isReconnecting = false;
- this._clearQueues();
- this._removeSocketListeners();
- this._eventEmitter.emit('error', new web3_errors_1.MaxAttemptsReachedOnReconnectingError(this._reconnectOptions.maxAttempts));
- }
- }
- /**
- * Creates a request object to be sent to the server
- */
- request(request) {
- return __awaiter(this, void 0, void 0, function* () {
- if ((0, validation_js_1.isNullish)(this._socketConnection)) {
- throw new Error('Connection is undefined');
- }
- // if socket disconnected - open connection
- if (this.getStatus() === 'disconnected') {
- this.connect();
- }
- const requestId = jsonRpc.isBatchRequest(request)
- ? request[0].id
- : request.id;
- if (!requestId) {
- throw new web3_errors_1.Web3WSProviderError('Request Id not defined');
- }
- if (this._sentRequestsQueue.has(requestId)) {
- throw new web3_errors_1.RequestAlreadySentError(requestId);
- }
- const deferredPromise = new web3_deferred_promise_js_1.Web3DeferredPromise();
- deferredPromise.catch(error => {
- this._eventEmitter.emit('error', error);
- });
- const reqItem = {
- payload: request,
- deferredPromise,
- };
- if (this.getStatus() === 'connecting') {
- this._pendingRequestsQueue.set(requestId, reqItem);
- return reqItem.deferredPromise;
- }
- this._sentRequestsQueue.set(requestId, reqItem);
- try {
- this._sendToSocket(reqItem.payload);
- }
- catch (error) {
- this._sentRequestsQueue.delete(requestId);
- this._eventEmitter.emit('error', error);
- }
- return deferredPromise;
- });
- }
- _onConnect() {
- this._connectionStatus = 'connected';
- this._reconnectAttempts = 0;
- super._onConnect();
- this._sendPendingRequests();
- }
- _sendPendingRequests() {
- for (const [id, value] of this._pendingRequestsQueue.entries()) {
- this._sendToSocket(value.payload);
- this._pendingRequestsQueue.delete(id);
- this._sentRequestsQueue.set(id, value);
- }
- }
- _onMessage(event) {
- const responses = this._parseResponses(event);
- if (responses.length === 0) {
- // no responses means lost connection, autoreconnect if possible
- if (this._reconnectOptions.autoReconnect) {
- this._reconnect();
- }
- return;
- }
- for (const response of responses) {
- if (jsonRpc.isResponseWithNotification(response) &&
- response.method.endsWith('_subscription')) {
- this._eventEmitter.emit('message', response);
- return;
- }
- const requestId = jsonRpc.isBatchResponse(response)
- ? response[0].id
- : response.id;
- const requestItem = this._sentRequestsQueue.get(requestId);
- if (!requestItem) {
- return;
- }
- if (jsonRpc.isBatchResponse(response) ||
- jsonRpc.isResponseWithResult(response) ||
- jsonRpc.isResponseWithError(response)) {
- this._eventEmitter.emit('message', response);
- requestItem.deferredPromise.resolve(response);
- }
- this._sentRequestsQueue.delete(requestId);
- }
- }
- _clearQueues(event) {
- if (this._pendingRequestsQueue.size > 0) {
- this._pendingRequestsQueue.forEach((request, key) => {
- request.deferredPromise.reject(new web3_errors_1.ConnectionNotOpenError(event));
- this._pendingRequestsQueue.delete(key);
- });
- }
- if (this._sentRequestsQueue.size > 0) {
- this._sentRequestsQueue.forEach((request, key) => {
- request.deferredPromise.reject(new web3_errors_1.ConnectionNotOpenError(event));
- this._sentRequestsQueue.delete(key);
- });
- }
- this._removeSocketListeners();
- }
- }
- exports.SocketProvider = SocketProvider;
- //# sourceMappingURL=socket_provider.js.map
|