UNPKG

hardhat

Version:

Hardhat is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.

118 lines (95 loc) 3.27 kB
import type { Client as ClientT } from "undici"; import type WsT from "ws"; import debug from "debug"; import http, { Server } from "http"; import { AddressInfo } from "net"; import { EIP1193Provider, JsonRpcServer as IJsonRpcServer, } from "../../../types"; import { HttpProvider } from "../../core/providers/http"; import { JsonRpcHandler } from "./handler"; const log = debug("hardhat:core:hardhat-network:jsonrpc"); export interface JsonRpcServerConfig { hostname: string; port: number; provider: EIP1193Provider; } export class JsonRpcServer implements IJsonRpcServer { private _config: JsonRpcServerConfig; private _httpServer: Server; private _wsServer: WsT.Server; constructor(config: JsonRpcServerConfig) { const { Server: WSServer } = require("ws") as typeof WsT; this._config = config; const handler = new JsonRpcHandler(config.provider); this._httpServer = http.createServer(); this._wsServer = new WSServer({ server: this._httpServer, }); this._httpServer.on("request", handler.handleHttp); this._wsServer.on("connection", handler.handleWs); } public getProvider = (name = "json-rpc"): EIP1193Provider => { const { Client } = require("undici") as { Client: typeof ClientT }; const { address, port } = this._httpServer.address() as AddressInfo; const dispatcher = new Client(`http://${address}:${port}/`, { keepAliveTimeout: 10, keepAliveMaxTimeout: 10, }); return new HttpProvider( `http://${address}:${port}/`, name, {}, 20000, dispatcher ); }; public listen = (): Promise<{ address: string; port: number }> => { return new Promise((resolve) => { log(`Starting JSON-RPC server on port ${this._config.port}`); this._httpServer.listen(this._config.port, this._config.hostname, () => { // We get the address and port directly from the server in order to handle random port allocation with `0`. const address = this._httpServer.address() as AddressInfo; // TCP sockets return AddressInfo resolve(address); }); }); }; public waitUntilClosed = async () => { const httpServerClosed = new Promise((resolve) => { this._httpServer.once("close", resolve); }); const wsServerClosed = new Promise((resolve) => { this._wsServer.once("close", resolve); }); await Promise.all([httpServerClosed, wsServerClosed]); }; public close = async () => { await Promise.all([ new Promise<void>((resolve, reject) => { log("Closing JSON-RPC server"); this._httpServer.close((err) => { if (err !== null && err !== undefined) { log("Failed to close JSON-RPC server"); reject(err); return; } log("JSON-RPC server closed"); resolve(); }); }), new Promise<void>((resolve, reject) => { log("Closing websocket server"); this._wsServer.close((err) => { if (err !== null && err !== undefined) { log("Failed to close websocket server"); reject(err); return; } log("Websocket server closed"); resolve(); }); }), ]); }; }