"use strict";
/**
 * `queries` submodule. Contains logic pertaining to anything that
 * requires an external node to be queried, including robust queries.
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getCyclesBatchFromNode = exports.getTxListFromNode = exports.getStandbyNodeListFromNode = exports.getArchiverListFromNode = exports.getValidatorListFromNode = exports.getCycleDataFromNode = exports.robustQueryForRecentCycleMarkers = exports.robustQueryForTxListHash = exports.robustQueryForStandbyNodeListHash = exports.robustQueryForArchiverListHash = exports.robustQueryForValidatorListHash = exports.robustQueryForCycleRecordHash = exports.initLogger = exports.p2pLogger = void 0;
const neverthrow_1 = require("neverthrow");
const Utils_1 = require("../Utils");
const http = __importStar(require("../../http"));
const Context_1 = require("../Context");
const MAX_RETRIES = 3;
let mainLogger;
function initLogger() {
    mainLogger = Context_1.logger.getLogger('main');
    exports.p2pLogger = Context_1.logger.getLogger('p2p');
}
exports.initLogger = initLogger;
/**
 * Executes a robust query to a specified endpoint across multiple nodes, providing more fault tolerance.
 *
 * @param {ActiveNode[]} nodes - An array of active nodes to query.
 * @param {string} endpointName - The name of the endpoint to call on the active nodes.
 *
 * The function runs a robust query, logs the query, and ensures the result of the query is robust.
 * It makes an HTTP GET request to the specified endpoint for each node, and if the call fails,
 * an error message is returned.
 *
 * @returns {RobustQueryResultAsync<T>} - A ResultAsync object. On success, it contains a result object with
 * the winning nodes and the returned value. On failure, it contains an Error object. The function is asynchronous
 * and can be awaited.
 */
function makeRobustQueryCall(nodes, endpointName) {
    // query function that makes the endpoint call as specified
    const queryFn = (node) => {
        const ip = node.ip;
        const port = node.port;
        // queries the cyclemarker endpoint defined in ../Join.ts
        return neverthrow_1.ResultAsync.fromPromise(http.get(`${ip}:${port}/${endpointName}`), (err) => new Error(`couldn't query ${endpointName}: ${err}`));
    };
    // run the robust query, wrapped in an async Result return the unwrapped result (with `map`) if successful
    const logPrefix = `syncv2-robust-query-${endpointName}`;
    return neverthrow_1.ResultAsync.fromPromise((0, Utils_1.attempt)(async () => await (0, Utils_1.robustQuery)(nodes, queryFn), {
        maxRetries: MAX_RETRIES,
        logPrefix,
        logger: mainLogger,
    }), (err) => new Error(`robust query failed for ${endpointName}: ${err}`)).andThen((robustResult) => {
        // ensuring the result was robust as well.
        if (!robustResult.isRobustResult) {
            return (0, neverthrow_1.errAsync)(new Error(`result of ${endpointName} wasn't robust`));
        }
        return robustResult.topResult.map((value) => ({
            winningNodes: robustResult.winningNodes,
            value,
        }));
    });
}
/**
 * Performs a simple fetch operation from a given node to a specified endpoint. The operation is retried up to
 * MAX_RETRIES times in case of failure.
 *
 * @param {ActiveNode} node - An active node to fetch data from.
 * @param {string} endpointName - The name of the endpoint to fetch data from.
 *
 * The function attempts to make an HTTP GET request to the specified endpoint. If the call fails,
 * it retries the operation and returns an error message.
 *
 * @returns {ResultAsync<T, Error>} - A ResultAsync object. On success, it will contain the data fetched, and
 * on error, it will contain an Error object. The function is asynchronous and can be awaited.
 */
