'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@opencensus/core");
const shimmer = require("shimmer");
const semver = require("semver");
class IORedisPlugin extends core_1.BasePlugin {
    constructor(moduleName) {
        super(moduleName);
    }
    applyPatch() {
        this.logger.debug('Patched redis');
        if (!semver.satisfies(this.version, '>=2.0.0 <5.0.0')) {
            this.logger.info('disabling ioredis plugin because version isnt supported');
            return this.moduleExports;
        }
        if (this.moduleExports) {
            this.logger.debug('patching ioredis.prototype.sendCommand');
            shimmer.wrap(this.moduleExports.prototype, 'sendCommand', this.getPatchSendCommand());
        }
        return this.moduleExports;
    }
    applyUnpatch() {
        if (!semver.satisfies(this.version, '>=2.0.0 <5.0.0'))
            return;
        shimmer.unwrap(this.moduleExports.prototype, 'sendCommand');
    }
    getPatchSendCommand() {
        const plugin = this;
        const addArguments = typeof this.options === 'object'
            && this.options.detailedCommands === true;
        return function internalSendCommandWrap(original) {
            return function internal_send_command_trace(command) {
                if (!plugin.tracer.currentRootSpan) {
                    return original.apply(this, arguments);
                }
                const span = plugin.tracer.startChildSpan(`redis-${command.name}`, core_1.SpanKind.CLIENT);
                if (span === null)
                    return original.apply(this, arguments);
                span.addAttribute('command', command.name);
                if (addArguments) {
                    span.addAttribute('arguments', JSON.stringify(command.args));
                }
                if (typeof command.reject === 'function') {
                    command.reject = plugin.tracer.wrap(command.reject);
                }
                if (typeof command.resolve === 'function') {
                    command.resolve = plugin.tracer.wrap(command.resolve);
                }
                if (typeof command.callback === 'function') {
                    command.callback = plugin.patchEnd(span, command.callback);
                }
                if (typeof command.promise === 'object') {
                    const patchedEnd = function (err) {
                        if (plugin.options.detailedCommands === true && err instanceof Error) {
                            span.addAttribute('error', err.message);
                        }
                        if (span.ended === false) {
                            span.end();
                        }
                    };
                    if (typeof command.promise.finally === 'function') {
                        command.promise.finally(patchedEnd);
                    }
                    else if (typeof command.promise.then === 'function') {
                        command.promise.then(patchedEnd).catch(patchedEnd);
                    }
                }
                return original.apply(this, arguments);
            };
        };
    }
    patchEnd(span, resultHandler) {
        const plugin = this;
        const patchedEnd = function (err) {
            if (plugin.options.detailedCommands === true && err instanceof Error) {
                span.addAttribute('error', err.message);
            }
            if (span.ended === false) {
                span.end();
            }
            return resultHandler.apply(this, arguments);
        };
        return this.tracer.wrap(patchedEnd);
    }
}
exports.IORedisPlugin = IORedisPlugin;
const plugin = new IORedisPlugin('ioredis');
exports.plugin = plugin;
//# sourceMappingURL=data:application/json;base64,[encoded data, 4252 characters]