hardhat
Version:
Hardhat is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.
95 lines (77 loc) • 2.88 kB
text/typescript
import type { JsonRpcServer } from "../../../../types/network.js";
import type { EthereumProvider } from "../../../../types/providers.js";
import type { Server } from "node:http";
import type { AddressInfo } from "node:net";
import http from "node:http";
import debug from "debug";
import { WebSocketServer } from "ws";
import { JsonRpcHandler } from "./handler.js";
const log = debug("hardhat:core:tasks:node:json-rpc:server");
export interface JsonRpcServerConfig {
hostname: string;
port?: number;
provider: EthereumProvider;
}
export class JsonRpcServerImplementation implements JsonRpcServer {
readonly #config: JsonRpcServerConfig;
readonly #httpServer: Server;
readonly #wsServer: WebSocketServer;
constructor(config: JsonRpcServerConfig) {
this.#config = config;
const handler = new JsonRpcHandler(config.provider);
this.#httpServer = http.createServer();
this.#wsServer = new WebSocketServer({
server: this.#httpServer,
});
this.#httpServer.on("request", handler.handleHttp);
this.#wsServer.on("connection", handler.handleWs);
}
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`.
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- TCP sockets return AddressInfo
const address = this.#httpServer.address() as AddressInfo;
resolve(address);
});
});
};
public afterClosed = async (): Promise<void> => {
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 (): Promise<void> => {
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();
});
}),
]);
};
}