function attemptSimpleFetch(node, endpointName, params = {}, timeout = 1000) {
    let url = `${node.ip}:${node.port}/${endpointName}`;
    if (params) {
        const encodedParams = new URLSearchParams(params).toString();
        url += `?${encodedParams}`;
    }
    return neverthrow_1.ResultAsync.fromPromise((0, Utils_1.attempt)(async () => await http.get(url, false, timeout), {
        maxRetries: MAX_RETRIES,
        logPrefix: `syncv2-simple-fetch-${endpointName}`,
        logger: mainLogger,
    }), (err) => new Error(`simple fetch failed for ${endpointName}: ${err}`));
}
/** Executes a robust query to retrieve the cycle marker from the network. */
function robustQueryForCycleRecordHash(nodes) {
    return makeRobustQueryCall(nodes, 'current-cycle-hash');
}
exports.robustQueryForCycleRecordHash = robustQueryForCycleRecordHash;
/** Executes a robust query to retrieve the validator list hash and next cycle timestamp from the network. */
function robustQueryForValidatorListHash(nodes) {
    return makeRobustQueryCall(nodes, 'validator-list-hash');
}
exports.robustQueryForValidatorListHash = robustQueryForValidatorListHash;
/** Executes a robust query to retrieve the archiver list hash from the network. */
function robustQueryForArchiverListHash(nodes) {
    return makeRobustQueryCall(nodes, 'archiver-list-hash');
}
exports.robustQueryForArchiverListHash = robustQueryForArchiverListHash;
/** Executes a robust query to retrieve the standby list hash from the network. */
function robustQueryForStandbyNodeListHash(nodes) {
    return makeRobustQueryCall(nodes, 'standby-list-hash');
}
exports.robustQueryForStandbyNodeListHash = robustQueryForStandbyNodeListHash;
/** Executes a robust query to retrieve the txList hash from the network. */
function robustQueryForTxListHash(nodes) {
    return makeRobustQueryCall(nodes, 'tx-list-hash');
}
exports.robustQueryForTxListHash = robustQueryForTxListHash;
/** Executes a robust query to retrieve recent cycle markers from the network. */
function robustQueryForRecentCycleMarkers(nodes) {
    return makeRobustQueryCall(nodes, 'recent-cycle-markers');
}
exports.robustQueryForRecentCycleMarkers = robustQueryForRecentCycleMarkers;
/** Retrives the cycle by marker from the node. */
function getCycleDataFromNode(node, expectedMarker) {
    info(`getCycleDataFromNode: expectedMarker: ${expectedMarker}`);
    return attemptSimpleFetch(node, 'cycle-by-marker', {
        marker: expectedMarker,
    });
}
exports.getCycleDataFromNode = getCycleDataFromNode;
/** Gets the full validator list from the specified node. */
function getValidatorListFromNode(node, expectedHash) {
    info(`getValidatorListFromNode: expectedHash: ${expectedHash}`);
    return attemptSimpleFetch(node, 'validator-list', {
        hash: expectedHash,
    }, 10000);
}
exports.getValidatorListFromNode = getValidatorListFromNode;
/** Gets the full archiver list from the specified archiver. */
function getArchiverListFromNode(node, expectedHash) {
    info(`getArchiverListFromNode: expectedHash: ${expectedHash}`);
    return attemptSimpleFetch(node, 'archiver-list', {
        hash: expectedHash,
    });
}
exports.getArchiverListFromNode = getArchiverListFromNode;
/** Gets the full standby list from the specified standby. */
function getStandbyNodeListFromNode(node, expectedHash) {
    info(`getStandbyNodeListFromNode: expectedHash: ${expectedHash}`);
    return attemptSimpleFetch(node, 'standby-list', {
        hash: expectedHash,
    }, 10000 //TODO need to make this scale when there could be millions of entries
    );
}
exports.getStandbyNodeListFromNode = getStandbyNodeListFromNode;
/** Gets the full tx list from the specified node */
function getTxListFromNode(node, expectedHash) {
    info(`getTxListFromNode: expectedHash: ${expectedHash}`);
    return attemptSimpleFetch(node, 'tx-list', {
        hash: expectedHash,
    }, 10000 //TODO need to make this scale when there could be millions of entries
    );
}
exports.getTxListFromNode = getTxListFromNode;
/** Retrieves multiple cycles in batch from a node. */
function getCyclesBatchFromNode(node, markers) {
    info(`getCyclesBatchFromNode: fetching ${markers.length} cycles`);
    return attemptSimpleFetch(node, 'cycles-batch', {
        markers: markers.join(','),
    }, 30000 // 30 seconds timeout for batch operations
    );
}
exports.getCyclesBatchFromNode = getCyclesBatchFromNode;
function info(...msg) {
    const entry = `SyncV2: ${msg.join(' ')}`;
    exports.p2pLogger.info(entry);
}
//# sourceMappingURL=queries.js.map