'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@opencensus/core");
const shimmer = require("shimmer");
const semver = require("semver");
class RedisPlugin extends core_1.BasePlugin {
    constructor(moduleName) {
        super(moduleName);
    }
    applyPatch() {
        this.logger.debug('Patched redis');
        if (semver.lt(this.version, '2.4.0')) {
            this.logger.info('disabling redis plugin because version isnt supported');
            return this.moduleExports;
        }
        if (this.moduleExports.RedisClient) {
            this.logger.debug('patching redis.RedisClient.prototype.create_stream');
            shimmer.wrap(this.moduleExports.RedisClient.prototype, 'create_stream', this.getPatchCreateStream());
            this.logger.debug('patching redis.RedisClient.prototype.internal_send');
            shimmer.wrap(this.moduleExports.RedisClient.prototype, 'internal_send_command', this.getPatchSendCommand());
            this.logger.debug('patching redis.RedisClient.prototype.createClient');
            shimmer.wrap(this.moduleExports, 'createClient', this.getPatchCreateClient());
        }
        return this.moduleExports;
    }
    applyUnpatch() {
        if (semver.lt(this.version, '2.4.0'))
            return;
        shimmer.unwrap(this.moduleExports.RedisClient.prototype, 'internal_send_command');
        shimmer.unwrap(this.moduleExports, 'createClient');
        shimmer.unwrap(this.moduleExports.RedisClient.prototype, 'create_stream');
    }
    getPatchCreateStream() {
        const plugin = this;
        return function createStreamWrap(original) {
            return function create_stream_trace() {
                if (!this.stream) {
                    Object.defineProperty(this, 'stream', {
                        get: function () { return this._patched_redis_stream; },
                        set: function (val) {
                            plugin.tracer.wrapEmitter(val);
                            this._patched_redis_stream = val;
                        }
                    });
                }
                return original.apply(this, arguments);
            };
        };
    }
    getPatchCreateClient() {
        const plugin = this;
        return function createClientWrap(original) {
            return function createClientTrace() {
                const client = original.apply(this, arguments);
                plugin.tracer.wrapEmitter(client);
                return client;
            };
        };
    }
    getPatchSendCommand() {
        const plugin = this;
        const addArguments = typeof this.options === 'object'
            && this.options.detailedCommands === true;
        return function internalSendCommandWrap(original) {
            return function internal_send_command_trace(cmd, args, cb) {
                if (!plugin.tracer.currentRootSpan) {
                    return original.apply(this, arguments);
                }
                if (arguments.length === 1 && typeof cmd === 'object') {
                    const span = plugin.tracer.startChildSpan(`redis-${cmd.command}`, core_1.SpanKind.CLIENT);
                    if (span === null)
                        return original.apply(this, arguments);
                    span.addAttribute('command', cmd.command);
                    if (addArguments) {
                        span.addAttribute('arguments', JSON.stringify(cmd.args || []));
                    }
                    cmd.callback = plugin.patchEnd(span, cmd.callback);
                    return original.apply(this, arguments);
                }
                if (typeof cmd === 'string' && Array.isArray(args) && typeof cb === 'function') {
                    const span = plugin.tracer.startChildSpan(`redis-${cmd}`, core_1.SpanKind.CLIENT);
                    if (span === null)
                        return original.apply(this, arguments);
                    span.addAttribute('command', cmd);
                    if (addArguments) {
                        span.addAttribute('arguments', JSON.stringify(args));
                    }
                    cb = plugin.patchEnd(span, cb);
                    return original.apply(this, arguments);
                }
                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();
            }
            if (typeof resultHandler === 'function') {
                return resultHandler.apply(this, arguments);
            }
        };
        return this.tracer.wrap(patchedEnd);
    }
}
exports.RedisPlugin = RedisPlugin;
const plugin = new RedisPlugin('redis');
exports.plugin = plugin;
//# sourceMappingURL=data:application/json;base64,[encoded data, 5708 characters]