import http from "node:http";
import { HttpActiveSocketsTracker } from "../../api/rest/activeSockets.js";
import { wrapError } from "../../util/wrapError.js";
import { RegistryMetricCreator } from "../utils/registryMetricCreator.js";
var RequestStatus;
(function (RequestStatus) {
    RequestStatus["success"] = "success";
    RequestStatus["error"] = "error";
})(RequestStatus || (RequestStatus = {}));
export async function getHttpMetricsServer(opts, { register, getOtherMetrics = async () => [], logger, }) {
    // New registry to metric the metrics. Using the same registry would deadlock the .metrics promise
    const httpServerRegister = new RegistryMetricCreator();
    const scrapeTimeMetric = httpServerRegister.histogram({
        name: "lodestar_metrics_scrape_seconds",
        help: "Lodestar metrics server async time to scrape metrics",
        labelNames: ["status"],
        buckets: [0.1, 1, 10],
    });
    const server = http.createServer(async function onRequest(req, res) {
        if (req.method === "GET" && req.url && req.url.includes("/metrics")) {
            const timer = scrapeTimeMetric.startTimer();
            const metricsRes = await Promise.all([wrapError(register.metrics()), getOtherMetrics()]);
            timer({ status: metricsRes[0].err ? RequestStatus.error : RequestStatus.success });
            // Ensure we only writeHead once
            if (metricsRes[0].err) {
                res.writeHead(500, { "content-type": "text/plain" }).end(metricsRes[0].err.stack);
            }
            else {
                // Get scrape time metrics
                const httpServerMetrics = await httpServerRegister.metrics();
                const metrics = [metricsRes[0].result, httpServerMetrics, ...metricsRes[1]];
                const metricsStr = metrics.join("\n\n");
                res.writeHead(200, { "content-type": register.contentType }).end(metricsStr);
            }
        }
        else {
            res.writeHead(404).end();
        }
    });
    const socketsMetrics = {
        activeSockets: httpServerRegister.gauge({
            name: "lodestar_metrics_server_active_sockets_count",
            help: "Metrics server current count of active sockets",
        }),
        socketsBytesRead: httpServerRegister.gauge({
            name: "lodestar_metrics_server_sockets_bytes_read_total",
            help: "Metrics server total count of bytes read on all sockets",
        }),
        socketsBytesWritten: httpServerRegister.gauge({
            name: "lodestar_metrics_server_sockets_bytes_written_total",
            help: "Metrics server total count of bytes written on all sockets",
        }),
    };
    const activeSockets = new HttpActiveSocketsTracker(server, socketsMetrics);
    await new Promise((resolve, reject) => {
        server.once("error", (err) => {
            logger.error("Error starting metrics HTTP server", opts, err);
            reject(err);
        });
        server.listen(opts.port, opts.address, () => {
            const { port, address: host, family } = server.address();
            const address = `http://${family === "IPv6" ? `[${host}]` : host}:${port}`;
            logger.info("Started metrics HTTP server", { address });
            resolve();
        });
    });
    return {
        async close() {
            // In NodeJS land calling close() only causes new connections to be rejected.
            // Existing connections can prevent .close() from resolving for potentially forever.
            // In Lodestar case when the BeaconNode wants to close we will attempt to gracefully
            // close all existing connections but forcefully terminate after timeout for a fast shutdown.
            // Inspired by https://github.com/gajus/http-terminator/
            await activeSockets.terminate();
            await new Promise((resolve, reject) => {
                server.close((err) => {
                    if (err)
                        reject(err);
                    else
                        resolve();
                });
            });
            logger.debug("Metrics HTTP server closed");
        },
    };
}
//# sourceMappingURL=http.js.map