"use strict";
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;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    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) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.processHttpSignedDataRequest = exports.processHttpRequest = exports.run = exports.startCoordinator = void 0;
const path = __importStar(require("path"));
const airnode_utilities_1 = require("@api3/airnode-utilities");
const promise_utils_1 = require("@api3/promise-utils");
const airnode_node_1 = require("@api3/airnode-node");
airnode_utilities_1.caching.init();
const configFile = path.resolve(`${__dirname}/../../config-data/config.json`);
const parsedConfig = (0, airnode_node_1.loadTrustedConfig)(configFile, process.env);
function startCoordinator() {
    return __awaiter(this, void 0, void 0, function* () {
        const coordinatorId = (0, airnode_utilities_1.randomHexString)(16);
        (0, airnode_utilities_1.setLogOptions)({
            format: parsedConfig.nodeSettings.logFormat,
            level: parsedConfig.nodeSettings.logLevel,
            meta: { 'Coordinator-ID': coordinatorId },
        });
        yield airnode_node_1.handlers.startCoordinator(parsedConfig, coordinatorId);
        const response = { ok: true, data: { message: 'Coordinator completed' } };
        airnode_utilities_1.caching.syncFsSync();
        return { statusCode: 200, body: JSON.stringify(response) };
    });
}
exports.startCoordinator = startCoordinator;
function run(payload) {
    (0, airnode_utilities_1.setLogOptions)(payload.logOptions);
    switch (payload.functionName) {
        case 'initializeProvider':
            return initializeProvider(payload);
        case 'callApi':
            return callApi(payload);
        case 'processTransactions':
            return processTransactions(payload);
    }
}
exports.run = run;
// TODO: Refactor handlers so they are common for all the cloud providers
// https://api3dao.atlassian.net/browse/AN-527
function initializeProvider(payload) {
    return __awaiter(this, void 0, void 0, function* () {
        const { state } = payload;
        const { chainId, name: providerName } = state.settings;
        (0, airnode_utilities_1.addMetadata)({ 'Chain-ID': chainId, Provider: providerName });
        const stateWithConfig = Object.assign(Object.assign({}, state), { config: parsedConfig });
        const goInitializedState = yield (0, promise_utils_1.go)(() => airnode_node_1.handlers.initializeProvider(stateWithConfig), {
            delay: { type: 'static', delayMs: airnode_utilities_1.DEFAULT_RETRY_DELAY_MS },
        });
        if (!goInitializedState.success) {
            const msg = `Failed to initialize provider: ${stateWithConfig.settings.name}`;
            airnode_utilities_1.logger.error(goInitializedState.error.toString());
            const errorLog = airnode_utilities_1.logger.pend('ERROR', msg, goInitializedState.error);
            const body = JSON.stringify({ ok: false, errorLog });
            return { statusCode: 500, body };
        }
        if (!goInitializedState.data) {
            const msg = `Failed to initialize provider: ${stateWithConfig.settings.name}`;
            const errorLog = airnode_utilities_1.logger.pend('ERROR', msg);
            const body = JSON.stringify({ ok: false, errorLog });
            return { statusCode: 500, body };
        }
        const body = JSON.stringify({ ok: true, data: airnode_node_1.providers.scrub(goInitializedState.data) });
        return { statusCode: 200, body };
    });
}
function callApi(payload) {
    return __awaiter(this, void 0, void 0, function* () {
        const { aggregatedApiCall } = payload;
        const { chainId, endpointId } = aggregatedApiCall;
        (0, airnode_utilities_1.addMetadata)({ 'Chain-ID': chainId, 'Endpoint-ID': endpointId });
        const [logs, apiCallResponse] = yield airnode_node_1.handlers.callApi(parsedConfig, aggregatedApiCall);
        airnode_utilities_1.logger.logPending(logs);
        const response = JSON.stringify({ ok: true, data: apiCallResponse });
        return { statusCode: 200, body: response };
    });
}
function processTransactions(payload) {
    return __awaiter(this, void 0, void 0, function* () {
        const { state } = payload;
        const { chainId, name: providerName } = state.settings;
        const stateWithConfig = Object.assign(Object.assign({}, state), { config: parsedConfig });
        (0, airnode_utilities_1.addMetadata)({ 'Chain-ID': chainId, Provider: providerName, 'Sponsor-Address': state.sponsorAddress });
        const goUpdatedState = yield (0, promise_utils_1.go)(() => airnode_node_1.handlers.processTransactions(stateWithConfig), {
            delay: { type: 'static', delayMs: airnode_utilities_1.DEFAULT_RETRY_DELAY_MS },
        });
        if (!goUpdatedState.success) {
            const msg = `Failed to process provider requests: ${stateWithConfig.settings.name}`;
            airnode_utilities_1.logger.error(goUpdatedState.error.toString());
            const errorLog = airnode_utilities_1.logger.pend('ERROR', msg, goUpdatedState.error);
            const body = JSON.stringify({ ok: false, errorLog });
            return { statusCode: 500, body };
        }
        const body = JSON.stringify({ ok: true, data: airnode_node_1.providers.scrub(goUpdatedState.data) });
        return { statusCode: 200, body };
    });
}
function processHttpRequest(event) {
    return __awaiter(this, void 0, void 0, function* () {
        (0, airnode_utilities_1.setLogOptions)({
            format: parsedConfig.nodeSettings.logFormat,
            level: parsedConfig.nodeSettings.logLevel,
        });
        // Check if the request origin header is allowed in the config
        const originVerification = (0, airnode_node_1.verifyRequestOrigin)(parsedConfig.nodeSettings.httpGateway.corsOrigins, event.headers.origin);
        // Respond to preflight requests
        if (event.httpMethod === 'OPTIONS') {
            if (!originVerification.success) {
                return { statusCode: 400, body: JSON.stringify(originVerification.error) };
            }
            return { statusCode: 204, headers: originVerification.headers, body: '' };
        }
        // The shape of the body is guaranteed by the openAPI spec
        const rawParameters = JSON.parse(event.body).parameters;
        // The "endpointId" path parameter existence is guaranteed by the openAPI spec
        const rawEndpointId = event.pathParameters.endpointId;
        const verificationResult = (0, airnode_node_1.verifyHttpRequest)(parsedConfig, rawParameters, rawEndpointId);
        if (!verificationResult.success) {
            const { statusCode, error } = verificationResult;
            return { statusCode, headers: originVerification.headers, body: JSON.stringify(error) };
        }
        const { parameters, endpointId } = verificationResult;
        (0, airnode_utilities_1.addMetadata)({ 'Endpoint-ID': endpointId });
        const [err, result] = yield airnode_node_1.handlers.processHttpRequest(parsedConfig, endpointId, parameters);
        if (err) {
            // Returning 500 because failure here means something went wrong internally with a valid request
            return { statusCode: 500, headers: originVerification.headers, body: JSON.stringify({ message: err.toString() }) };
        }
        // We do not want the user to see {"success": true, "data": <actual_data>}, but the actual data itself
        return { statusCode: 200, headers: originVerification.headers, body: JSON.stringify(result.data) };
    });
}
exports.processHttpRequest = processHttpRequest;
// TODO: Copy&paste for now, will refactor as part of
// https://api3dao.atlassian.net/browse/AN-527
function processHttpSignedDataRequest(event) {
    return __awaiter(this, void 0, void 0, function* () {
        (0, airnode_utilities_1.setLogOptions)({
            format: parsedConfig.nodeSettings.logFormat,
            level: parsedConfig.nodeSettings.logLevel,
        });
        // Check if the request origin header is allowed in the config
        const originVerification = (0, airnode_node_1.verifyRequestOrigin)(parsedConfig.nodeSettings.httpSignedDataGateway.corsOrigins, event.headers.origin);
        // Respond to preflight requests
        if (event.httpMethod === 'OPTIONS') {
            if (!originVerification.success) {
                return { statusCode: 400, body: JSON.stringify(originVerification.error) };
            }
            return { statusCode: 204, headers: originVerification.headers, body: '' };
        }
        // The shape of the body is guaranteed by the openAPI spec
        const rawEncodedParameters = JSON.parse(event.body).encodedParameters;
        // The "endpointId" path parameter existence is guaranteed by the openAPI spec
        const rawEndpointId = event.pathParameters.endpointId;
        const verificationResult = (0, airnode_node_1.verifyHttpSignedDataRequest)(parsedConfig, rawEncodedParameters, rawEndpointId);
        if (!verificationResult.success) {
            const { statusCode, error } = verificationResult;
            return { statusCode, headers: originVerification.headers, body: JSON.stringify(error) };
        }
        const { encodedParameters, endpointId } = verificationResult;
        (0, airnode_utilities_1.addMetadata)({ 'Endpoint-ID': endpointId });
        const [err, result] = yield airnode_node_1.handlers.processHttpSignedDataRequest(parsedConfig, endpointId, encodedParameters);
        if (err) {
            // Returning 500 because failure here means something went wrong internally with a valid request
            return { statusCode: 500, headers: originVerification.headers, body: JSON.stringify({ message: err.toString() }) };
        }
        // We do not want the user to see {"success": true, "data": <actual_data>}, but the actual data itself
        return { statusCode: 200, headers: originVerification.headers, body: JSON.stringify(result.data) };
    });
}
exports.processHttpSignedDataRequest = processHttpSignedDataRequest;
//# sourceMappingURL=index.js.map