"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const dgram = require("dgram");
const SyncWorkerCounters = {
    authentication_failed: {
        help: "Authentication failed",
    },
    connection_started: {
        help: "Connection started",
    },
    connection_terminated: {
        help: "Connection terminated",
    },
    session_started: {
        help: "Session started",
    },
    session_terminated: {
        help: "Session terminated",
    },
    session_failed: {
        help: "Session failed",
    },
    protocol_violated: {
        help: "Protocol violated",
    },
    protocol_bytes_sent: {
        help: "Total bytes sent",
    },
    protocol_bytes_received: {
        help: "Total bytes received",
    },
    changeset_integrated: {
        help: "Changesets integrated",
    },
    download_constructed: {
        help: "Downloads constructed",
    },
    permission_denied: {
        help: "Permission denied",
    },
    client_unsyncable: {
        help: "Client unsyncable",
    },
    merges_performed: {
        help: "Merges performed",
    },
    connection_term_end_of_input: {
        name: "ros_sync_conn_term_end_of_input",
        help: "End of input",
    },
    connection_term_connection_reset_error: {
        name: "ros_sync_conn_term_connection_reset_error",
        help: "Connection reset",
    },
    connection_term_broken_pipe_error: {
        name: "ros_sync_conn_term_broken_pipe_error",
        help: "Broken pipe",
    },
    connection_term_system_error: {
        name: "ros_sync_conn_term_system_error",
        help: "System error",
    },
    connection_term_network_error: {
        name: "ros_sync_conn_term_network_error",
        help: "Network error",
    },
    connection_term_ssl_error: {
        name: "ros_sync_conn_term_ssl_error",
        help: "TLS error",
    },
    connection_term_http_error: {
        name: "ros_sync_conn_term_http_error",
        help: "HTTP error",
    },
    connection_term_websocket_error: {
        name: "ros_sync_conn_term_websocket_error",
        help: "WebSocker error",
    },
    connection_term_sync_protocol_error: {
        name: "ros_sync_conn_term_sync_protocol_error",
        help: "Sync protocol error",
    },
    connection_term_error_of_unexpected_category: {
        name: "ros_sync_conn_term_error_of_unexpected_category",
        help: "Error of unexpected category",
    },
    connection_term_heartbeat_timeout: {
        name: "ros_sync_conn_term_heartbeat_timeout",
        help: "Heartbeat timeout",
    },
    connection_term_http_response_written: {
        name: "ros_sync_conn_term_http_response_written",
        help: "HTTP response written",
    },
};
const SyncWorkerGauges = {
    protocol_bytes_sent: {
        name: "ros_sync_protocol_bytes_sent_gauge",
        help: "Total bytes sent",
    },
    protocol_bytes_received: {
        name: "ros_sync_protocol_bytes_received_gauge",
        help: "Total bytes received",
    },
    connection_online: {
        help: "Connections online",
    },
    connection_total: {
        help: "Connections total",
    },
    session_online: {
        help: "Sessions online",
    },
    session_total: {
        help: "Sessions total",
    },
    realms_open: {
        help: "Realms open",
    },
    event_loop_saturation: {
        help: "Event loop saturation",
    },
    event_loop_inefficiency: {
        help: "Event loop inefficiency",
    },
};
const SyncWorkerHistograms = {
    download_constructed: {
        name: "ros_sync_download_constructed_ms",
        help: "Downloads constructed durations in ms",
    },
    download_constructed_size: {
        name: "ros_sync_download_constructed_bytes",
        help: "Downloads constructed sizes in bytes",
    },
    changeset_integrated: {
        name: "ros_sync_changeset_integrated_ms",
        help: "Changeset integrated durations in ms",
    },
    changeset_integrated_size: {
        name: "ros_sync_changeset_integrated_bytes",
        help: "Changeset integrated sizes in bytes",
    },
    changeset_integrated_merges: {
        help: "Changeset integrated merge counts",
    },
    ping_rtt: {
        name: "ros_sync_ping_rtt_ms",
        help: "Ping round-trip-time in ms",
    },
};
class StatsdExporter {
    constructor(config) {
        this.gauges = {};
        this.counters = {};
        this.histograms = {};
        const labelNames = [];
        for (const name in SyncWorkerCounters) {
            this.counters[name] = config.statsSink.counter(Object.assign({ name: `ros_sync_${name}`, labelNames }, SyncWorkerCounters[name]));
        }
        for (const name in SyncWorkerGauges) {
            this.gauges[name] = config.statsSink.gauge(Object.assign({ name: `ros_sync_${name}`, labelNames }, SyncWorkerGauges[name]));
        }
        for (const name in SyncWorkerHistograms) {
            this.histograms[name] = config.statsSink.histogram(Object.assign({ name: `ros_sync_${name}`, labelNames }, SyncWorkerHistograms[name]));
        }
    }
    startImporter(labels, logger) {
        return __awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => {
                const server = dgram.createSocket("udp4", (msg, rinfo) => {
                    this.handleMessage(msg, rinfo, labels, logger);
                });
                const errCallback = (err) => {
                    this.server.close();
                    return reject(err);
                };
                server.on("error", errCallback);
                server.bind(0, "127.0.0.1", () => resolve(server));
            });
        });
    }
    handleMessage(msg, rinfo, labels, logger) {
        let metrics;
        const packetData = msg.toString();
        if (packetData.indexOf("\n") > -1) {
            metrics = packetData.split("\n");
        }
        else {
            metrics = [packetData];
        }
        for (const midx in metrics) {
            if (metrics[midx].length === 0) {
                continue;
            }
            const bits = metrics[midx].toString().split(":");
            const key = bits.shift();
            const keyBits = key.split(".");
            const namespace = keyBits.shift();
            if (namespace !== "realm") {
                logger.warn(`unknown metric key: ${key}`);
                continue;
            }
            const host = keyBits.shift();
            if (!host) {
                logger.warn(`unknown metric key: ${key}`);
                continue;
            }
            const metricName = keyBits.join("_");
            if (bits.length === 0) {
                bits.push("1");
            }
            let i;
            for (i = 0; i < bits.length; i++) {
                const fields = bits[i].split("|");
                const metricType = fields[1].trim();
                if (metricType === "g") {
                    const gauge = this.gauges[metricName];
                    if (gauge) {
                        gauge.set(labels, Number(fields[0] || 0));
                    }
                    else {
                        logger.warn(`unknown gauge: ${key} - ${fields}`);
                    }
                }
                else if (metricType === "c") {
                    const counter = this.counters[metricName];
                    if (counter) {
                        counter.inc(labels, Number(fields[0] || 0));
                    }
                    else {
                        logger.warn(`unknown counter: ${key} - ${fields}`);
                    }
                }
                else if (metricType === "ms") {
                    const histogram = this.histograms[metricName];
                    if (histogram) {
                        histogram.observe(labels, Number(fields[0]) || 0);
                    }
                    else {
                        logger.warn(`unknown timing: ${key} - ${fields}`);
                    }
                }
                else {
                    logger.warn(`unknown metric: ${metricType}: ${key}`);
                }
            }
        }
    }
}
exports.StatsdExporter = StatsdExporter;
//# sourceMappingURL=StatsdExporter.js.map