// SPDX-License-Identifier: Apache-2.0
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var RapidFireCommand_1;
import { Listr } from 'listr2';
import { SoloError } from '../core/errors/solo-error.js';
import * as constants from '../core/constants.js';
import { BaseCommand } from './base.js';
import { Flags as flags } from './flags.js';
import { ListrLock } from '../core/lock/listr-lock.js';
import { injectable } from 'tsyringe-neo';
import { NETWORK_LOAD_GENERATOR_CHART_VERSION } from '../../version.js';
import * as helpers from '../core/helpers.js';
import { ContainerReference } from '../integration/kube/resources/container/container-reference.js';
import chalk from 'chalk';
import { PassThrough } from 'node:stream';
export var NLGTestClass;
(function (NLGTestClass) {
    NLGTestClass["HCSLoadTest"] = "HCSLoadTest";
    NLGTestClass["CryptoTransferLoadTest"] = "CryptoTransferLoadTest";
    NLGTestClass["NftTransferLoadTest"] = "NftTransferLoadTest";
    NLGTestClass["TokenTransferLoadTest"] = "TokenTransferLoadTest";
    NLGTestClass["SmartContractLoadTest"] = "SmartContractLoadTest";
    NLGTestClass["HeliSwapLoadTest"] = "HeliSwapLoadTest";
    NLGTestClass["LongevityLoadTest"] = "LongevityLoadTest";
})(NLGTestClass || (NLGTestClass = {}));
let RapidFireCommand = class RapidFireCommand extends BaseCommand {
    static { RapidFireCommand_1 = this; }
    constructor() {
        super();
    }
    static CRYPTO_TRANSFER_START_CONFIG_NAME = 'cryptoTransferStartConfig';
    static STOP_CONFIG_NAME = 'stopConfig';
    static START_FLAGS_LIST = {
        required: [flags.deployment, flags.nlgArguments, flags.performanceTest],
        optional: [
            flags.devMode,
            flags.force,
            flags.quiet,
            flags.valuesFile,
            flags.javaHeap,
            flags.packageName,
            flags.maxTps,
        ],
    };
    static STOP_FLAGS_LIST = {
        required: [flags.deployment, flags.performanceTest],
        optional: [flags.devMode, flags.force, flags.quiet, flags.packageName],
    };
    static DESTROY_FLAGS_LIST = {
        required: [flags.deployment],
        optional: [flags.devMode, flags.force, flags.quiet],
    };
    nglChartIsDeployed(context_) {
        return this.chartManager.isChartInstalled(context_.config.namespace, constants.NETWORK_LOAD_GENERATOR_RELEASE_NAME, context_.config.context);
    }
    deployNlgChart() {
        return {
            title: 'Deploy Network Load Generator chart',
            task: (context_, task) => {
                const subTasks = [
                    {
                        title: 'Install Network Load Generator chart',
                        task: async (context_, task) => {
                            let valuesArgument = helpers.prepareValuesFiles(constants.RAPID_FIRE_VALUES_FILE);
                            if (context_.config.valuesFile) {
                                valuesArgument += helpers.prepareValuesFiles(context_.config.valuesFile);
                            }
                            const haproxyPods = await this.k8Factory
                                .getK8(context_.config.context)
                                .pods()
                                .list(context_.config.namespace, ['solo.hedera.com/type=haproxy']);
                            const port = constants.GRPC_PORT;
                            const networkProperties = haproxyPods.map((pod) => {
                                const accountId = pod.labels['solo.hedera.com/account-id'] ?? 'unknown';
                                // Using multiple backslashes to ensure it is not stripped when the network.properties file is generated
                                // Final result should look like: x.x.x.x\:50211=0.0.y
                                return String.raw `${pod.podIp}\\\:${port}=${accountId}`;
                            });
                            for (const row of networkProperties) {
                                valuesArgument += ` --set loadGenerator.properties[${networkProperties.indexOf(row)}]="${row}"`;
                            }
                            await this.chartManager.install(context_.config.namespace, constants.NETWORK_LOAD_GENERATOR_RELEASE_NAME, constants.NETWORK_LOAD_GENERATOR_CHART, constants.NETWORK_LOAD_GENERATOR_CHART_URL, NETWORK_LOAD_GENERATOR_CHART_VERSION, valuesArgument, context_.config.context);
                        },
                    },
                    {
                        title: 'Check NLG pod is ready',
                        task: async ({ config }) => {
                            await this.k8Factory
                                .getK8(config.context)
                                .pods()
                                .waitForReadyStatus(config.namespace, constants.NETWORK_LOAD_GENERATOR_POD_LABELS, constants.NETWORK_LOAD_GENERATOR_POD_RUNNING_MAX_ATTEMPTS, constants.NETWORK_LOAD_GENERATOR_POD_RUNNING_DELAY);
                        },
                    },
                    {
                        title: 'Install libraries in NLG pod',
                        task: async ({ config }) => {
                            const nlgPods = await this.k8Factory
                                .getK8(config.context)
                                .pods()
                                .list(config.namespace, constants.NETWORK_LOAD_GENERATOR_POD_LABELS);
                            const k8Containers = this.k8Factory.getK8(config.context).containers();
                            for (const pod of nlgPods) {
                                const containerReference = ContainerReference.of(pod.podReference, constants.NETWORK_LOAD_GENERATOR_CONTAINER);
                                const container = k8Containers.readByRef(containerReference);
                                await container.execContainer('apt-get update -qq');
                                await container.execContainer('apt-get install -y libsodium23');
                                await container.execContainer('apt-get clean -qq');
                            }
                        },
                    },
                ];
                // set up the sub-tasks
                return task.newListr(subTasks, {
                    concurrent: false, // no need to run concurrently since if one node is up, the rest should be up by then
                    rendererOptions: {
                        collapseSubtasks: false,
                    },
                });
            },
            skip: this.nglChartIsDeployed.bind(this),
        };
    }
    startLoadTest(leaseReference) {
        return {
            title: 'Start performance load test',
            task: async (context_, task) => {
                const { performanceTest, packageName } = context_.config;
                const testClass = `${packageName}.${performanceTest}`;
                task.title = `Start performance load test: ${testClass}`;
                const nlgPods = await this.k8Factory
                    .getK8(context_.config.context)
                    .pods()
                    .list(context_.config.namespace, constants.NETWORK_LOAD_GENERATOR_POD_LABELS);
                const k8Containers = this.k8Factory.getK8(context_.config.context).containers();
                for (const pod of nlgPods) {
                    const containerReference = ContainerReference.of(pod.podReference, constants.NETWORK_LOAD_GENERATOR_CONTAINER);
                    const container = k8Containers.readByRef(containerReference);
                    const outputStream = new PassThrough();
                    const errorStream = new PassThrough();
                    for (const stream_ of [errorStream, outputStream]) {
                        stream_.on('data', (chunk) => {
                            const string_ = chunk.toString();
                            task.output = (task.output || '') + chalk.gray(string_);
                        });
                    }
                    try {
                        await leaseReference.lease?.release();
                        const tpsSetting = context_.config.maxTps ? `-Dbenchmark.maxtps=${context_.config.maxTps}` : '';
                        let commandString = `/usr/bin/env java -Xmx${context_.config.javaHeap}g ${tpsSetting} -cp /app/lib/*:/app/network-load-generator-${NETWORK_LOAD_GENERATOR_CHART_VERSION}.jar ${testClass} ${context_.config.parsedNlgArguments}`;
                        commandString = commandString.replaceAll('  ', ' ').trim();
                        await container.execContainer(commandString, outputStream, errorStream);
                    }
                    catch (error) {
                        throw new SoloError(`Error running ${testClass} load test: ${error.message}`, error);
                    }
                    if (task.output) {
                        const showOutput = '>   ' + task.output.replaceAll('\n', '\n    ');
                        this.logger.showUser(showOutput);
                    }
                }
            },
        };
    }
    async start(argv) {
        const leaseReference = {}; // This allows the lease to be passed by reference to the init task
        const tasks = new Listr([
            {
                title: 'Initialize',
                task: async (context_, task) => {
                    await this.localConfig.load();
                    await this.remoteConfig.loadAndValidate(argv);
                    leaseReference.lease = await this.leaseManager.create();
                    this.configManager.update(argv);
                    flags.disablePrompts(RapidFireCommand_1.START_FLAGS_LIST.optional);
                    const allFlags = [
                        ...RapidFireCommand_1.START_FLAGS_LIST.required,
                        ...RapidFireCommand_1.START_FLAGS_LIST.optional,
                    ];
                    await this.configManager.executePrompt(task, allFlags);
                    const config = this.configManager.getConfig(RapidFireCommand_1.CRYPTO_TRANSFER_START_CONFIG_NAME, allFlags, ['parsedNlgArguments']);
                    context_.config = config;
                    config.namespace = await this.getNamespace(task);
                    config.clusterRef = this.getClusterReference();
                    config.context = this.getClusterContext(config.clusterRef);
                    // Parse nlgArguments to remove any surrounding quotes
                    config.parsedNlgArguments = config.nlgArguments.replaceAll("'", '').replaceAll('"', '');
                    return ListrLock.newAcquireLockTask(leaseReference.lease, task);
                },
            },
            this.deployNlgChart(),
            this.startLoadTest(leaseReference),
        ], constants.LISTR_DEFAULT_OPTIONS.DEFAULT);
        try {
            await tasks.run();
        }
        catch (error) {
            throw new SoloError(`Error running rapid-fire: ${error.message}`, error);
        }
        finally {
            await leaseReference.lease?.release();
        }
        return true;
    }
    stopInitializeTask(argv, leaseReference) {
        return {
            title: 'Initialize',
            task: async (context_, task) => {
                await this.localConfig.load();
                await this.remoteConfig.loadAndValidate(argv);
                leaseReference.lease = await this.leaseManager.create();
                this.configManager.update(argv);
                flags.disablePrompts(RapidFireCommand_1.STOP_FLAGS_LIST.optional);
                const allFlags = [
                    ...RapidFireCommand_1.STOP_FLAGS_LIST.required,
                    ...RapidFireCommand_1.STOP_FLAGS_LIST.optional,
                ];
                await this.configManager.executePrompt(task, allFlags);
                const config = this.configManager.getConfig(RapidFireCommand_1.STOP_CONFIG_NAME, allFlags);
                config.namespace = await this.getNamespace(task);
                config.clusterRef = this.getClusterReference();
                config.context = this.getClusterContext(config.clusterRef);
                context_.config = config;
                return ListrLock.newAcquireLockTask(leaseReference.lease, task);
            },
        };
    }
    async allStopTasks(argv, stopTask) {
        const leaseReference = {}; // This allows the lease to be passed by reference to the init task
        const tasks = new Listr([this.stopInitializeTask(argv, leaseReference), stopTask], constants.LISTR_DEFAULT_OPTIONS.DEFAULT);
        try {
            await tasks.run();
        }
        catch (error) {
            throw new SoloError(`Error running rapid-fire stop: ${error.message}`, error);
        }
        finally {
            if (leaseReference.lease) {
                await leaseReference.lease.release();
            }
        }
        return true;
    }
    stopLoadTest() {
        return {
            title: 'Stop load test',
            task: async (context_, task) => {
                const { performanceTest, packageName } = context_.config;
                const testClass = `${packageName}.${performanceTest}`;
                task.title = `Stop load test: ${testClass}`;
                const nlgPods = await this.k8Factory
                    .getK8(context_.config.context)
                    .pods()
                    .list(context_.config.namespace, constants.NETWORK_LOAD_GENERATOR_POD_LABELS);
                const k8Containers = this.k8Factory.getK8(context_.config.context).containers();
                for (const pod of nlgPods) {
                    const containerReference = ContainerReference.of(pod.podReference, constants.NETWORK_LOAD_GENERATOR_CONTAINER);
                    const container = k8Containers.readByRef(containerReference);
                    try {
                        await container.execContainer(`pkill -f ${testClass}`);
                    }
                    catch (error) {
                        throw new SoloError(`Error stopping ${testClass} load test: ${error.message}`, error);
                    }
                }
            },
        };
    }
    async stop(argv) {
        const leaseReference = {}; // This allows the lease to be passed by reference to the init task
        const tasks = new Listr([this.stopInitializeTask(argv, leaseReference), this.stopLoadTest()], constants.LISTR_DEFAULT_OPTIONS.DEFAULT);
        try {
            await tasks.run();
        }
        catch (error) {
            throw new SoloError(`Error running rapid-fire stop: ${error.message}`, error);
        }
        finally {
            if (leaseReference.lease) {
                await leaseReference.lease.release();
            }
        }
        return true;
    }
    async destroy(argv) {
        return this.allStopTasks(argv, {
            title: 'Uninstall Network Load Generator chart',
            task: async (context_, task) => {
                await this.chartManager.uninstall(context_.config.namespace, constants.NETWORK_LOAD_GENERATOR_RELEASE_NAME, context_.config.context);
            },
        });
    }
    async close() { } // no-op
};
RapidFireCommand = RapidFireCommand_1 = __decorate([
    injectable(),
    __metadata("design:paramtypes", [])
], RapidFireCommand);
export { RapidFireCommand };
//# sourceMappingURL=rapid-fire.js.map