UNPKG

opnet

Version:

The perfect library for building Bitcoin-based applications.

112 lines (94 loc) 3.62 kB
import { Network } from '@btc-vision/bitcoin'; import Agent from 'undici/types/agent.js'; import { Response } from 'undici/types/fetch'; import getFetcher from '../fetch/fetch.js'; import { Fetcher } from '../fetch/fetcher-type.js'; import { AbstractRpcProvider } from './AbstractRpcProvider.js'; import { JsonRpcPayload } from './interfaces/JSONRpc.js'; import { JsonRpcCallResult, JsonRpcError, JsonRpcResult } from './interfaces/JSONRpcResult.js'; /** * @description This class is used to provide a JSON RPC provider. * @class JSONRpcProvider * @category Providers */ export class JSONRpcProvider extends AbstractRpcProvider { public readonly url: string; constructor( url: string, network: Network, private readonly timeout: number = 20_000, private readonly fetcherConfigurations: Agent.Options = { keepAliveTimeout: 30_000, // how long sockets stay open keepAliveTimeoutThreshold: 30_000, // threshold before closing keep-alive sockets connections: 128, // max connections per server pipelining: 2, // max pipelining per server }, ) { super(network); this.url = this.providerUrl(url); } private _fetcher: Fetcher | undefined; private get fetcher(): Fetcher { if (!this._fetcher) { this._fetcher = getFetcher(this.fetcherConfigurations); } return this._fetcher; } /** * @description Sends a JSON RPC payload to the provider. * @param {JsonRpcPayload | JsonRpcPayload[]} payload - The payload to send * @returns {Promise<JsonRpcCallResult>} - The result of the call */ public async _send(payload: JsonRpcPayload | JsonRpcPayload[]): Promise<JsonRpcCallResult> { // Create an AbortController instance const controller = new AbortController(); const { signal } = controller; // Start a timer that will abort the fetch after the timeout period const timeoutId = setTimeout(() => controller.abort(), this.timeout); const params = { method: 'POST', headers: { 'Content-Type': 'application/json', 'User-Agent': 'OPNET/1.0', //'Accept-Encoding': 'gzip, deflate, br', Accept: 'application/json', 'Accept-Charset': 'utf-8', 'Accept-Language': 'en-US', Connection: 'Keep-Alive', }, body: JSON.stringify(payload), timeout: this.timeout, signal: signal, }; try { const resp: Response = await this.fetcher(this.url, params); if (!resp.ok) { throw new Error(`Failed to fetch: ${resp.statusText}`); } const fetchedData = (await resp.json()) as JsonRpcResult | JsonRpcError; if (!fetchedData) { throw new Error('No data fetched'); } return [fetchedData]; } catch (e) { const error = e as Error; if (error.name === 'AbortError') { throw new Error(`Request timed out after ${this.timeout}ms`); } throw e; } finally { clearTimeout(timeoutId); } } protected providerUrl(url: string): string { url = url.trim(); if (url.endsWith('/')) { return url.slice(0, -1); } if (url.includes('api/v1/json-rpc')) { return url; } else { return `${url}/api/v1/json-rpc`; } } }