"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MetricsController = void 0;
const tslib_1 = require("tslib");
const _a = tslib_1.__importStar(require("@zyno-io/ts-server-foundation/type-metadata-runtime"));
const http_1 = require("../../http");
const helpers_1 = require("./helpers");
let _MetricsControllerMetadata_1;
let MetricsController = class MetricsController {
    async getMetrics(request) {
        // Authorization must use the transport peer, not optionally trusted
        // forwarding headers that an external caller can spoof.
        const ip = request.socket.remoteAddress ?? request.remoteAddress;
        if (!isPrivateLanIp(ip)) {
            return (0, http_1.rawResponse)('Forbidden', { statusCode: 403, contentType: 'text/plain' });
        }
        if (!helpers_1.OtelState.prometheusExporter) {
            return (0, http_1.rawResponse)('Metrics not available', { statusCode: 503, contentType: 'text/plain' });
        }
        const metrics = await collectPrometheusMetrics(helpers_1.OtelState.prometheusExporter);
        return (0, http_1.rawResponse)(metrics.body, { statusCode: metrics.statusCode, headers: metrics.headers });
    }
    static __tsfType = _MetricsControllerMetadata_1 = _a.decodeCompactMetadataV1("[1,{\"kind\":16,\"name\":\"MetricsController\",\"typeName\":\"MetricsController\",\"classType\":{\"$tsf\":0},\"properties\":[],\"methods\":[{\"name\":\"getMetrics\",\"parameters\":[{\"name\":\"request\",\"type\":{\"kind\":16,\"typeName\":\"HttpRequest\",\"classType\":{\"$tsfImport\":[1,\"../../http/index\",\"HttpRequest\"]}},\"optional\":false,\"default\":false}],\"returnType\":{\"kind\":22,\"type\":{\"kind\":16,\"typeName\":\"RawResponseResult\",\"classType\":{\"$tsfImport\":[1,\"../../http/index\",\"RawResponseResult\"]}}}}],\"hasConstructor\":false,\"constructorParameters\":[]}]", [() => MetricsController, require]);
};
exports.MetricsController = MetricsController;
tslib_1.__decorate([
    http_1.http.GET(),
    tslib_1.__metadata("design:type", Function),
    tslib_1.__metadata("design:paramtypes", [http_1.HttpRequest]),
    tslib_1.__metadata("design:returntype", Promise)
], MetricsController.prototype, "getMetrics", null);
exports.MetricsController = MetricsController = tslib_1.__decorate([
    http_1.http.controller('/metrics')
], MetricsController);
_MetricsControllerMetadata_1.classType = MetricsController;
MetricsController.__tsfType = _MetricsControllerMetadata_1;
function isPrivateLanIp(ip) {
    if (ip.startsWith('::ffff:'))
        ip = ip.slice(7);
    if (ip.startsWith('10.'))
        return true;
    if (/^172\.(1[6-9]|2[0-9]|3[0-1])\./.test(ip))
        return true;
    if (ip.startsWith('192.168.'))
        return true;
    if (ip.startsWith('127.'))
        return true;
    if (ip === '::1')
        return true;
    if (/^f[cd][0-9a-f]{2}:/i.test(ip))
        return true;
    if (/^fe[89ab][0-9a-f]:/i.test(ip))
        return true;
    return false;
}
function collectPrometheusMetrics(exporter) {
    return new Promise((resolve, reject) => {
        const chunks = [];
        const headers = {};
        const response = {
            statusCode: 200,
            setHeader(name, value) {
                headers[name.toLowerCase()] = value;
            },
            end(chunk) {
                if (chunk !== undefined)
                    chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
                resolve({
                    statusCode: this.statusCode,
                    headers,
                    body: Buffer.concat(chunks)
                });
            }
        };
        try {
            exporter.getMetricsRequestHandler({ url: '/metrics' }, response);
        }
        catch (error) {
            reject(error);
        }
    });
}
//# sourceMappingURL=metrics.controller.js.map