"use strict";
/*
 * @adonisjs/profiler
 *
 * (c) Harminder Virk <virk@adonisjs.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.Profiler = void 0;
/// <reference path="../../adonis-typings/profiler.ts" />
const jest_worker_1 = require("jest-worker");
const helpers_1 = require("@poppinss/utils/build/helpers");
const Row_1 = require("../Row");
const Action_1 = require("../Action");
const AbstractProfiler_1 = require("./AbstractProfiler");
const DummyProfiler_1 = require("../DummyProfiler");
const InvalidProcessorException_1 = require("../Exceptions/InvalidProcessorException");
/**
 * Profiler exposes the public interface to create new profiling
 * rows and actions. In case of blacklisted actions, dummy
 * implementations are returned, resulting in noop.
 */
class Profiler extends AbstractProfiler_1.AbstractProfiler {
    constructor(appRoot, logger, config) {
        super();
        this.appRoot = appRoot;
        this.logger = logger;
        this.config = Object.assign({
            enabled: true,
            whitelist: [],
            blacklist: [],
        }, config);
    }
    /**
     * Returns the action to be used for timing functions
     */
    getAction(action, data) {
        return this.isEnabled(action)
            ? new Action_1.ProfilerAction(action, this.processor, undefined, data)
            : DummyProfiler_1.dummyAction;
    }
    /**
     * Returns a boolean telling if profiler is enabled for
     * a given `action` or `label` or not?
     */
    isEnabled(labelOrAction) {
        if (!this.config.enabled || !this.processor) {
            return false;
        }
        /**
         * If white list is empty, then check for blacklist
         */
        if (this.config.whitelist.length === 0) {
            return this.config.blacklist.indexOf(labelOrAction) === -1;
        }
        /**
         * Otherwise check for whitelist only. We can check for `whitelist` and
         * `blacklist` both here, but not 100% sure.
         */
        return this.config.whitelist.indexOf(labelOrAction) > -1;
    }
    /**
     * Creates a new profiler row for a given action. If action is not enabled
     * then a copy of [[this.dummyRow]] is returned, which has the same
     * public API with all actions to a noop.
     */
    create(label, data) {
        if (this.isEnabled(label)) {
            return new Row_1.ProfilerRow(label, this, data);
        }
        return DummyProfiler_1.dummyRow;
    }
    /**
     * Close the worker and cleanup memory
     */
    cleanup() {
        if (this.worker) {
            this.worker.end();
        }
        this.processor = undefined;
        this.worker = undefined;
    }
    /**
     * Define subscriber for the profiler. Only one subscriber can be defined
     * at max. Redifying the subscriber will override the existing subscriber
     */
    process(fn) {
        /**
         * The processor is an inline function
         */
        if (typeof fn === 'function') {
            this.processor = async (log) => {
                try {
                    await fn(log);
                }
                catch (error) {
                    this.logger.fatal(error, 'The profiler processor function raised an exception');
                }
            };
            return;
        }
        this.worker = new jest_worker_1.Worker((0, helpers_1.resolveFrom)(this.appRoot, fn));
        this.worker.getStdout().pipe(process.stdout);
        this.worker.getStderr().pipe(process.stderr);
        /**
         * Ensure worker has "process" method on it
         */
        if (typeof this.worker['process'] !== 'function') {
            throw InvalidProcessorException_1.InvalidProcessorException.missingWorkerMethod();
        }
        /**
         * The processor is a spawned worker (recommended)
         */
        this.processor = async (log) => {
            try {
                await this.worker['process'](log);
            }
            catch (error) {
                this.logger.fatal(error, `The profiler processor worker "${fn}" raised an exception`);
            }
        };
    }
}
exports.Profiler = Profiler;
